diff --git a/Cargo.lock b/Cargo.lock index d21ee64b7..de05e52d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,7 +730,6 @@ dependencies = [ name = "hash-semantics" version = "0.1.0" dependencies = [ - "bimap", "bitflags 2.0.0-rc.1", "dashmap", "derive_more", @@ -841,7 +840,6 @@ dependencies = [ name = "hash-tir" version = "0.1.0" dependencies = [ - "bimap", "derive_more", "hash-ast", "hash-source", @@ -879,7 +877,6 @@ dependencies = [ name = "hash-typecheck" version = "0.1.0" dependencies = [ - "bimap", "dashmap", "derive_more", "hash-ast", diff --git a/compiler/hash-ast-desugaring/src/desugaring.rs b/compiler/hash-ast-desugaring/src/desugaring.rs index 85ad67474..c8de67a91 100644 --- a/compiler/hash-ast-desugaring/src/desugaring.rs +++ b/compiler/hash-ast-desugaring/src/desugaring.rs @@ -47,7 +47,7 @@ impl<'s> AstDesugaring<'s> { let block = match node { Block::For(body) => body, block => panic_on_span!( - self.source_location(parent_span), + parent_span, self.source_map, "lowering: expected for-loop, got {}", block.as_str() @@ -75,7 +75,7 @@ impl<'s> AstDesugaring<'s> { Pat::Constructor(ConstructorPat { subject: make_binding_pat("Some"), spread: None, - fields: ast_nodes![AstNode::new(TuplePatEntry { name: None, pat }, pat_span)], + fields: ast_nodes![AstNode::new(TuplePatEntry { name: None, pat }, pat_span); pat_span], }), pat_span, ); @@ -96,14 +96,14 @@ impl<'s> AstDesugaring<'s> { Pat::Constructor(ConstructorPat { subject: make_binding_pat("None"), spread: None, - fields: ast_nodes![], + fields: ast_nodes![; pat_span], },), pat_span ), expr: AstNode::new(Expr::Break(BreakStatement {}), body_span), }, pat_span - ), + ); parent_span ]; // Here want to transform the for-loop into just a loop block @@ -121,7 +121,7 @@ impl<'s> AstDesugaring<'s> { args: ast_nodes![AstNode::new( ConstructorCallArg { name: None, value: iterator }, iter_span - )], + ); iter_span], }), body_span, ), @@ -168,7 +168,7 @@ impl<'s> AstDesugaring<'s> { let block = match node { Block::While(body) => body, block => panic_on_span!( - self.source_location(parent_span), + parent_span, self.source_map, "lowering: expected while-block, got {}", block.as_str() @@ -215,7 +215,8 @@ impl<'s> AstDesugaring<'s> { expr: AstNode::new(Expr::Break(BreakStatement {}), condition_span) }, condition_span - ), + ); + parent_span ], origin: MatchOrigin::While, }), @@ -334,7 +335,7 @@ impl<'s> AstDesugaring<'s> { let block = match node { Block::If(body) => body, block => panic_on_span!( - self.source_location(parent_span), + parent_span, self.source_map, "lowering: expected if-block, got {}", block.as_str() @@ -380,7 +381,7 @@ impl<'s> AstDesugaring<'s> { Expr::Block(BlockExpr { data: AstNode::new( Block::Body(BodyBlock { - statements: AstNodes::empty(), + statements: AstNodes::empty(parent_span), expr: None, }), parent_span, diff --git a/compiler/hash-ast-desugaring/src/lib.rs b/compiler/hash-ast-desugaring/src/lib.rs index f6ae6df4e..3ce31c3a9 100644 --- a/compiler/hash-ast-desugaring/src/lib.rs +++ b/compiler/hash-ast-desugaring/src/lib.rs @@ -75,7 +75,7 @@ impl CompilerStage for AstDesugaringPass { // De-sugar the target if it isn't already de-sugared if !source_stage_info.get(entry_point).is_desugared() && entry_point.is_interactive() { let source = node_map.get_interactive_block_mut(entry_point.into()); - let mut desugarer = AstDesugaring::new(source_map, entry_point); + let mut desugarer = AstDesugaring::new(source_map); desugarer.visit_body_block(source.node_ref_mut()).unwrap(); } @@ -101,7 +101,7 @@ impl CompilerStage for AstDesugaringPass { // investigating this in the future. for expr in module.node_mut().contents.iter_mut() { scope.spawn(move |_| { - let mut desugarer = AstDesugaring::new(source_map, source_id); + let mut desugarer = AstDesugaring::new(source_map); desugarer.visit_expr(expr.ast_ref_mut()).unwrap() }) } diff --git a/compiler/hash-ast-desugaring/src/visitor.rs b/compiler/hash-ast-desugaring/src/visitor.rs index d03ff8144..df8563135 100644 --- a/compiler/hash-ast-desugaring/src/visitor.rs +++ b/compiler/hash-ast-desugaring/src/visitor.rs @@ -5,27 +5,18 @@ use hash_ast::{ ast_visitor_mut_default_impl, visitor::{walk_mut, AstVisitorMut}, }; -use hash_source::{ - location::{SourceLocation, Span}, - SourceId, SourceMap, -}; +use hash_source::SourceMap; #[derive(Debug)] pub struct AstDesugaring<'s> { pub(crate) source_map: &'s SourceMap, - source_id: SourceId, } impl<'s> AstDesugaring<'s> { /// Create a new [AstDesugaring]. Contains the [SourceMap] and the /// current id of the source in reference. - pub fn new(source_map: &'s SourceMap, source_id: SourceId) -> Self { - Self { source_map, source_id } - } - - /// Create a [SourceLocation] from a [Span] - pub(crate) fn source_location(&self, span: Span) -> SourceLocation { - SourceLocation { span, id: self.source_id } + pub fn new(source_map: &'s SourceMap) -> Self { + Self { source_map } } } diff --git a/compiler/hash-ast-expand/src/lib.rs b/compiler/hash-ast-expand/src/lib.rs index a59ee5822..67d12b458 100644 --- a/compiler/hash-ast-expand/src/lib.rs +++ b/compiler/hash-ast-expand/src/lib.rs @@ -64,7 +64,7 @@ impl CompilerStage for AstExpansionPass { // De-sugar the target if it isn't already de-sugared if source_info.is_expanded() && entry_point.is_interactive() { - let mut expander = AstExpander::new(source_map, entry_point, settings, stdout.clone()); + let mut expander = AstExpander::new(source_map, settings, stdout.clone()); let source = node_map.get_interactive_block(entry_point.into()); expander.visit_body_block(source.node_ref()).unwrap(); @@ -79,7 +79,7 @@ impl CompilerStage for AstExpansionPass { continue; } - let mut expander = AstExpander::new(source_map, source_id, settings, stdout.clone()); + let mut expander = AstExpander::new(source_map, settings, stdout.clone()); expander.visit_module(module.node_ref()).unwrap(); } diff --git a/compiler/hash-ast-expand/src/visitor.rs b/compiler/hash-ast-expand/src/visitor.rs index 1ee8846ef..072cad29d 100644 --- a/compiler/hash-ast-expand/src/visitor.rs +++ b/compiler/hash-ast-expand/src/visitor.rs @@ -11,11 +11,7 @@ use hash_pipeline::{ interface::CompilerOutputStream, settings::{AstDumpMode, CompilerSettings}, }; -use hash_source::{ - identifier::IDENTS, - location::{SourceLocation, Span}, - SourceId, SourceMap, -}; +use hash_source::{identifier::IDENTS, SourceMap}; use hash_utils::{ stream_writeln, tree_writing::{TreeNode, TreeWriter, TreeWriterConfig}, @@ -25,8 +21,6 @@ use hash_utils::{ pub struct AstExpander<'s> { /// The map of the current workspace sources. pub(crate) source_map: &'s SourceMap, - /// The `id` of the module that is currently being checked - source_id: SourceId, /// The settings to the AST expansion pass. pub(crate) settings: &'s CompilerSettings, @@ -40,16 +34,10 @@ impl<'s> AstExpander<'s> { /// current id of the source in reference. pub fn new( source_map: &'s SourceMap, - source_id: SourceId, settings: &'s CompilerSettings, stdout: CompilerOutputStream, ) -> Self { - Self { source_map, settings, source_id, stdout } - } - - /// Create a [SourceLocation] from a [Span] - pub(crate) fn source_location(&self, span: Span) -> SourceLocation { - SourceLocation { span, id: self.source_id } + Self { source_map, settings, stdout } } } @@ -77,9 +65,12 @@ impl<'s> AstVisitorMutSelf for AstExpander<'s> { } else { node.subject.span() }; - let location = self.source_location(directive_span); - stream_writeln!(self.stdout, "AST dump for {}", self.source_map.fmt_location(location)); + stream_writeln!( + self.stdout, + "AST dump for {}", + self.source_map.fmt_location(directive_span) + ); match ast_settings.dump_mode { AstDumpMode::Pretty => { diff --git a/compiler/hash-ast/src/ast.rs b/compiler/hash-ast/src/ast.rs index 84ac2216f..0d349b426 100644 --- a/compiler/hash-ast/src/ast.rs +++ b/compiler/hash-ast/src/ast.rs @@ -10,7 +10,8 @@ use std::{ use hash_source::{ constant::{FloatTy, IntTy, InternedFloat, InternedInt, InternedStr, SIntTy}, identifier::Identifier, - location::Span, + location::{ByteRange, Span}, + SourceId, }; use hash_tree_def::define_tree; use hash_utils::{ @@ -30,11 +31,24 @@ define_index_type! { DISABLE_MAX_INDEX_CHECK = cfg!(not(debug_assertions)); } +impl AstNodeId { + /// Get the [Span] of this [AstNodeId]. + pub fn span(&self) -> Span { + SpanMap::span_of(*self) + } + + /// Get the [SourceId] of this [AstNodeId]. + pub fn source(&self) -> SourceId { + SpanMap::source_of(*self) + } +} + /// The [`SPAN_MAP`] is a global static that is used to store the span /// of each AST node. This is used to avoid storing the [Span] on the /// [`AstNode`] itself in order for other data structures to be able /// to query the [Span] of a node simply by using the [AstNodeId] of the /// node. + static SPAN_MAP: Lazy>> = Lazy::new(|| RwLock::new(IndexVec::new())); @@ -47,6 +61,11 @@ impl SpanMap { SPAN_MAP.read()[id] } + /// Get the [SourceId] of a node by [AstNodeId]. + pub fn source_of(id: AstNodeId) -> SourceId { + SpanMap::span_of(id).id + } + /// Get a mutable reference to the [`SPAN_MAP`]. This is only /// internal to the `hash-ast` crate since it creates entries /// in the span map when creating new AST nodes. @@ -104,6 +123,11 @@ impl AstNode { SpanMap::span_of(self.id) } + /// Get the [ByteRange] of this [AstNode]. + pub fn byte_range(&self) -> ByteRange { + self.span().span + } + /// Set the [Span] of this [AstNode]. pub fn set_span(&mut self, span: Span) { SpanMap::update_span(self.id, span) @@ -125,7 +149,7 @@ impl AstNode { } /// Create an [AstNodeRef] by providing a body and copying over the - /// [Span] and [AstNodeId] that belong to this [AstNode]. + /// [AstNodeId] that belong to this [AstNode]. pub fn with_body<'u, U>(&self, body: &'u U) -> AstNodeRef<'u, U> { AstNodeRef { body, id: self.id } } @@ -160,7 +184,7 @@ impl<'t, T> AstNodeRef<'t, T> { self.body } - /// Utility function to copy over the [Span] and [AstNodeId] from + /// Utility function to copy over the [AstNodeId] from /// another [AstNodeRef] with a provided body. pub fn with_body<'u, U>(&self, body: &'u U) -> AstNodeRef<'u, U> { AstNodeRef { body, id: self.id } @@ -273,27 +297,30 @@ pub trait OwnsAstNode { pub struct AstNodes { /// The nodes that the [AstNodes] holds. pub nodes: Vec>, - /// The span of the AST nodes if one is available. - pub span: Option, + + /// The id that is used to refer to the span of the [AstNodes]. + id: AstNodeId, } #[macro_export] macro_rules! ast_nodes { - ($($item:expr),*) => { - $crate::ast::AstNodes::new(vec![$($item,)*], None) + ($($item:expr),*; $span:expr) => { + $crate::ast::AstNodes::new(vec![$($item,)*], $span) }; - ($($item:expr,)*) => { - $crate::ast::AstNodes::new(vec![$($item,)*], None) + ($($item:expr,)*; $span:expr) => { + $crate::ast::AstNodes::new(vec![$($item,)*], $span) }; } impl AstNodes { - pub fn empty() -> Self { - Self { nodes: vec![], span: None } + /// Create a new [AstNodes]. + pub fn empty(span: Span) -> Self { + Self::new(vec![], span) } - pub fn new(nodes: Vec>, span: Option) -> Self { - Self { nodes, span } + pub fn new(nodes: Vec>, span: Span) -> Self { + let id = SpanMap::add_span(span); + Self { nodes, id } } /// Function to adjust the span location of [AstNodes] if it is initially @@ -301,11 +328,12 @@ impl AstNodes { /// be parsed before parsing the nodes. This token could be something like a /// '<' or '(' which starts a tuple, or type bound pub fn set_span(&mut self, span: Span) { - self.span = Some(span); + SpanMap::update_span(self.id, span); } - pub fn span(&self) -> Option { - self.span.or_else(|| Some(self.nodes.first()?.span().join(self.nodes.last()?.span()))) + /// Get the [AstNodeId] of this [AstNodes]. + pub fn span(&self) -> Span { + SpanMap::span_of(self.id) } pub fn ast_ref_iter(&self) -> impl Iterator> { @@ -2033,7 +2061,7 @@ mod size_asserts { use super::*; - static_assert_size!(Expr, 88); + static_assert_size!(Expr, 72); static_assert_size!(Pat, 72); - static_assert_size!(Ty, 64); + static_assert_size!(Ty, 56); } diff --git a/compiler/hash-codegen-llvm/src/translation/debug_info.rs b/compiler/hash-codegen-llvm/src/translation/debug_info.rs index 0f95e4aba..c64667e24 100644 --- a/compiler/hash-codegen-llvm/src/translation/debug_info.rs +++ b/compiler/hash-codegen-llvm/src/translation/debug_info.rs @@ -5,7 +5,7 @@ use hash_codegen::{ abi::FnAbi, traits::debug::{DebugInfoBuilderMethods, VariableKind}, }; -use hash_source::{identifier::Identifier, location::SourceLocation}; +use hash_source::{identifier::Identifier, location::Span}; use super::LLVMBuilder; @@ -24,7 +24,7 @@ impl<'b, 'm> DebugInfoBuilderMethods for LLVMBuilder<'_, 'b, 'm> { _ty: hash_ir::ty::IrTyId, _scope: Self::DebugInfoScope, _kind: VariableKind, - _span: SourceLocation, + _span: Span, ) -> Self::DebugInfoVariable { unimplemented!() } @@ -32,7 +32,7 @@ impl<'b, 'm> DebugInfoBuilderMethods for LLVMBuilder<'_, 'b, 'm> { fn create_debug_info_location( &self, _scope: Self::DebugInfoScope, - _span: SourceLocation, + _span: Span, ) -> Self::DebugInfoLocation { unimplemented!() } diff --git a/compiler/hash-codegen/src/traits/debug.rs b/compiler/hash-codegen/src/traits/debug.rs index ad22be90f..00dc30b17 100644 --- a/compiler/hash-codegen/src/traits/debug.rs +++ b/compiler/hash-codegen/src/traits/debug.rs @@ -6,7 +6,7 @@ use hash_abi::FnAbi; use hash_ir::ty::IrTyId; -use hash_source::{identifier::Identifier, location::SourceLocation}; +use hash_source::{identifier::Identifier, location::Span}; use super::BackendTypes; @@ -41,7 +41,7 @@ pub trait DebugInfoBuilderMethods: BackendTypes { ty: IrTyId, scope: Self::DebugInfoScope, kind: VariableKind, - span: SourceLocation, + span: Span, ) -> Self::DebugInfoVariable; /// Create a new [`BackendTypes::DebugInfoLocation`] which represents a @@ -50,7 +50,7 @@ pub trait DebugInfoBuilderMethods: BackendTypes { fn create_debug_info_location( &self, scope: Self::DebugInfoScope, - span: SourceLocation, + span: Span, ) -> Self::DebugInfoLocation; /// Finish the process of generating debug information for a particular diff --git a/compiler/hash-exhaustiveness/src/diagnostics.rs b/compiler/hash-exhaustiveness/src/diagnostics.rs index bb1f5bbda..2decca8b1 100644 --- a/compiler/hash-exhaustiveness/src/diagnostics.rs +++ b/compiler/hash-exhaustiveness/src/diagnostics.rs @@ -4,7 +4,7 @@ use hash_ast::ast::{MatchOrigin, RangeEnd}; use hash_error_codes::error_codes::HashErrorCode; use hash_reporting::{diagnostic::DiagnosticCellStore, reporter::Reporter}; -use hash_source::location::SourceLocation; +use hash_source::location::Span; use hash_tir::{environment::env::Env, lits::LitPat, pats::PatId, utils::common::CommonUtils}; use hash_utils::{ itertools::Itertools, @@ -47,7 +47,7 @@ pub enum ExhaustivenessError { /// When a match block is non-exhaustive NonExhaustiveMatch { /// The term of the subject expression. - location: SourceLocation, + location: Span, /// Generated patterns that are not covered by match arms uncovered_pats: Vec, @@ -136,7 +136,7 @@ pub enum ExhaustivenessWarning { pat: PatId, /// The location of the match subject that is being checked. - location: SourceLocation, + location: Span, }, // Exhaustiveness checking has found this pattern to diff --git a/compiler/hash-exhaustiveness/src/lib.rs b/compiler/hash-exhaustiveness/src/lib.rs index 6da423c48..ba5c821cc 100644 --- a/compiler/hash-exhaustiveness/src/lib.rs +++ b/compiler/hash-exhaustiveness/src/lib.rs @@ -67,7 +67,7 @@ use diagnostics::{ExhaustivenessDiagnostics, ExhaustivenessError, Exhaustiveness use hash_ast::ast::MatchOrigin; use hash_intrinsics::primitives::{AccessToPrimitives, DefinedPrimitives}; use hash_reporting::diagnostic::Diagnostics; -use hash_source::location::SourceLocation; +use hash_source::location::Span; use hash_storage::store::CloneStore; use hash_tir::{ environment::env::{AccessToEnv, Env}, @@ -101,7 +101,7 @@ impl PatCtx { pub struct ExhaustivenessChecker<'tc> { /// The span of the subject that is being checked for exhaustiveness /// or usefulness. - subject_span: SourceLocation, + subject_span: Span, /// A reference to the TC env in order to lookup various TIR items and have /// access to TC utilities. @@ -138,11 +138,7 @@ impl<'tc> AccessToPrimitives for ExhaustivenessChecker<'tc> { impl<'tc> ExhaustivenessChecker<'tc> { /// Create a new checker. - pub fn new( - subject_span: SourceLocation, - tcx: &'tc Env<'tc>, - primitives: &'tc DefinedPrimitives, - ) -> Self { + pub fn new(subject_span: Span, tcx: &'tc Env<'tc>, primitives: &'tc DefinedPrimitives) -> Self { Self { subject_span, tcx, diff --git a/compiler/hash-ir/src/ir.rs b/compiler/hash-ir/src/ir.rs index f4f829f5b..8c119cbb7 100644 --- a/compiler/hash-ir/src/ir.rs +++ b/compiler/hash-ir/src/ir.rs @@ -7,11 +7,12 @@ use std::{ iter::{self, once}, }; +use hash_ast::ast::AstNodeId; use hash_intrinsics::intrinsics; use hash_source::{ constant::{IntConstant, InternedFloat, InternedInt, InternedStr, CONSTANT_MAP}, identifier::Identifier, - location::{SourceLocation, Span}, + location::Span, SourceId, }; use hash_storage::{ @@ -836,11 +837,10 @@ pub struct Statement { /// The kind of [Statement] that it is. pub kind: StatementKind, - /// The [Span] of the statement, relative to the [Body] - /// `source-id`. This is mostly used for error reporting or - /// generating debug information at later stages of lowering + /// The location of the statement. This is mostly used for error reporting + /// or generating debug information at later stages of lowering /// beyond the IR. - pub span: Span, + pub origin: AstNodeId, } /// The kind of assert terminator that it is. @@ -913,11 +913,10 @@ pub struct Terminator { /// The kind of [Terminator] that it is. pub kind: TerminatorKind, - /// The [Span] of the statement, relative to the [Body] - /// `source-id`. This is mostly used for error reporting or - /// generating debug information at later stages of lowering - /// beyond the IR. - pub span: Span, + /// The source location of the terminator. This is mostly used for error + /// reporting or generating debug information at later stages of + /// lowering beyond the IR. + pub origin: AstNodeId, } pub type Successors<'a> = impl Iterator + 'a; @@ -1295,10 +1294,7 @@ pub struct Body { pub arg_count: usize, /// The location of the function - span: Span, - - /// The id of the source of where this body originates from. - pub source_id: SourceId, + origin: AstNodeId, /// Whether the IR Body that is generated should be printed /// when the generation process is finalised. @@ -1313,8 +1309,7 @@ impl Body { declarations: IndexVec, info: BodyInfo, arg_count: usize, - span: Span, - source_id: SourceId, + origin: AstNodeId, ) -> Self { Self { needed_constants: vec![], @@ -1322,8 +1317,7 @@ impl Body { info, declarations, arg_count, - span, - source_id, + origin, dump: false, } } @@ -1371,15 +1365,20 @@ impl Body { self.dump } - /// Get the [SourceLocation] for the [Body] - pub fn location(&self) -> SourceLocation { - SourceLocation { id: self.source_id, span: self.span } - } - /// Get the [BodyInfo] for the [Body] pub fn info(&self) -> &BodyInfo { &self.info } + + /// Get the [Span] of the [Body]. + pub(crate) fn span(&self) -> Span { + self.origin.span() + } + + /// Get the [SourceId] of the [Body]. + pub(crate) fn source(&self) -> SourceId { + self.origin.source() + } } /// This struct contains additional metadata about the body that was lowered, @@ -1524,3 +1523,14 @@ mod tests { assert_eq!(format!("{}", place), "(*(*(*_0)))"); } } + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use hash_utils::assert::static_assert_size; + + use super::*; + + static_assert_size!(Statement, 64); + static_assert_size!(Terminator, 104); + static_assert_size!(RValue, 40); +} diff --git a/compiler/hash-ir/src/write/graphviz.rs b/compiler/hash-ir/src/write/graphviz.rs index 0525339b6..4c79b9b08 100644 --- a/compiler/hash-ir/src/write/graphviz.rs +++ b/compiler/hash-ir/src/write/graphviz.rs @@ -282,7 +282,7 @@ pub fn dump_ir_bodies( for (id, body) in bodies.iter().enumerate() { // Skip the prelude if we're in quiet mode - if prelude_is_quiet && body.source_id.is_prelude() { + if prelude_is_quiet && body.source().is_prelude() { continue; } diff --git a/compiler/hash-ir/src/write/pretty.rs b/compiler/hash-ir/src/write/pretty.rs index a31264424..d8ddce82f 100644 --- a/compiler/hash-ir/src/write/pretty.rs +++ b/compiler/hash-ir/src/write/pretty.rs @@ -164,7 +164,7 @@ pub fn dump_ir_bodies( ) -> std::io::Result<()> { for (index, body) in bodies.iter().enumerate() { // Skip the prelude if we're in quiet mode - if prelude_is_quiet && body.source_id.is_prelude() { + if prelude_is_quiet && body.source().is_prelude() { continue; } @@ -184,7 +184,7 @@ pub fn dump_ir_bodies( "IR dump for {} `{}` defined at {}\n{}", body.info().source(), body.info().name(), - source_map.fmt_location(body.location()), + source_map.fmt_location(body.span()), IrBodyWriter::new(body) )?; } diff --git a/compiler/hash-lexer/src/error.rs b/compiler/hash-lexer/src/error.rs index d0756ec35..e19c2f327 100644 --- a/compiler/hash-lexer/src/error.rs +++ b/compiler/hash-lexer/src/error.rs @@ -7,7 +7,7 @@ use hash_reporting::{ report::{Report, ReportElement, ReportNote, ReportNoteKind}, reporter::{Reporter, Reports}, }; -use hash_source::{identifier::Identifier, location::SourceLocation}; +use hash_source::{identifier::Identifier, location::Span}; use hash_token::{delimiter::Delimiter, TokenKind}; use crate::Lexer; @@ -80,7 +80,7 @@ pub type LexerResult = Result; /// A [LexerError] represents a encountered error during tokenisation, which /// includes an optional message with the error, the [LexerErrorKind] which -/// classifies the error, and a [SourceLocation] that represents where the +/// classifies the error, and a [Span] that represents where the /// tokenisation error occurred. #[derive(Debug)] pub struct LexerError { @@ -92,7 +92,7 @@ pub struct LexerError { /// The location of the error, this includes the span and the id of the /// source. - pub(crate) location: SourceLocation, + pub(crate) location: Span, } /// A [LexerErrorKind] represents the kind of [LexerError] which gives diff --git a/compiler/hash-lexer/src/lib.rs b/compiler/hash-lexer/src/lib.rs index 5f301da6c..3a333fa1a 100644 --- a/compiler/hash-lexer/src/lib.rs +++ b/compiler/hash-lexer/src/lib.rs @@ -8,7 +8,7 @@ use hash_reporting::diagnostic::AccessToDiagnosticsMut; use hash_source::{ constant::{IntConstant, IntConstantValue, IntTy, SIntTy, UIntTy, CONSTANT_MAP}, identifier::{Identifier, IDENTS}, - location::{SourceLocation, Span}, + location::{ByteRange, Span}, SourceId, }; use hash_target::size::Size; @@ -92,7 +92,7 @@ impl<'a> Lexer<'a> { &mut self, message: Option, kind: LexerErrorKind, - span: Span, + span: ByteRange, ) -> TokenKind { self.diagnostics.has_fatal_error.set(true); self.emit_error(message, kind, span) @@ -105,13 +105,9 @@ impl<'a> Lexer<'a> { &mut self, message: Option, kind: LexerErrorKind, - span: Span, + span: ByteRange, ) -> TokenKind { - self.add_error(LexerError { - message, - kind, - location: SourceLocation { span, id: self.source_id }, - }); + self.add_error(LexerError { message, kind, location: Span { span, id: self.source_id } }); TokenKind::Err } @@ -123,9 +119,9 @@ impl<'a> Lexer<'a> { &self, message: Option, kind: LexerErrorKind, - span: Span, + span: ByteRange, ) -> Result { - Err(LexerError { message, kind, location: SourceLocation { span, id: self.source_id } }) + Err(LexerError { message, kind, location: Span { span, id: self.source_id } }) } /// Returns a reference to the stored token trees for the current job @@ -223,7 +219,10 @@ impl<'a> Lexer<'a> { // @@Hack: since we already compare if the first item is a slash, we'll just // return here the slash and advance it by one. - return Some(Token::new(TokenKind::Slash, Span::new(offset, offset + 1))); + return Some(Token::new( + TokenKind::Slash, + ByteRange::new(offset, offset + 1), + )); } }, _ => break, @@ -306,7 +305,7 @@ impl<'a> Lexer<'a> { return None; } - let location = Span::new(offset, self.len_consumed()); + let location = ByteRange::new(offset, self.len_consumed()); Some(Token::new(token_kind, location)) } @@ -352,7 +351,7 @@ impl<'a> Lexer<'a> { _ => self.emit_error( None, LexerErrorKind::Unclosed(delimiter), - Span::new(start, start + 1), + ByteRange::new(start, start + 1), ), } } @@ -492,7 +491,7 @@ impl<'a> Lexer<'a> { self.emit_error( None, LexerErrorKind::InvalidLitSuffix(NumericLitKind::Integer, suffix), - Span::new(self.offset.get(), self.offset.get()), + ByteRange::new(self.offset.get(), self.offset.get()), ); IntTy::Int(SIntTy::I32) @@ -504,7 +503,7 @@ impl<'a> Lexer<'a> { self.emit_error( None, LexerErrorKind::MalformedNumericalLit, - Span::new(start_pos, self.offset.get()), + ByteRange::new(start_pos, self.offset.get()), ); // It doesn't matter what we return here since we will terminate on the @@ -563,7 +562,7 @@ impl<'a> Lexer<'a> { return self.emit_error( None, LexerErrorKind::MissingDigits, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -578,7 +577,7 @@ impl<'a> Lexer<'a> { return self.emit_error( None, LexerErrorKind::UnsupportedFloatBaseLiteral(radix.into()), - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } else { return self.create_int_const(chars.as_str(), radix, suffix, start); @@ -625,7 +624,7 @@ impl<'a> Lexer<'a> { Err(err) => self.emit_error( Some(format!("{err}.")), LexerErrorKind::MalformedNumericalLit, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ), Ok(parsed) => { // Create interned float constant @@ -651,7 +650,7 @@ impl<'a> Lexer<'a> { Err(err) => self.emit_error( Some(format!("{err}.")), LexerErrorKind::MalformedNumericalLit, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ), Ok(value) => { match self.eat_exponent(start) { @@ -672,7 +671,7 @@ impl<'a> Lexer<'a> { self.emit_error( None, LexerErrorKind::InvalidLitSuffix(NumericLitKind::Float, suffix_ident), - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -713,7 +712,7 @@ impl<'a> Lexer<'a> { return self.error( None, LexerErrorKind::MissingExponentDigits, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -721,7 +720,7 @@ impl<'a> Lexer<'a> { Err(_) => self.error( Some("Invalid float exponent.".to_string()), LexerErrorKind::MalformedNumericalLit, - Span::new(start, self.offset.get() + 1), + ByteRange::new(start, self.offset.get() + 1), ), Ok(num) if negated => Ok(-num), Ok(num) => Ok(num), @@ -756,7 +755,7 @@ impl<'a> Lexer<'a> { return self.error( Some("Expected `{` after a `\\u` escape sequence".to_string()), LexerErrorKind::BadEscapeSequence, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -769,7 +768,7 @@ impl<'a> Lexer<'a> { return self.error( Some("expected `}` after a escape sequence".to_string()), LexerErrorKind::BadEscapeSequence, - Span::new(self.offset.get(), self.offset.get() + 1), + ByteRange::new(self.offset.get(), self.offset.get() + 1), ); } self.skip(); // Eat the '}' ending part of the scape sequence @@ -778,7 +777,7 @@ impl<'a> Lexer<'a> { return self.error( Some("Unicode escape literal must be at most 6 hex digits".to_string()), LexerErrorKind::BadEscapeSequence, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -791,7 +790,7 @@ impl<'a> Lexer<'a> { .to_string(), ), LexerErrorKind::BadEscapeSequence, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } @@ -807,12 +806,12 @@ impl<'a> Lexer<'a> { EOF_CHAR => self.error( Some("ASCII escape code too short".to_string()), LexerErrorKind::BadEscapeSequence, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ), c => self.error( Some("ASCII escape code must only contain hex digits".to_string()), LexerErrorKind::Unexpected(c), - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ), }) .collect(); @@ -836,7 +835,7 @@ impl<'a> Lexer<'a> { ch => self.error( Some(format!("unknown escape sequence `{ch}`")), LexerErrorKind::BadEscapeSequence, - Span::new(start, start + 1), + ByteRange::new(start, start + 1), ), } } @@ -878,14 +877,14 @@ impl<'a> Lexer<'a> { return self.emit_error( Some("unclosed character literal".to_string()), LexerErrorKind::Expected(TokenKind::SingleQuote), - Span::new(offset, offset + 1), + ByteRange::new(offset, offset + 1), ); } return self.emit_error( Some("character literal can only contain one codepoint".to_string()), LexerErrorKind::BadEscapeSequence, - Span::new(start, offset), + ByteRange::new(start, offset), ); } @@ -922,7 +921,7 @@ impl<'a> Lexer<'a> { self.emit_error( None, LexerErrorKind::InvalidCharacterLit(lit), - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ) } @@ -964,7 +963,7 @@ impl<'a> Lexer<'a> { return self.emit_fatal_error( None, LexerErrorKind::UnclosedStringLit, - Span::new(start, self.offset.get()), + ByteRange::new(start, self.offset.get()), ); } diff --git a/compiler/hash-lower/src/build/constant.rs b/compiler/hash-lower/src/build/constant.rs index 68a20a744..98d757ea8 100644 --- a/compiler/hash-lower/src/build/constant.rs +++ b/compiler/hash-lower/src/build/constant.rs @@ -4,12 +4,10 @@ use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}; +use hash_ast::ast::AstNodeId; use hash_ir::ir::{self, BinOp, Const, ConstKind}; use hash_reporting::macros::panic_on_span; -use hash_source::{ - constant::{FloatConstant, FloatConstantValue, IntConstant, CONSTANT_MAP}, - location::Span, -}; +use hash_source::constant::{FloatConstant, FloatConstantValue, IntConstant, CONSTANT_MAP}; use hash_tir::{environment::env::AccessToEnv, lits::Lit, terms::Term}; use super::BodyBuilder; @@ -27,11 +25,11 @@ impl<'tcx> BodyBuilder<'tcx> { } /// Lower a constant expression, i.e. a literal value. - pub(crate) fn lower_constant_expr(&mut self, term: &Term, span: Span) -> ConstKind { + pub(crate) fn lower_constant_expr(&mut self, term: &Term, origin: AstNodeId) -> ConstKind { match term { Term::Lit(lit) => self.as_constant(lit), _ => panic_on_span!( - span.into_location(self.source_id), + origin.span(), self.source_map(), "cannot lower non-literal expression into constant" ), diff --git a/compiler/hash-lower/src/build/into.rs b/compiler/hash-lower/src/build/into.rs index 7fd0e0e0f..7e72f6799 100644 --- a/compiler/hash-lower/src/build/into.rs +++ b/compiler/hash-lower/src/build/into.rs @@ -3,6 +3,7 @@ //! `strategies` can be found in [`crate::build::rvalue`] and //! [crate::build::temp]. +use hash_ast::ast::AstNodeId; use hash_ir::{ intrinsics::Intrinsic, ir::{ @@ -12,7 +13,7 @@ use hash_ir::{ ty::{AdtId, IrTy, IrTyId, Mutability, RefKind, VariantIdx, COMMON_IR_TYS}, }; use hash_reporting::macros::panic_on_span; -use hash_source::{constant::CONSTANT_MAP, identifier::Identifier, location::Span}; +use hash_source::{constant::CONSTANT_MAP, identifier::Identifier}; use hash_storage::store::{statics::StoreId, SequenceStoreKey}; use hash_tir::{ args::ArgsId, @@ -246,7 +247,7 @@ impl<'tcx> BodyBuilder<'tcx> { // **jump** to the proceeding block of the loop block let Some(LoopBlockInfo { loop_body, next_block }) = self.loop_block_info else { panic_on_span!( - span.into_location(self.source_id), + span.span(), self.env().source_map(), "`continue` or `break` outside of loop" ); @@ -277,7 +278,7 @@ impl<'tcx> BodyBuilder<'tcx> { // // ##Note: during CFG simplification, this edge will be removed and unified with // the `exit` block. - let return_block = self.control_flow_graph.make_return_block(); + let return_block = self.control_flow_graph.make_return_block(span); self.control_flow_graph.goto(block, return_block, span); self.control_flow_graph.start_new_block().unit() } @@ -337,14 +338,14 @@ impl<'tcx> BodyBuilder<'tcx> { &mut self, mut block: BasicBlock, assignment: AssignTerm, - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { // Lower the subject and the value of the assignment in RTL // and then assign the value into the subject let value = unpack!(block = self.as_rvalue(block, assignment.value)); let place = unpack!(block = self.as_place(block, assignment.subject, Mutability::Mutable)); - self.control_flow_graph.push_assign(block, place, value, span); + self.control_flow_graph.push_assign(block, place, value, origin); block.unit() } @@ -356,7 +357,7 @@ impl<'tcx> BodyBuilder<'tcx> { mut block: BasicBlock, subject: TermId, args: ArgsId, - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { // First we want to lower the subject of the function call let func = unpack!(block = self.as_operand(block, subject, Mutability::Immutable)); @@ -382,7 +383,7 @@ impl<'tcx> BodyBuilder<'tcx> { .map(|arg| unpack!(block = self.as_operand(block, arg.value, Mutability::Immutable))) .collect::>(); - self.build_fn_call(destination, block, func, args, span) + self.build_fn_call(destination, block, func, args, origin) } /// Build a function call from the provided subject and arguments. This @@ -395,7 +396,7 @@ impl<'tcx> BodyBuilder<'tcx> { block: BasicBlock, subject: Operand, args: Vec, - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { // This is the block that is used when resuming from the function.. let success = self.control_flow_graph.start_new_block(); @@ -403,7 +404,7 @@ impl<'tcx> BodyBuilder<'tcx> { // Terminate the current block with a `Call` terminator self.control_flow_graph.terminate( block, - span, + origin, TerminatorKind::Call { op: subject, args, destination, target: Some(success) }, ); @@ -424,7 +425,7 @@ impl<'tcx> BodyBuilder<'tcx> { block: BasicBlock, subject: &CtorTerm, adt_id: AdtId, - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { let CtorTerm { ctor, ctor_args, .. } = subject; @@ -442,7 +443,7 @@ impl<'tcx> BodyBuilder<'tcx> { if let AggregateKind::Enum(_, index) = aggregate_kind { self.control_flow_graph.push( block, - Statement { kind: StatementKind::Discriminate(destination, index), span }, + Statement { kind: StatementKind::Discriminate(destination, index), origin }, ); // We don't need to do anything else if it is just the discriminant. @@ -464,7 +465,7 @@ impl<'tcx> BodyBuilder<'tcx> { }) .collect::>(); - self.aggregate_into_dest(destination, block, aggregate_kind, &args, span) + self.aggregate_into_dest(destination, block, aggregate_kind, &args, origin) } /// Place any aggregate value into the specified destination. This does not @@ -477,7 +478,7 @@ impl<'tcx> BodyBuilder<'tcx> { mut block: BasicBlock, aggregate_kind: AggregateKind, args: &[(Identifier, TermId)], - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { // We don't need to perform this check for arrays since they don't need // to have a specific amount of arguments to the constructor. @@ -515,7 +516,7 @@ impl<'tcx> BodyBuilder<'tcx> { // Ensure we have the exact amount of arguments as the definition expects. if args.len() != field_count { panic_on_span!( - span.into_location(self.source_id), + origin.span(), self.source_map(), "default arguments on constructors are not currently supported", ); @@ -546,7 +547,7 @@ impl<'tcx> BodyBuilder<'tcx> { }; let aggregate = RValue::Aggregate(aggregate_kind, fields); - self.control_flow_graph.push_assign(block, destination, aggregate, span); + self.control_flow_graph.push_assign(block, destination, aggregate, origin); block.unit() } @@ -602,7 +603,7 @@ impl<'tcx> BodyBuilder<'tcx> { ty: IrTyId, aggregate_kind: AggregateKind, args: &[(Identifier, TermId)], - span: Span, + origin: AstNodeId, ) -> BlockAnd<()> { let ptr_width = self.settings.target().ptr_size(); let element_ty = ty.borrow().element_ty().unwrap(); @@ -620,7 +621,7 @@ impl<'tcx> BodyBuilder<'tcx> { // Make the call to `malloc`, and then assign the result to a // temporary. let ptr = self.temp_place(COMMON_IR_TYS.raw_ptr); - unpack!(block = self.build_fn_call(ptr, block, subject, vec![size_op], span)); + unpack!(block = self.build_fn_call(ptr, block, subject, vec![size_op], origin)); // we make a new temporary which is a pointer to the array and assign `ptr` // to it. @@ -630,10 +631,10 @@ impl<'tcx> BodyBuilder<'tcx> { RefKind::Normal, ); let array_ptr = self.temp_place(ty); - self.control_flow_graph.push_assign(block, array_ptr, Operand::Place(ptr).into(), span); + self.control_flow_graph.push_assign(block, array_ptr, Operand::Place(ptr).into(), origin); // 2). Write data to allocation. - self.aggregate_into_dest(array_ptr.deref(), block, aggregate_kind, args, span); + self.aggregate_into_dest(array_ptr.deref(), block, aggregate_kind, args, origin); // 3). // @@ -644,7 +645,7 @@ impl<'tcx> BodyBuilder<'tcx> { let value = self.create_ptr_with_metadata(sized_ptr_ty, Operand::Place(array_ptr), args.len()); - self.control_flow_graph.push_assign(block, sized_ptr, value, span); + self.control_flow_graph.push_assign(block, sized_ptr, value, origin); // Finally, transmute the SizedPointer into a `&[T]` and assign it to the // destination. @@ -662,7 +663,7 @@ impl<'tcx> BodyBuilder<'tcx> { Operand::Const(Const::Zero(COMMON_IR_TYS.unit).into()), Operand::Place(sized_ptr) ], - span + origin ) ); diff --git a/compiler/hash-lower/src/build/matches/candidate.rs b/compiler/hash-lower/src/build/matches/candidate.rs index 7d3e843b7..b05623427 100644 --- a/compiler/hash-lower/src/build/matches/candidate.rs +++ b/compiler/hash-lower/src/build/matches/candidate.rs @@ -13,12 +13,11 @@ use std::{borrow::Borrow, mem}; -use hash_ast::ast; +use hash_ast::ast::{self, AstNodeId}; use hash_ir::{ ir::{BasicBlock, Place, PlaceProjection}, ty::{AdtId, IrTy, Mutability}, }; -use hash_source::location::Span; use hash_storage::store::statics::StoreId; use hash_target::size::Size; use hash_tir::{ @@ -47,7 +46,7 @@ use crate::build::{place::PlaceBuilder, BodyBuilder}; pub(super) struct Candidate { /// The span of the `match` arm, for-error reporting /// functionality. - pub span: Span, + pub origin: AstNodeId, /// Whether or not the candidate arm hsa an associated guard, pub has_guard: bool, @@ -93,9 +92,14 @@ pub(super) type Candidates<'tcx> = (MatchCase, Candidate); impl Candidate { /// Create a new [Candidate]. - pub(super) fn new(span: Span, pat: PatId, place: &PlaceBuilder, has_guard: bool) -> Self { + pub(super) fn new( + origin: AstNodeId, + pat: PatId, + place: &PlaceBuilder, + has_guard: bool, + ) -> Self { Self { - span, + origin, has_guard, otherwise_block: None, pre_binding_block: None, @@ -146,7 +150,7 @@ pub(super) fn traverse_candidate( #[derive(Debug, Clone)] pub(super) struct Binding { /// The span of the binding. - pub span: Span, + pub origin: AstNodeId, /// The source of the binding, where the value is coming from. pub source: Place, @@ -275,7 +279,7 @@ impl<'tcx> BodyBuilder<'tcx> { } candidate.bindings.push(Binding { - span, + origin: span, mutability: if is_mutable { Mutability::Mutable } else { @@ -466,7 +470,7 @@ impl<'tcx> BodyBuilder<'tcx> { .copied() .map(|pat| { let mut sub_candidate = Candidate::new( - candidate.span, + candidate.origin, pat, subject, candidate.has_guard || pat.borrow().is_or(), diff --git a/compiler/hash-lower/src/build/matches/declarations.rs b/compiler/hash-lower/src/build/matches/declarations.rs index 31a161751..54a718a4a 100644 --- a/compiler/hash-lower/src/build/matches/declarations.rs +++ b/compiler/hash-lower/src/build/matches/declarations.rs @@ -1,12 +1,12 @@ //! This deals with lowering declarations,assigning them to a [Local], //! and later resolving references to the locals with the current [Builder]. +use hash_ast::ast::AstNodeId; use hash_ir::{ ir::{BasicBlock, Local, LocalDecl, Place}, ty::{IrTyId, Mutability}, }; use hash_reporting::macros::panic_on_span; -use hash_source::location::Span; use hash_storage::store::{statics::StoreId, TrivialSequenceStoreKey}; use hash_tir::{ arrays::ArrayPat, @@ -46,7 +46,7 @@ impl<'tcx> BodyBuilder<'tcx> { &mut self, mut block: BasicBlock, decl: &DeclTerm, - decl_span: Span, + decl_origin: AstNodeId, ) -> BlockAnd<()> { if let Some(value) = &decl.value { // First, we declare all of the bindings that are present @@ -57,7 +57,7 @@ impl<'tcx> BodyBuilder<'tcx> { unpack!(block = self.tir_term_into_pat(block, decl.bind_pat, *value)); } else { panic_on_span!( - decl_span.into_location(self.source_id), + decl_origin.span(), self.source_map(), "expected initialisation value, declaration are expected to have values (for now)." ); @@ -83,7 +83,7 @@ impl<'tcx> BodyBuilder<'tcx> { fn visit_primary_pattern_bindings( &mut self, pat: PatId, - f: &mut impl FnMut(&mut Self, Mutability, Symbol, Span, IrTyId), + f: &mut impl FnMut(&mut Self, Mutability, Symbol, AstNodeId, IrTyId), ) { let span = self.span_of_pat(pat); diff --git a/compiler/hash-lower/src/build/matches/mod.rs b/compiler/hash-lower/src/build/matches/mod.rs index c9d943e68..3300a41d9 100644 --- a/compiler/hash-lower/src/build/matches/mod.rs +++ b/compiler/hash-lower/src/build/matches/mod.rs @@ -10,12 +10,11 @@ mod test; use std::mem; -use hash_ast::ast; +use hash_ast::ast::{self, AstNodeId}; use hash_ir::{ ir::{self, BasicBlock, LogicalBinOp, Place, RValue, TerminatorKind}, ty::{Mutability, RefKind}, }; -use hash_source::location::Span; use hash_storage::store::statics::StoreId; use hash_tir::{ context::{Context, ScopeKind}, @@ -44,16 +43,16 @@ impl<'tcx> BodyBuilder<'tcx> { &mut self, destination: Place, mut block: BasicBlock, - span: Span, + origin: AstNodeId, subject: TermId, arms: MatchCasesId, - origin: ast::MatchOrigin, + match_origin: ast::MatchOrigin, ) -> BlockAnd<()> { // @@Hack: if the match-origin is an `if`-chain, then we don't bother // lowering the place since we always know that the branches are // always matching, and it's only guards that are being tested. Therefore, // we use the `subject_place` as the `return_place` in this instance. - let subject_place = if matches!(origin, ast::MatchOrigin::If) { + let subject_place = if matches!(match_origin, ast::MatchOrigin::If) { PlaceBuilder::from(ir::RETURN_PLACE) } else { unpack!(block = self.as_place_builder(block, subject, Mutability::Mutable)) @@ -70,9 +69,8 @@ impl<'tcx> BodyBuilder<'tcx> { // Using the decision tree, now build up the blocks for each arm, and then // join them at the end to the next block after the match, i.e. the `ending // block`. - self.lower_match_tree(block, subject_span, span, &mut candidates); - - self.lower_match_arms(destination, span, arm_candidates) + self.lower_match_tree(block, subject_span, origin, &mut candidates); + self.lower_match_arms(destination, subject_span, arm_candidates) } fn create_match_candidates( @@ -137,8 +135,8 @@ impl<'tcx> BodyBuilder<'tcx> { fn lower_match_tree( &mut self, block: BasicBlock, - subject_span: Span, - span: Span, + subject_origin: AstNodeId, + origin: AstNodeId, candidates: &mut [&mut Candidate], ) { // This is the basic block that is derived for using when the @@ -146,14 +144,14 @@ impl<'tcx> BodyBuilder<'tcx> { // in the `otherwise` situation. let mut otherwise = None; - self.match_candidates(span, block, &mut otherwise, candidates); + self.match_candidates(origin, block, &mut otherwise, candidates); // We need to terminate the otherwise block with an `unreachable` since // this branch should never be reached since the `match` is exhaustive. if let Some(otherwise_block) = otherwise { self.control_flow_graph.terminate( otherwise_block, - subject_span, + subject_origin, TerminatorKind::Unreachable, ); } @@ -178,7 +176,7 @@ impl<'tcx> BodyBuilder<'tcx> { fn lower_match_arms( &mut self, destination: Place, - subject_span: Span, + subject_origin: AstNodeId, arm_candidates: Vec>, ) -> BlockAnd<()> { // Lower all of the arms... @@ -188,7 +186,7 @@ impl<'tcx> BodyBuilder<'tcx> { // Each match-case creates its own scope, so we need to enter it here... Context::enter_resolved_scope_mut(self, ScopeKind::Stack(arm.stack_id), |this| { this.declare_bindings(arm.bind_pat); - let arm_block = this.bind_pat(subject_span, arm.bind_pat, candidate); + let arm_block = this.bind_pat(subject_origin, arm.bind_pat, candidate); lowered_arms_edges.push(this.term_into_dest(destination, arm_block, arm.value)); }) } @@ -202,8 +200,8 @@ impl<'tcx> BodyBuilder<'tcx> { let span = self.control_flow_graph.basic_blocks[arm_edge.0] .statements .last() - .map(|stmt| stmt.span) - .unwrap_or(subject_span); + .map(|stmt| stmt.origin) + .unwrap_or(subject_origin); let arm_block_edge = unpack!(arm_edge); @@ -221,7 +219,7 @@ impl<'tcx> BodyBuilder<'tcx> { /// This is the main **entry point** of the match-lowering algorithm. fn match_candidates( &mut self, - span: Span, + origin: AstNodeId, block: BasicBlock, otherwise: &mut Option, candidates: &mut [&mut Candidate], @@ -248,16 +246,16 @@ impl<'tcx> BodyBuilder<'tcx> { candidate.visit_leaves(|leaf| new_candidates.push(leaf)); } - self.match_simplified_candidates(span, block, otherwise, &mut new_candidates) + self.match_simplified_candidates(origin, block, otherwise, &mut new_candidates) } else { - self.match_simplified_candidates(span, block, otherwise, candidates) + self.match_simplified_candidates(origin, block, otherwise, candidates) } }); } fn match_simplified_candidates( &mut self, - span: Span, + origin: AstNodeId, start_block: BasicBlock, otherwise_block: &mut Option, candidates: &mut [&mut Candidate], @@ -291,7 +289,7 @@ impl<'tcx> BodyBuilder<'tcx> { // to create tests for any of the un-matched candidates. if unmatched_candidates.is_empty() { if let Some(otherwise) = *otherwise_block { - self.control_flow_graph.goto(block, otherwise, span); + self.control_flow_graph.goto(block, otherwise, origin); } else { *otherwise_block = Some(block); } @@ -300,7 +298,7 @@ impl<'tcx> BodyBuilder<'tcx> { } // Otherwise, we need to create tests for all of the unmatched candidates. - self.test_candidates_with_or(span, unmatched_candidates, block, otherwise_block) + self.test_candidates_with_or(origin, unmatched_candidates, block, otherwise_block) } /// Link matching candidates together, so that they are essentially chained. @@ -369,7 +367,7 @@ impl<'tcx> BodyBuilder<'tcx> { /// if not then we start building tests for candidates. fn test_candidates_with_or( &mut self, - span: Span, + origin: AstNodeId, candidates: &mut [&mut Candidate], block: BasicBlock, otherwise_block: &mut Option, @@ -382,7 +380,7 @@ impl<'tcx> BodyBuilder<'tcx> { // If this is the case, it means that we have no or-patterns // here... since we sorted them if !first.pairs[0].pat.borrow().is_or() { - self.test_candidates(span, candidates, block, otherwise_block); + self.test_candidates(origin, candidates, block, otherwise_block); return; } @@ -408,7 +406,7 @@ impl<'tcx> BodyBuilder<'tcx> { let remainder_start = otherwise.unwrap_or_else(|| self.control_flow_graph.start_new_block()); - self.match_candidates(span, remainder_start, otherwise_block, remaining); + self.match_candidates(origin, remainder_start, otherwise_block, remaining); } /// This is the point where we begin to "test" candidates since we have @@ -471,7 +469,7 @@ impl<'tcx> BodyBuilder<'tcx> { /// approach, we essentially generate an `if-else-if` chain. fn test_candidates( &mut self, - span: Span, + origin: AstNodeId, mut candidates: &mut [&mut Candidate], block: BasicBlock, otherwise: &mut Option, @@ -552,7 +550,7 @@ impl<'tcx> BodyBuilder<'tcx> { let candidate_start = this.control_flow_graph.start_new_block(); this.match_candidates( - span, + origin, candidate_start, remainder_start, &mut candidates, @@ -568,18 +566,18 @@ impl<'tcx> BodyBuilder<'tcx> { if !candidates.is_empty() { let remainder_start = remainder_start.unwrap_or_else(|| this.control_flow_graph.start_new_block()); - this.match_candidates(span, remainder_start, otherwise, candidates); + this.match_candidates(origin, remainder_start, otherwise, candidates); }; target_blocks }; - self.perform_test(span, block, &match_place, &test, make_target_blocks); + self.perform_test(origin, block, &match_place, &test, make_target_blocks); } /// This function is responsible for putting all of the declared bindings /// into scope. - fn bind_pat(&mut self, span: Span, pat: PatId, candidate: Candidate) -> BasicBlock { + fn bind_pat(&mut self, origin: AstNodeId, pat: PatId, candidate: Candidate) -> BasicBlock { let guard = match pat.value() { Pat::If(IfPat { condition, .. }) => Some(condition), _ => None, @@ -588,7 +586,7 @@ impl<'tcx> BodyBuilder<'tcx> { if candidate.sub_candidates.is_empty() { // We don't need generate another `BasicBlock` when we only have // this candidate. - self.bind_and_guard_matched_candidate(candidate, guard, &[], span) + self.bind_and_guard_matched_candidate(candidate, guard, &[], origin) } else { let target_block = self.control_flow_graph.start_new_block(); @@ -597,8 +595,8 @@ impl<'tcx> BodyBuilder<'tcx> { &mut Vec::new(), &mut |leaf, parent_bindings| { let binding_end = - self.bind_and_guard_matched_candidate(leaf, guard, parent_bindings, span); - self.control_flow_graph.goto(binding_end, target_block, span); + self.bind_and_guard_matched_candidate(leaf, guard, parent_bindings, origin); + self.control_flow_graph.goto(binding_end, target_block, origin); }, |inner, parent_bindings| { parent_bindings.push(inner.bindings); @@ -627,7 +625,7 @@ impl<'tcx> BodyBuilder<'tcx> { candidate: Candidate, guard: Option, parent_bindings: &[Vec], - span: Span, + origin: AstNodeId, ) -> BasicBlock { let block = candidate.pre_binding_block.unwrap(); @@ -644,7 +642,7 @@ impl<'tcx> BodyBuilder<'tcx> { let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| { let unreachable = self.control_flow_graph.start_new_block(); - self.control_flow_graph.terminate(unreachable, span, TerminatorKind::Unreachable); + self.control_flow_graph.terminate(unreachable, origin, TerminatorKind::Unreachable); unreachable }); @@ -685,7 +683,7 @@ impl<'tcx> BodyBuilder<'tcx> { block, value_place, binding.source.into(), - binding.span, + binding.origin, ); } } @@ -709,7 +707,7 @@ impl<'tcx> BodyBuilder<'tcx> { // an assign onto the binding source. let value_place = Place::from_local(self.lookup_local(binding.name).unwrap()); - self.control_flow_graph.push_assign(block, value_place, rvalue, binding.span); + self.control_flow_graph.push_assign(block, value_place, rvalue, binding.origin); } } } diff --git a/compiler/hash-lower/src/build/matches/optimise.rs b/compiler/hash-lower/src/build/matches/optimise.rs index 64ee72d8d..30632e4f0 100644 --- a/compiler/hash-lower/src/build/matches/optimise.rs +++ b/compiler/hash-lower/src/build/matches/optimise.rs @@ -4,11 +4,11 @@ use std::mem; +use hash_ast::ast::AstNodeId; use hash_ir::{ ir::PlaceProjection, ty::{IrTy, IrTyId}, }; -use hash_source::location::Span; use hash_storage::store::statics::StoreId; use hash_tir::pats::{PatId, Spread}; use hash_utils::smallvec::SmallVec; @@ -19,7 +19,7 @@ use crate::build::{place::PlaceBuilder, BodyBuilder}; impl<'tcx> BodyBuilder<'tcx> { /// Attempt to optimise the sub-candidates of a provided [Candidate]. This /// only performs a trivial merge, so we avoid generating exponential - pub(super) fn merge_sub_candidates(&mut self, candidate: &mut Candidate, span: Span) { + pub(super) fn merge_sub_candidates(&mut self, candidate: &mut Candidate, origin: AstNodeId) { if candidate.sub_candidates.is_empty() { return; } @@ -31,7 +31,7 @@ impl<'tcx> BodyBuilder<'tcx> { // // @@Todo: don't give up so easily here. for sub_candidate in &mut candidate.sub_candidates { - self.merge_sub_candidates(sub_candidate, span); + self.merge_sub_candidates(sub_candidate, origin); can_merge &= sub_candidate.sub_candidates.is_empty() && sub_candidate.bindings.is_empty(); @@ -44,7 +44,7 @@ impl<'tcx> BodyBuilder<'tcx> { // candidate `pre_binding` block. for sub_candidate in mem::take(&mut candidate.sub_candidates) { let or_block = sub_candidate.pre_binding_block.unwrap(); - self.control_flow_graph.goto(or_block, any_matches, span) + self.control_flow_graph.goto(or_block, any_matches, origin) } candidate.pre_binding_block = Some(any_matches); diff --git a/compiler/hash-lower/src/build/matches/test.rs b/compiler/hash-lower/src/build/matches/test.rs index 5ac159ff1..97f478c9a 100644 --- a/compiler/hash-lower/src/build/matches/test.rs +++ b/compiler/hash-lower/src/build/matches/test.rs @@ -6,7 +6,7 @@ use std::cmp::Ordering; use fixedbitset::FixedBitSet; -use hash_ast::ast; +use hash_ast::ast::{self, AstNodeId}; use hash_ir::{ ir::{ BasicBlock, BinOp, Const, Operand, PlaceProjection, RValue, SwitchTargets, TerminatorKind, @@ -14,10 +14,7 @@ use hash_ir::{ ty::{AdtId, IrTy, IrTyId, ToIrTy, VariantIdx, COMMON_IR_TYS}, }; use hash_reporting::macros::panic_on_span; -use hash_source::{ - constant::{IntConstant, IntConstantValue, CONSTANT_MAP}, - location::Span, -}; +use hash_source::constant::{IntConstant, IntConstantValue, CONSTANT_MAP}; use hash_storage::store::statics::StoreId; use hash_tir::{ args::PatArgsId, @@ -101,7 +98,7 @@ pub(super) struct Test { /// The span of where the test occurs, in order to provide richer /// information to basic block terminations when actually *performing* /// the test - pub span: Span, + pub origin: AstNodeId, } impl Test { @@ -143,7 +140,7 @@ impl<'tcx> BodyBuilder<'tcx> { otherwise: &mut Option, place_builder: &PlaceBuilder, pats: &[PatId], - or_span: Span, + or_origin: AstNodeId, ) { let mut or_candidates: Vec<_> = pats .iter() @@ -169,19 +166,19 @@ impl<'tcx> BodyBuilder<'tcx> { // to simplify anything trivial, and assume the starting block // is the pre-binding block of the overall candidate. self.match_candidates( - or_span, + or_origin, candidate.pre_binding_block.unwrap(), otherwise, &mut or_candidates_ref, ); - self.merge_sub_candidates(candidate, or_span); + self.merge_sub_candidates(candidate, or_origin); } /// Create a [Test] from a [MatchPair]. If this function is called /// on a un-simplified pattern, then this breaks an invariant and the /// function will panic. pub(super) fn test_match_pair(&mut self, pair: &MatchPair) -> Test { - let span = self.span_of_pat(pair.pat); + let origin = self.span_of_pat(pair.pat); // Emit a test for a literal kind of pattern, here we also consider // constants as being literals. @@ -189,9 +186,9 @@ impl<'tcx> BodyBuilder<'tcx> { // If it is not an integral constant, we use an `Eq` test. This will // happen when the constant is either a float or a string. if value.is_switchable() { - Test { kind: TestKind::SwitchInt { ty, options: Default::default() }, span } + Test { kind: TestKind::SwitchInt { ty, options: Default::default() }, origin } } else { - Test { kind: TestKind::Eq { ty, value }, span } + Test { kind: TestKind::Eq { ty, value }, origin } } }; @@ -211,7 +208,7 @@ impl<'tcx> BodyBuilder<'tcx> { // Structs can be simplified... if adt.flags.is_struct() { panic_on_span!( - span.into_location(self.source_id), + origin.span(), self.source_map(), "attempt to test simplify-able pattern, `{}`", (pair.pat) @@ -226,7 +223,7 @@ impl<'tcx> BodyBuilder<'tcx> { adt, options: FixedBitSet::with_capacity(variant_count), }, - span, + origin, } } _ => unreachable!("non-bool, non-adt type in test_match_pair"), @@ -239,16 +236,16 @@ impl<'tcx> BodyBuilder<'tcx> { // If it is not an integral constant, we use an `Eq` test. This will // happen when the constant is either a float or a string. if value.is_switchable() { - Test { kind: TestKind::SwitchInt { ty, options: Default::default() }, span } + Test { kind: TestKind::SwitchInt { ty, options: Default::default() }, origin } } else { - Test { kind: TestKind::Eq { ty, value }, span } + Test { kind: TestKind::Eq { ty, value }, origin } } } Pat::Range(ref range_pat) => { let ty = self.ty_id_from_tir_pat(pair.pat); Test { kind: TestKind::Range { range: ConstRange::from_range(range_pat, ty, self) }, - span, + origin, } } Pat::Array(array_pat) => { @@ -257,19 +254,19 @@ impl<'tcx> BodyBuilder<'tcx> { let len = (prefix.len() + suffix.len()) as u64; let op = if rest.is_some() { BinOp::GtEq } else { BinOp::Eq }; - Test { kind: TestKind::Len { len, op }, span } + Test { kind: TestKind::Len { len, op }, origin } } Pat::If(IfPat { pat, .. }) => { self.test_match_pair(&MatchPair { pat, place: pair.place.clone() }) } Pat::Or(_) => panic_on_span!( - span.into_location(self.source_id), + origin.span(), self.source_map(), "or patterns should be handled by `test_or_pat`" ), Pat::Tuple(_) | Pat::Binding(_) => { panic_on_span!( - span.into_location(self.source_id), + origin.span(), self.source_map(), "attempt to test simplify-able pattern, `{}`", (pair.pat) @@ -558,7 +555,7 @@ impl<'tcx> BodyBuilder<'tcx> { /// [Test]. pub(super) fn perform_test( &mut self, - subject_span: Span, + subject_origin: AstNodeId, block: BasicBlock, place_builder: &PlaceBuilder, test: &Test, @@ -566,7 +563,7 @@ impl<'tcx> BodyBuilder<'tcx> { ) { // Build the place from the provided place builder let place = place_builder.clone().into_place(); - let span = test.span; + let span = test.origin; match test.kind { TestKind::Switch { adt, options: ref variants } => { @@ -605,7 +602,7 @@ impl<'tcx> BodyBuilder<'tcx> { // switch statement. let discriminant_tmp = self.temp_place(discriminant_ty); let value = RValue::Discriminant(place); - self.control_flow_graph.push_assign(block, discriminant_tmp, value, subject_span); + self.control_flow_graph.push_assign(block, discriminant_tmp, value, subject_origin); // then terminate this block with the `switch` terminator self.control_flow_graph.terminate( @@ -773,7 +770,7 @@ impl<'tcx> BodyBuilder<'tcx> { op: BinOp, lhs: Operand, rhs: Operand, - span: Span, + origin: AstNodeId, ) { debug_assert!(op.is_comparator()); @@ -784,13 +781,13 @@ impl<'tcx> BodyBuilder<'tcx> { // rhs)` let operands = Box::new((lhs, rhs)); let value = RValue::BinaryOp(op, operands); - self.control_flow_graph.push_assign(block, result, value, span); + self.control_flow_graph.push_assign(block, result, value, origin); // Then insert the switch statement, which determines where the cfg goes based // on if the comparison was true or false. self.control_flow_graph.terminate( block, - span, + origin, TerminatorKind::make_if(result.into(), success, fail), ); } diff --git a/compiler/hash-lower/src/build/mod.rs b/compiler/hash-lower/src/build/mod.rs index bc047e25e..a6d8b477a 100644 --- a/compiler/hash-lower/src/build/mod.rs +++ b/compiler/hash-lower/src/build/mod.rs @@ -24,10 +24,7 @@ use hash_ir::{ ty::{IrTy, Mutability}, }; use hash_pipeline::settings::CompilerSettings; -use hash_source::{ - identifier::{Identifier, IDENTS}, - SourceId, -}; +use hash_source::identifier::{Identifier, IDENTS}; use hash_storage::store::{statics::StoreId, FxHashMap, PartialCloneStore, SequenceStoreKey}; use hash_tir::{ context::{Context, ScopeKind}, @@ -155,9 +152,6 @@ pub(crate) struct BodyBuilder<'tcx> { /// The item that is being lowered. item: BuildItem, - /// The originating module of where this item is defined. - source_id: SourceId, - /// Number of arguments that will be used in the function, for constant /// expressions, this will be zero. arg_count: usize, @@ -218,7 +212,6 @@ impl<'ctx> BodyBuilder<'ctx> { pub(crate) fn new( name: Identifier, item: BuildItem, - source_id: SourceId, tcx: BuilderCtx<'ctx>, settings: &'ctx CompilerSettings, ) -> Self { @@ -238,7 +231,6 @@ impl<'ctx> BodyBuilder<'ctx> { ctx: tcx, info: BodyInfo::new(name, source), arg_count, - source_id, control_flow_graph: ControlFlowGraph::new(), declarations: IndexVec::new(), _needed_constants: Vec::new(), @@ -279,7 +271,6 @@ impl<'ctx> BodyBuilder<'ctx> { self.info, self.arg_count, span, - self.source_id, ); // If the body needs to be dumped, then we mark it as such. diff --git a/compiler/hash-lower/src/build/rvalue.rs b/compiler/hash-lower/src/build/rvalue.rs index 2ba88a318..30d956a03 100644 --- a/compiler/hash-lower/src/build/rvalue.rs +++ b/compiler/hash-lower/src/build/rvalue.rs @@ -1,15 +1,13 @@ //! Module that contains logic for handling and creating [RValue]s from //! [Term]s. +use hash_ast::ast::AstNodeId; use hash_ir::{ cast::CastKind, ir::{AssertKind, BasicBlock, BinOp, Const, ConstKind, Operand, RValue, UnaryOp}, ty::{IrTy, IrTyId, Mutability, COMMON_IR_TYS}, }; -use hash_source::{ - constant::{IntConstant, IntTy, InternedInt, CONSTANT_MAP}, - location::Span, -}; +use hash_source::constant::{IntConstant, IntTy, InternedInt, CONSTANT_MAP}; use hash_storage::store::statics::StoreId; use hash_tir::terms::{Term, TermId}; @@ -201,7 +199,7 @@ impl<'tcx> BodyBuilder<'tcx> { &mut self, mut block: BasicBlock, ty: IrTyId, - span: Span, + origin: AstNodeId, op: BinOp, lhs: Operand, rhs: Operand, @@ -232,14 +230,14 @@ impl<'tcx> BodyBuilder<'tcx> { let overflow = temp.field(1); // Push an assignment to the tuple on the operation - self.control_flow_graph.push_assign(block, temp, rvalue, span); + self.control_flow_graph.push_assign(block, temp, rvalue, origin); block = self.assert( block, Operand::Place(overflow), false, AssertKind::Overflow { op, lhs, rhs }, - span, + origin, ); return block.and(result.into()); @@ -266,10 +264,10 @@ impl<'tcx> BodyBuilder<'tcx> { block, is_zero, RValue::BinaryOp(BinOp::Eq, Box::new((rhs, zero_val))), - span, + origin, ); - block = self.assert(block, Operand::Place(is_zero), false, assert_kind, span); + block = self.assert(block, Operand::Place(is_zero), false, assert_kind, origin); // In the case of signed integers, if the RHS value is `-1`, and the LHS // is the MIN value, this will result in a division overflow, we need to @@ -290,14 +288,14 @@ impl<'tcx> BodyBuilder<'tcx> { block, is_negative_one, RValue::BinaryOp(BinOp::Eq, Box::new((rhs, negative_one_val))), - span, + origin, ); self.control_flow_graph.push_assign( block, is_minimum_value, RValue::BinaryOp(BinOp::Eq, Box::new((lhs, minimum_value))), - span, + origin, ); // To simplify the generated control flow, we perform a bit_and operation @@ -312,7 +310,7 @@ impl<'tcx> BodyBuilder<'tcx> { BinOp::BitAnd, Box::new((is_negative_one.into(), is_minimum_value.into())), ), - span, + origin, ); // Now finally, emit the assert @@ -321,7 +319,7 @@ impl<'tcx> BodyBuilder<'tcx> { Operand::Place(is_overflow), false, AssertKind::Overflow { op, lhs, rhs }, - span, + origin, ); } } diff --git a/compiler/hash-lower/src/build/utils.rs b/compiler/hash-lower/src/build/utils.rs index 6544384ec..29661810f 100644 --- a/compiler/hash-lower/src/build/utils.rs +++ b/compiler/hash-lower/src/build/utils.rs @@ -3,6 +3,7 @@ //! provided mappings between nodes to locations, patterns, and //! types. +use hash_ast::ast::AstNodeId; use hash_ir::{ ir::{ AggregateKind, AssertKind, BasicBlock, Const, Local, LocalDecl, Operand, Place, RValue, @@ -11,7 +12,7 @@ use hash_ir::{ ty::{IrTyId, Mutability, COMMON_IR_TYS}, IrCtx, }; -use hash_source::{constant::CONSTANT_MAP, location::Span}; +use hash_source::constant::CONSTANT_MAP; use hash_storage::store::{statics::StoreId, SequenceStore}; use hash_tir::{ data::DataTy, @@ -21,42 +22,39 @@ use hash_tir::{ pats::PatId, symbols::Symbol, terms::TermId, - utils::{common::CommonUtils, AccessToUtils}, + utils::AccessToUtils, }; use hash_utils::log; use super::BodyBuilder; -// @@Temporary: use this for terms that don't have a location -const DUMMY_SPAN: Span = Span::new(0, 0); - impl<'tcx> BodyBuilder<'tcx> { /// Get a reference to a [IrCtx]. pub(crate) fn ctx(&self) -> &IrCtx { self.ctx.lcx } - /// Get the [Span] of a given [PatId]. - pub(crate) fn span_of_pat(&self, id: PatId) -> Span { - self.get_location(id).map(|loc| loc.span).unwrap_or_else(|| { + /// Get the interned span of a given [PatId]. + pub(crate) fn span_of_pat(&self, id: PatId) -> AstNodeId { + self.stores().ast_info().pats().get_node_by_data(id).unwrap_or_else(|| { log::debug!("expected pattern `{}` to have a location", id); - DUMMY_SPAN + AstNodeId::new(0) }) } - /// Get the [Span] of a [FnDefId]. - pub(crate) fn span_of_def(&self, id: FnDefId) -> Span { - self.get_location(id).map(|loc| loc.span).unwrap_or_else(|| { + /// Get the interned span of a [FnDefId]. + pub(crate) fn span_of_def(&self, id: FnDefId) -> AstNodeId { + self.stores().ast_info().fn_defs().get_node_by_data(id).unwrap_or_else(|| { log::debug!("expected function definition `{}` to have a location", id); - DUMMY_SPAN + AstNodeId::new(0) }) } - /// Get the [Span] of a given [TermId]. - pub(crate) fn span_of_term(&self, id: TermId) -> Span { - self.get_location(id).map(|loc| loc.span).unwrap_or_else(|| { + /// Get the interned span of a given [TermId]. + pub(crate) fn span_of_term(&self, id: TermId) -> AstNodeId { + self.stores().ast_info().terms().get_node_by_data(id).unwrap_or_else(|| { log::debug!("expected term `{:?}` to have a location", id); - DUMMY_SPAN + AstNodeId::new(0) }) } @@ -145,13 +143,13 @@ impl<'tcx> BodyBuilder<'tcx> { condition: Operand, expected: bool, kind: AssertKind, - span: Span, + origin: AstNodeId, ) -> BasicBlock { let success_block = self.control_flow_graph.start_new_block(); self.control_flow_graph.terminate( block, - span, + origin, TerminatorKind::Assert { condition, expected, kind, target: success_block }, ); diff --git a/compiler/hash-lower/src/cfg.rs b/compiler/hash-lower/src/cfg.rs index fc4f4b226..8069a3d77 100644 --- a/compiler/hash-lower/src/cfg.rs +++ b/compiler/hash-lower/src/cfg.rs @@ -3,10 +3,10 @@ use std::fmt; +use hash_ast::ast::AstNodeId; use hash_ir::ir::{ BasicBlock, BasicBlockData, Place, RValue, Statement, StatementKind, Terminator, TerminatorKind, }; -use hash_source::location::Span; use hash_utils::index_vec::IndexVec; pub struct ControlFlowGraph { @@ -53,16 +53,16 @@ impl ControlFlowGraph { /// Create a [BasicBlock] that is terminated by a [TerminatorKind::Return] /// and has no other present statements. - pub(crate) fn make_return_block(&mut self) -> BasicBlock { + pub(crate) fn make_return_block(&mut self, origin: AstNodeId) -> BasicBlock { let block = self.start_new_block(); self.block_data_mut(block).terminator = - Some(Terminator { kind: TerminatorKind::Return, span: Span::default() }); + Some(Terminator { kind: TerminatorKind::Return, origin }); block } /// Function to terminate a particular [BasicBlock] provided that it has not /// been already terminated. - pub(crate) fn terminate(&mut self, block: BasicBlock, span: Span, kind: TerminatorKind) { + pub(crate) fn terminate(&mut self, block: BasicBlock, origin: AstNodeId, kind: TerminatorKind) { debug_assert!( self.block_data(block).terminator.is_none(), "terminate: block `{:?}` already has a terminator `{:?}` set", @@ -70,7 +70,7 @@ impl ControlFlowGraph { self.block_data(block).terminator.as_ref().unwrap() ); - self.block_data_mut(block).terminator = Some(Terminator { span, kind }); + self.block_data_mut(block).terminator = Some(Terminator { origin, kind }); } /// Check whether a block has been terminated or not. @@ -89,13 +89,13 @@ impl ControlFlowGraph { block: BasicBlock, place: Place, value: RValue, - span: Span, + origin: AstNodeId, ) { - self.push(block, Statement { kind: StatementKind::Assign(place, value), span }); + self.push(block, Statement { kind: StatementKind::Assign(place, value), origin }); } /// Terminate a [BasicBlock] by adding a [TerminatorKind::Goto] - pub(crate) fn goto(&mut self, source: BasicBlock, target: BasicBlock, span: Span) { - self.terminate(source, span, TerminatorKind::Goto(target)); + pub(crate) fn goto(&mut self, source: BasicBlock, target: BasicBlock, origin: AstNodeId) { + self.terminate(source, origin, TerminatorKind::Goto(target)); } } diff --git a/compiler/hash-lower/src/lib.rs b/compiler/hash-lower/src/lib.rs index 706ab0979..b03ea8efc 100644 --- a/compiler/hash-lower/src/lib.rs +++ b/compiler/hash-lower/src/lib.rs @@ -34,7 +34,7 @@ use hash_pipeline::{ workspace::{SourceStageInfo, Workspace}, }; use hash_semantics::SemanticStorage; -use hash_source::{identifier::IDENTS, location::SourceLocation, SourceId}; +use hash_source::{identifier::IDENTS, SourceId}; use hash_storage::store::{ statics::{SequenceStoreValue, StoreId}, PartialStore, @@ -44,7 +44,6 @@ use hash_tir::{ data::DataTy, directives::DirectiveTarget, environment::{env::Env, source_info::CurrentSourceInfo, stores::tir_stores}, - utils::common::CommonUtils, }; use hash_utils::{ stream_writeln, @@ -153,13 +152,7 @@ impl CompilerStage for IrGen { for func in items.iter() { let name = func.borrow().name.ident(); - // Get the source of the symbol therefore that way - // we can get the source id of the function. - let Some(SourceLocation { id, .. }) = env.get_location(func) else { - panic!("function `{name}` has no defined source location"); - }; - - let mut builder = BodyBuilder::new(name, (*func).into(), id, ctx, settings); + let mut builder = BodyBuilder::new(name, (*func).into(), ctx, settings); builder.build(); let body = builder.finish(); diff --git a/compiler/hash-parser/src/diagnostics/error.rs b/compiler/hash-parser/src/diagnostics/error.rs index aa5f4c4b0..1c214d5e9 100644 --- a/compiler/hash-parser/src/diagnostics/error.rs +++ b/compiler/hash-parser/src/diagnostics/error.rs @@ -6,7 +6,7 @@ use hash_reporting::{ report::{ReportElement, ReportNote, ReportNoteKind}, reporter::{Reporter, Reports}, }; -use hash_source::{identifier::Identifier, location::SourceLocation}; +use hash_source::{identifier::Identifier, location::Span}; use hash_token::{TokenKind, TokenKindVector}; use hash_utils::printing::SequenceDisplay; @@ -22,7 +22,7 @@ pub struct ParseError { /// The kind of the error. kind: ParseErrorKind, /// Location of where the error references - location: SourceLocation, + location: Span, /// An optional vector of tokens that are expected to circumvent the error. expected: Option, /// An optional token in question that was received byt shouldn't of been diff --git a/compiler/hash-parser/src/diagnostics/mod.rs b/compiler/hash-parser/src/diagnostics/mod.rs index 72a6ebd95..708816927 100644 --- a/compiler/hash-parser/src/diagnostics/mod.rs +++ b/compiler/hash-parser/src/diagnostics/mod.rs @@ -9,18 +9,12 @@ use hash_reporting::{ reporter::Reports, }; -use self::{ - error::ParseError, - warning::{ParseWarning, ParseWarningWrapper}, -}; +use self::{error::ParseError, warning::ParseWarning}; use crate::parser::AstGen; impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(super) fn into_reports(mut self) -> Reports { - let current_source_id = self.resolver.current_source_id(); - self.diagnostics().into_reports(Reports::from, |warn| { - Reports::from(ParseWarningWrapper(warn, current_source_id)) - }) + self.diagnostics().into_reports(Reports::from, Reports::from) } } diff --git a/compiler/hash-parser/src/diagnostics/warning.rs b/compiler/hash-parser/src/diagnostics/warning.rs index 91eae2ec0..8df9eee03 100644 --- a/compiler/hash-parser/src/diagnostics/warning.rs +++ b/compiler/hash-parser/src/diagnostics/warning.rs @@ -5,10 +5,7 @@ use std::fmt::Display; use derive_more::Constructor; use hash_ast::ast::Expr; use hash_reporting::reporter::{Reporter, Reports}; -use hash_source::{ - location::{SourceLocation, Span}, - SourceId, -}; +use hash_source::location::Span; use hash_utils::pluralise; use crate::parser::DefinitionKind; @@ -19,8 +16,9 @@ pub struct ParseWarning { /// The kind of warning that is generated, stores relevant information /// about the warning. kind: WarningKind, + /// The highlighter span of the where the warning applies to. - location: Span, + span: Span, } /// When warnings describe that a subject could be being applied @@ -75,10 +73,8 @@ pub enum WarningKind { UselessTyParams { def_kind: DefinitionKind }, } -pub(crate) struct ParseWarningWrapper(pub ParseWarning, pub SourceId); - -impl From for Reports { - fn from(ParseWarningWrapper(warning, id): ParseWarningWrapper) -> Self { +impl From for Reports { + fn from(warning: ParseWarning) -> Self { let mut span_label = "".to_string(); let message = match warning.kind { @@ -108,10 +104,7 @@ impl From for Reports { }; let mut reporter = Reporter::new(); - reporter - .warning() - .title(message) - .add_labelled_span(SourceLocation { span: warning.location, id }, span_label); + reporter.warning().title(message).add_labelled_span(warning.span, span_label); reporter.into_reports() } diff --git a/compiler/hash-parser/src/import_resolver.rs b/compiler/hash-parser/src/import_resolver.rs index bc48b7938..c4687dc53 100644 --- a/compiler/hash-parser/src/import_resolver.rs +++ b/compiler/hash-parser/src/import_resolver.rs @@ -32,7 +32,7 @@ impl<'p> ImportResolver<'p> { } /// Get the [SourceId] associated with the current [ImportResolver] - pub(crate) fn current_source_id(&self) -> SourceId { + pub(crate) fn source(&self) -> SourceId { self.source_id } diff --git a/compiler/hash-parser/src/parser/block.rs b/compiler/hash-parser/src/parser/block.rs index 5271c94ee..025c1b80b 100644 --- a/compiler/hash-parser/src/parser/block.rs +++ b/compiler/hash-parser/src/parser/block.rs @@ -16,7 +16,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let block = gen.parse_body_block_inner(); self.diagnostics.merge_diagnostics(gen.diagnostics); - Ok(self.node_with_span(Block::Body(block), self.current_location())) + Ok(self.node_with_span(Block::Body(block), self.current_pos())) } /// Helper function to simply parse a body block without wrapping it in @@ -28,7 +28,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let block = gen.parse_body_block_inner(); self.merge_diagnostics(gen.diagnostics); - Ok(self.node_with_span(block, self.current_location())) + Ok(self.node_with_span(block, self.current_pos())) } /// Parse a body block that uses itself as the inner generator. This @@ -36,7 +36,8 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// next token is a brace tree. pub(crate) fn parse_body_block_inner(&mut self) -> BodyBlock { // Append the initial statement if there is one. - let mut block = BodyBlock { statements: AstNodes::empty(), expr: None }; + let start = self.current_pos(); + let mut block = BodyBlock { statements: AstNodes::empty(self.span()), expr: None }; // Just return an empty block if we don't get anything if !self.has_token() { @@ -46,6 +47,8 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // firstly check if the first token signals a beginning of a statement, we can // tell this by checking for keywords that must begin a statement... while self.has_token() { + let next_location = self.current_pos(); + let (semi, expr) = match self.parse_top_level_expr() { Ok(Some(res)) => res, Ok(_) => continue, @@ -59,6 +62,10 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { if semi || self.peek().is_some() { block.statements.nodes.push(expr) } else { + // update the `statements` span to reflect the true span of the statements + // that were parsed + let span = self.make_span(start.join(next_location)); + block.statements.set_span(span); block.expr = Some(expr) } } @@ -70,7 +77,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_for_loop(&mut self) -> ParseResult> { debug_assert!(self.current_token().has_kind(TokenKind::Keyword(Keyword::For))); - let start = self.current_location(); + let start = self.current_pos(); // now we parse the singular pattern that begins at the for-loop let pattern = self.parse_singular_pat()?; @@ -90,7 +97,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_while_loop(&mut self) -> ParseResult> { debug_assert!(self.current_token().has_kind(TokenKind::Keyword(Keyword::While))); - let start = self.current_location(); + let start = self.current_pos(); let condition = self.parse_expr_with_precedence(0)?; let while_body = self.parse_block()?; @@ -102,7 +109,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse a match case. A match case involves handling the pattern and the /// expression branch. pub(crate) fn parse_match_case(&mut self) -> ParseResult> { - let start = self.current_location(); + let start = self.current_pos(); let pattern = self.parse_pat()?; self.parse_arrow()?; @@ -116,7 +123,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_match_block(&mut self) -> ParseResult> { debug_assert!(self.current_token().has_kind(TokenKind::Keyword(Keyword::Match))); - let start = self.current_location(); + let start = self.current_pos(); let subject = self.parse_expr_with_precedence(0)?; let mut gen = self.parse_delim_tree(Delimiter::Brace, None)?; @@ -134,14 +141,14 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_if_block(&mut self) -> ParseResult> { debug_assert!(matches!(self.current_token().kind, TokenKind::Keyword(Keyword::If))); - let start = self.current_location(); + let start = self.current_pos(); let mut clauses = vec![]; let mut otherwise_clause = None; + let mut if_span = self.current_pos(); while self.has_token() { - let if_span = self.current_location(); - + if_span = self.current_pos(); let condition = self.parse_expr_with_precedence(0)?; let body = self.parse_block()?; @@ -173,7 +180,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { Ok(self.node_with_joined_span( Block::If(IfBlock { - clauses: AstNodes::new(clauses, None), + clauses: self.nodes_with_span(clauses, start.join(if_span)), otherwise: otherwise_clause, }), start, diff --git a/compiler/hash-parser/src/parser/definitions.rs b/compiler/hash-parser/src/parser/definitions.rs index b6e4ec60f..31c47365c 100644 --- a/compiler/hash-parser/src/parser/definitions.rs +++ b/compiler/hash-parser/src/parser/definitions.rs @@ -56,9 +56,8 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse an [EnumDefEntry]. pub fn parse_enum_def_entry(&mut self) -> ParseResult> { let name = self.parse_name()?; - let name_span = name.span(); - - let mut fields = AstNodes::empty(); + let name_span = name.byte_range(); + let mut fields = self.nodes_with_span(vec![], name_span); if matches!(self.peek(), Some(token) if token.is_paren_tree()) { let mut gen = self.parse_delim_tree(Delimiter::Paren, None)?; @@ -66,6 +65,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { |g| g.parse_nominal_def_param(ParamOrigin::EnumVariant), |g| g.parse_token(TokenKind::Comma), ); + fields.set_span(gen.span()); self.consume_gen(gen); } @@ -90,7 +90,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { &mut self, origin: ParamOrigin, ) -> ParseResult> { - let start = self.next_location(); + let start = self.next_pos(); // Try and parse the name and type let (name, ty) = match self.peek_second() { @@ -152,7 +152,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // then any specified bounds on the argument which are essentially types // that are separated by a `~` fn parse_ty_fn_def_param(&mut self) -> ParseResult> { - let start = self.current_location(); + let start = self.current_pos(); let name = self.parse_name()?; // Now it's followed by a colon @@ -175,7 +175,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { name: Some(name), ty, default: default.map(|node| { - let span = node.span(); + let span = node.byte_range(); self.node_with_span(Expr::Ty(TyExpr { ty: node }), span) }), origin: ParamOrigin::TyFn, @@ -226,15 +226,15 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { self.skip_token(); self.parse_ty_params(def_kind) } - _ => Ok(AstNodes::new(vec![], None)), + _ => Ok(self.nodes_with_span(vec![], self.current_pos())), } } /// Parse a collection of type [Param]s which can appear on nominal /// definitions, and trait definitions. fn parse_ty_params(&mut self, def_kind: DefinitionKind) -> ParseResult> { - let start_span = self.current_location(); - let mut params = AstNodes::empty(); + let start_span = self.current_pos(); + let mut params = self.nodes_with_span(vec![], start_span); // Flag denoting that we were able to parse the ending `>` within the function // def arg @@ -256,7 +256,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::UnExpected, Some(TokenKindVector::from_vec(smallvec![TokenKind::Comma, TokenKind::Gt])), token.map(|t| t.kind), - token.map_or_else(|| self.next_location(), |t| t.span), + token.map_or_else(|| self.next_pos(), |t| t.span), )?, } } @@ -272,20 +272,18 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::UnExpected, Some(TokenKindVector::singleton(TokenKind::Gt)), self.peek().map(|tok| tok.kind), - self.next_location(), + self.next_pos(), )?; } } // Update the ast_nodes span to contain - params.set_span(start_span.join(self.current_location())); + let span = self.make_span(start_span.join(self.current_pos())); + params.set_span(span); // Emit a warning here if there were no params if params.is_empty() { - self.add_warning(ParseWarning::new( - WarningKind::UselessTyParams { def_kind }, - params.span().unwrap(), - )) + self.add_warning(ParseWarning::new(WarningKind::UselessTyParams { def_kind }, span)) } Ok(params) diff --git a/compiler/hash-parser/src/parser/expr.rs b/compiler/hash-parser/src/parser/expr.rs index 2001fcb47..107eeb8e1 100644 --- a/compiler/hash-parser/src/parser/expr.rs +++ b/compiler/hash-parser/src/parser/expr.rs @@ -2,7 +2,7 @@ //! logic that transforms tokens into an AST. use hash_ast::{ast::*, ast_nodes}; use hash_reporting::diagnostic::AccessToDiagnosticsMut; -use hash_source::{constant::CONSTANT_MAP, location::Span}; +use hash_source::{constant::CONSTANT_MAP, location::ByteRange}; use hash_token::{delimiter::Delimiter, keyword::Keyword, Token, TokenKind, TokenKindVector}; use hash_utils::smallvec::smallvec; @@ -17,7 +17,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// semi-colon. #[profiling::function] pub fn parse_top_level_expr(&mut self) -> ParseResult)>> { - let start = self.next_location(); + let start = self.next_pos(); // This is used to handle a semi-colon that occurs at the end of // an expression... @@ -85,7 +85,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } // Emit trailing semis diagnostic - let span = tok.span.join(self.current_location()); + let span = self.make_span(tok.span.join(self.current_pos())); self.add_warning(ParseWarning::new(WarningKind::TrailingSemis(span.len()), span)); } @@ -95,7 +95,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let token = self .next_token() .ok_or_else(|| { - self.make_err(ParseErrorKind::ExpectedExpr, None, None, Some(self.next_location())) + self.make_err(ParseErrorKind::ExpectedExpr, None, None, Some(self.next_pos())) }) .copied()?; @@ -170,7 +170,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } // Non-body blocks kind if kind.begins_block() => { - let start = self.current_location(); + let start = self.current_pos(); let block = match kind { TokenKind::Keyword(Keyword::For) => self.parse_for_loop()?, @@ -235,7 +235,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let gen = self.from_stream(tree, token.span); self.parse_fn_def(gen)? } - false => self.parse_expr_or_tuple(tree, self.current_location())?, + false => self.parse_expr_or_tuple(tree, self.current_pos())?, } } TokenKind::Keyword(Keyword::Continue) => { @@ -280,7 +280,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// it could be that this isn't a type function call, but rather a /// simple binary expression which uses the `<` operator. fn maybe_parse_ty_fn_call(&mut self, subject: AstNode) -> (AstNode, bool) { - let span = subject.span(); + let span = subject.byte_range(); // @@Speed: so here we want to be efficient about type_args, we'll just try to // see if the next token atom is a 'Lt' rather than using parse_token_atom @@ -318,13 +318,13 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ) -> ParseResult> { // first of all, we want to get the lhs... let mut lhs = self.parse_expr()?; - let lhs_span = lhs.span(); + let lhs_span = lhs.byte_range(); // reset the compound_expr flag, since this is a new expression... self.is_compound_expr.set(false); loop { - let op_start = self.next_location(); + let op_start = self.next_pos(); // this doesn't consider operators that have an 'eq' variant because that is // handled at the statement level, since it isn't really a binary // operator... @@ -351,7 +351,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } self.offset.update(|x| x + consumed_tokens as usize); - let op_span = op_start.join(self.current_location()); + let op_span = op_start.join(self.current_pos()); // if the operator is a non-functional, (e.g. as) we need to perform a different // conversion where we transform the AstNode into a @@ -418,14 +418,14 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { self.skip_token(); let tree = self.token_trees.get(tree_index as usize).unwrap(); - self.parse_array_index(subject, tree, self.current_location())? + self.parse_array_index(subject, tree, self.current_pos())? } // Function call TokenKind::Tree(Delimiter::Paren, tree_index) => { self.skip_token(); let tree = self.token_trees.get(tree_index as usize).unwrap(); - self.parse_constructor_call(subject, tree, self.current_location())? + self.parse_constructor_call(subject, tree, self.current_pos())? } _ => break, } @@ -446,7 +446,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// provide is references '.hash' extension file or a directory with a /// `index.hash` file contained within the directory. pub(crate) fn parse_import(&mut self) -> ParseResult> { - let start = self.current_location(); + let start = self.current_pos(); let gen = self.parse_delim_tree(Delimiter::Paren, None)?; let (path, span) = match gen.next_token().copied() { @@ -476,13 +476,13 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { &mut self, subject: AstNode, tree: &'stream [Token], - span: Span, + span: ByteRange, ) -> ParseResult> { let mut gen = self.from_stream(tree, span); let mut args = vec![]; while gen.has_token() { - let start = gen.next_location(); + let start = gen.next_pos(); // here we trying to check if this argument is in form of just an expression or // if there is a name being assigned here... @@ -518,12 +518,12 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } self.consume_gen(gen); - let subject_span = subject.span(); + let subject_span = subject.byte_range(); Ok(self.node_with_joined_span( Expr::ConstructorCall(ConstructorCallExpr { subject, - args: AstNodes::new(args, Some(span)), + args: self.nodes_with_span(args, span), }), subject_span, )) @@ -535,10 +535,10 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { &mut self, subject: AstNode, tree: &'stream [Token], - span: Span, + span: ByteRange, ) -> ParseResult> { let mut gen = self.from_stream(tree, span); - let start = gen.current_location(); + let start = gen.current_pos(); // parse the indexing expression between the square brackets... let index_expr = gen.parse_expr_with_precedence(0)?; @@ -559,7 +559,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// modifier. pub(crate) fn parse_unary_expr(&mut self) -> ParseResult> { let token = *self.current_token(); - let start = self.current_location(); + let start = self.current_pos(); let expr = match &token.kind { TokenKind::Star => Expr::Deref(DerefExpr { data: self.parse_expr()? }), @@ -570,10 +570,9 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { self.skip_token(); // Parse a mutability modifier if any - let mutability = - self.parse_token_fast(TokenKind::Keyword(Keyword::Mut)).map(|_| { - self.node_with_span(Mutability::Mutable, self.current_location()) - }); + let mutability = self + .parse_token_fast(TokenKind::Keyword(Keyword::Mut)) + .map(|_| self.node_with_span(Mutability::Mutable, self.current_pos())); Expr::Ref(RefExpr { inner_expr: self.parse_expr()?, @@ -638,11 +637,12 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { loop { match self.peek() { Some(Token { kind: TokenKind::Ident(ident), span }) if prefixed => { - let mut directive_span = self.current_location(); + let mut directive_span = self.current_pos(); self.skip_token(); directive_span = directive_span.join(*span); - directives.push(AstNode::new(Name { ident: *ident }, directive_span)); + directives + .push(self.node_with_span(Name { ident: *ident }, directive_span)); prefixed = false; } Some(Token { kind: TokenKind::Hash, .. }) if !prefixed => { @@ -668,7 +668,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::ExpectedName, None, token.map(|t| t.kind), - token.map_or_else(|| self.next_location(), |t| t.span), + token.map_or_else(|| self.next_pos(), |t| t.span), )?; } _ => break, @@ -753,7 +753,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ) -> ParseResult> { self.parse_token(TokenKind::Eq)?; let value = self.parse_expr_with_precedence(0)?; - let decl_span = decl.span(); + let decl_span = decl.byte_range(); Ok(self.node_with_joined_span( Expr::MergeDeclaration(MergeDeclaration { decl, value }), @@ -769,14 +769,14 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { #[profiling::function] pub(crate) fn parse_expr_with_re_assignment(&mut self) -> ParseResult<(AstNode, bool)> { let lhs = self.parse_expr_with_precedence(0)?; - let lhs_span = lhs.span(); + let lhs_span = lhs.byte_range(); // Check if we can parse a merge declaration if self.parse_token_fast(TokenKind::Tilde).is_some() { return Ok((self.parse_merge_declaration(lhs)?, false)); } - let start = self.current_location(); + let start = self.current_pos(); let (operator, consumed_tokens) = self.parse_binary_operator(); // Look at the token after the consumed tokens and see if it's an equal sign @@ -808,7 +808,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { subject: AstNode, ) -> ParseResult> { debug_assert!(self.current_token().has_kind(TokenKind::Dot)); - let span = subject.span(); + let span = subject.byte_range(); if let Some(token) = self.peek() && token.kind.is_numeric() { // If the next token kind is a integer with no sign, then we can assume @@ -853,7 +853,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse a [AccessExpr] with a `namespace` access kind. pub(crate) fn parse_ns_access(&self, subject: AstNode) -> ParseResult> { debug_assert!(self.current_token().has_kind(TokenKind::Colon)); - let span = subject.span(); + let span = subject.byte_range(); Ok(self.node_with_joined_span( Expr::Access(AccessExpr { @@ -881,10 +881,10 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_expr_or_tuple( &mut self, tree: &'stream [Token], - span: Span, + span: ByteRange, ) -> ParseResult> { let mut gen = self.from_stream(tree, span); - let start = self.current_location(); + let start = self.current_pos(); // Handle the case if it is an empty stream, this means that if it failed to // parse a function in the form of `() => ...` for whatever reason, then it @@ -894,7 +894,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let tuple = gen.node_with_joined_span( Expr::Lit(LitExpr { data: gen.node_with_joined_span( - Lit::Tuple(TupleLit { elements: ast_nodes![] }), + Lit::Tuple(TupleLit { elements: gen.nodes_with_span(vec![], start) }), start, ), }), @@ -932,7 +932,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { return Ok(expr); } - let mut elements = ast_nodes![entry]; + let mut elements = ast_nodes![entry; gen.span()]; loop { match gen.peek() { @@ -968,7 +968,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// a function type. pub(crate) fn parse_fn_def_param(&mut self) -> ParseResult> { let name = self.parse_name()?; - let name_span = name.span(); + let name_span = name.byte_range(); let ty = match self.peek() { Some(token) if token.has_kind(TokenKind::Colon) => { @@ -996,7 +996,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// of lambdas that can be assigned to variables or passed as arguments /// into other functions. pub(crate) fn parse_fn_def(&mut self, mut gen: Self) -> ParseResult> { - let start = self.current_location(); + let start = self.current_pos(); // parse function definition parameters. let params = @@ -1037,7 +1037,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - let span = gen.parent_span; + let span = gen.span(); self.consume_gen(gen); Ok(AstNodes::new(exprs, span)) diff --git a/compiler/hash-parser/src/parser/lit.rs b/compiler/hash-parser/src/parser/lit.rs index 710fc8e6f..f8d7fb1ab 100644 --- a/compiler/hash-parser/src/parser/lit.rs +++ b/compiler/hash-parser/src/parser/lit.rs @@ -1,7 +1,7 @@ //! Hash Compiler AST generation sources. This file contains the sources to the //! logic that transforms tokens into an AST. use hash_ast::ast::*; -use hash_source::{constant::CONSTANT_MAP, location::Span}; +use hash_source::{constant::CONSTANT_MAP, location::ByteRange}; use hash_token::{keyword::Keyword, Token, TokenKind, TokenKindVector}; use super::AstGen; @@ -87,7 +87,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// this will just parse the entry as a single expression rather than a /// tuple entry with an associated name and type. pub(crate) fn parse_tuple_lit_entry(&mut self) -> ParseResult> { - let start = self.next_location(); + let start = self.next_pos(); let offset = self.offset(); // Determine if this might have a tuple field name and optional type @@ -131,7 +131,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::ExpectedValueAfterTyAnnotation, Some(TokenKindVector::singleton(TokenKind::Eq)), None, - Some(self.next_location()), + Some(self.next_pos()), ) })?; @@ -166,10 +166,10 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_array_lit( &self, tree: &'stream [Token], - span: Span, + span: ByteRange, ) -> ParseResult> { let mut gen = self.from_stream(tree, span); - let mut elements = AstNodes::empty(); + let mut elements = self.nodes_with_joined_span(vec![], span); while gen.has_token() { let expr = gen.parse_expr_with_precedence(0)?; diff --git a/compiler/hash-parser/src/parser/mod.rs b/compiler/hash-parser/src/parser/mod.rs index fad3e90ab..4c56280ca 100644 --- a/compiler/hash-parser/src/parser/mod.rs +++ b/compiler/hash-parser/src/parser/mod.rs @@ -15,7 +15,7 @@ use std::{cell::Cell, fmt::Display}; use hash_ast::ast::*; use hash_reporting::diagnostic::{AccessToDiagnosticsMut, DiagnosticStore}; -use hash_source::location::{SourceLocation, Span}; +use hash_source::location::{ByteRange, Span}; use hash_token::{ delimiter::{Delimiter, DelimiterVariant}, Token, TokenKind, TokenKindVector, @@ -115,7 +115,7 @@ pub struct AstGen<'stream, 'resolver> { /// `k[]` was being parsed, the index component `[]` is expected to be /// non-empty, so the error reporting can grab the span of the `[]` and /// report it as an expected expression. - parent_span: Option, + parent_span: Option, /// The token stream stream: &'stream [Token], @@ -159,7 +159,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Create new AST generator from a provided token stream with inherited /// module resolver and a provided parent span. #[must_use] - pub fn from_stream(&self, stream: &'stream [Token], parent_span: Span) -> Self { + pub fn from_stream(&self, stream: &'stream [Token], parent_span: ByteRange) -> Self { Self { stream, token_trees: self.token_trees, @@ -171,10 +171,16 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - /// Function to create a [SourceLocation] from a [Span] by using the + /// Get the [Span] of the current generator, this asserts that a parent + /// [Span] is present. + pub(crate) fn span(&self) -> Span { + Span { span: self.parent_span.unwrap(), id: self.resolver.source() } + } + + /// Function to create a [Span] from a [ByteRange] by using the /// provided resolver - pub(crate) fn source_location(&self, span: &Span) -> SourceLocation { - SourceLocation { span: *span, id: self.resolver.current_source_id() } + pub(crate) fn make_span(&self, span: ByteRange) -> Span { + Span { span, id: self.resolver.source() } } /// Get the current offset of where the stream is at. @@ -246,7 +252,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Get the current location from the current token, if there is no token at /// the current offset, then the location of the last token is used. - pub(crate) fn current_location(&self) -> Span { + pub(crate) fn current_pos(&self) -> ByteRange { // check that the length of current generator is at least one... if self.stream.is_empty() { return self.parent_span.unwrap_or_default(); @@ -262,12 +268,12 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Get the next location of the token, if there is no token after, we use /// the next character offset to determine the location. - pub(crate) fn next_location(&self) -> Span { + pub(crate) fn next_pos(&self) -> ByteRange { match self.peek() { Some(token) => token.span, None => { - let span = self.current_location(); - Span::new(span.end(), span.end() + 1) + let span = self.current_pos(); + ByteRange::new(span.end(), span.end() + 1) } } } @@ -275,20 +281,39 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Create a new [AstNode] from the information provided by the [AstGen] #[inline(always)] pub fn node(&self, inner: T) -> AstNode { - AstNode::new(inner, self.current_location()) + AstNode::new(inner, self.make_span(self.current_pos())) } /// Create a new [AstNode] from the information provided by the [AstGen] #[inline(always)] - pub fn node_with_span(&self, inner: T, location: Span) -> AstNode { - AstNode::new(inner, location) + pub fn node_with_span(&self, inner: T, location: ByteRange) -> AstNode { + AstNode::new(inner, self.make_span(location)) } - /// Create a new [AstNode] with a span that ranges from the start [Span] to - /// the current [Span]. + /// Create a new [AstNode] with a span that ranges from the start + /// [ByteRange] to join with the [ByteRange]. #[inline(always)] - pub(crate) fn node_with_joined_span(&self, body: T, start: Span) -> AstNode { - AstNode::new(body, start.join(self.current_location())) + pub(crate) fn node_with_joined_span(&self, body: T, start: ByteRange) -> AstNode { + AstNode::new(body, self.make_span(start.join(self.current_pos()))) + } + + /// Create [AstNodes] with a span. + pub(crate) fn nodes_with_span( + &self, + nodes: Vec>, + location: ByteRange, + ) -> AstNodes { + AstNodes::new(nodes, self.make_span(location)) + } + + /// Create [AstNodes] with a span that ranges from the start [ByteRange] to + /// the current [ByteRange]. + pub(crate) fn nodes_with_joined_span( + &self, + nodes: Vec>, + start: ByteRange, + ) -> AstNodes { + AstNodes::new(nodes, self.make_span(start.join(self.current_pos()))) } /// Create an error without wrapping it in an [Err] variant @@ -298,11 +323,11 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { kind: ParseErrorKind, expected: Option, received: Option, - span: Option, + span: Option, ) -> ParseError { ParseError::new( kind, - self.source_location(&span.unwrap_or_else(|| self.current_location())), + self.make_span(span.unwrap_or_else(|| self.current_pos())), expected, received, ) @@ -324,7 +349,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { kind: ParseErrorKind, expected: Option, received: Option, - span: Span, + span: ByteRange, ) -> ParseResult { Err(self.make_err(kind, expected, received, Some(span))) } @@ -417,7 +442,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { mut item: impl FnMut(&mut Self) -> ParseResult>, mut separator: impl FnMut(&mut Self) -> ParseResult<()>, ) -> AstNodes { - let start = self.current_location(); + let start = self.current_pos(); let mut args = vec![]; // flag specifying if the parser has errored but is trying to recover @@ -459,7 +484,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - AstNodes::new(args, Some(start.join(self.current_location()))) + self.nodes_with_joined_span(args, start) } /// This function behaves identically to [parse_separated_fn] except that it @@ -475,7 +500,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { mut item: impl FnMut(&mut Self, usize) -> ParseResult>>, mut separator: impl FnMut(&mut Self) -> ParseResult<()>, ) -> AstNodes { - let start = self.current_location(); + let start = self.current_pos(); let mut args = vec![]; // flag specifying if the parser has errored but is trying to recover @@ -528,7 +553,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - AstNodes::new(args, Some(start.join(self.current_location()))) + self.nodes_with_joined_span(args, start) } /// Function to parse the next [Token] with the specified [TokenKind]. @@ -542,7 +567,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::UnExpected, Some(TokenKindVector::singleton(atom)), token.map(|t| t.kind), - token.map_or_else(|| self.next_location(), |t| t.span), + token.map_or_else(|| self.next_pos(), |t| t.span), ), } } @@ -582,7 +607,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { DelimiterVariant::Left, ))), token.map(|tok| tok.kind), - token.map_or_else(|| self.current_location(), |tok| tok.span), + token.map_or_else(|| self.current_pos(), |tok| tok.span), )?, } } @@ -592,7 +617,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// The function returns [None] if parsing failed, which means the caller /// should get all the diagnostics for the current session. pub(crate) fn parse_module(&mut self) -> AstNode { - let start = self.current_location(); + let start = self.current_pos(); let mut contents = vec![]; while self.has_token() { @@ -607,8 +632,8 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } } - let span = start.join(self.current_location()); - self.node_with_span(Module { contents: AstNodes::new(contents, Some(span)) }, span) + let span = start.join(self.current_pos()); + self.node_with_span(Module { contents: self.nodes_with_joined_span(contents, span) }, span) } /// This function is used to exclusively parse a interactive block which @@ -621,7 +646,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// The function returns [None] if parsing failed, which means the caller /// should get all the diagnostics for the current session. pub(crate) fn parse_expr_from_interactive(&mut self) -> AstNode { - let start = self.current_location(); + let start = self.current_pos(); let body = self.parse_body_block_inner(); self.node_with_joined_span(body, start) diff --git a/compiler/hash-parser/src/parser/name.rs b/compiler/hash-parser/src/parser/name.rs index 44a9a54c5..be188ea96 100644 --- a/compiler/hash-parser/src/parser/name.rs +++ b/compiler/hash-parser/src/parser/name.rs @@ -26,7 +26,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { err, None, None, - token.map(|tok| tok.span).unwrap_or_else(|| self.next_location()), + token.map(|tok| tok.span).unwrap_or_else(|| self.next_pos()), ), } } @@ -44,7 +44,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { err, None, None, - token.map(|tok| tok.span).unwrap_or_else(|| self.next_location()), + token.map(|tok| tok.span).unwrap_or_else(|| self.next_pos()), ), } } diff --git a/compiler/hash-parser/src/parser/operator.rs b/compiler/hash-parser/src/parser/operator.rs index d09dada4d..21743fdfa 100644 --- a/compiler/hash-parser/src/parser/operator.rs +++ b/compiler/hash-parser/src/parser/operator.rs @@ -88,7 +88,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::ExpectedArrow, None, None, - self.next_location(), + self.next_pos(), )?; } @@ -97,7 +97,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::ExpectedArrow, None, None, - self.next_location(), + self.next_pos(), )?; } diff --git a/compiler/hash-parser/src/parser/pat.rs b/compiler/hash-parser/src/parser/pat.rs index 4ba175b7c..1cd4194c5 100644 --- a/compiler/hash-parser/src/parser/pat.rs +++ b/compiler/hash-parser/src/parser/pat.rs @@ -1,8 +1,8 @@ //! Hash Compiler AST generation sources. This file contains the sources to the //! logic that transforms tokens into an AST. -use hash_ast::{ast::*, ast_nodes, origin::PatOrigin}; +use hash_ast::{ast::*, origin::PatOrigin}; use hash_reporting::diagnostic::AccessToDiagnosticsMut; -use hash_source::{identifier::IDENTS, location::Span}; +use hash_source::{identifier::IDENTS, location::ByteRange}; use hash_token::{delimiter::Delimiter, keyword::Keyword, Token, TokenKind}; use super::AstGen; @@ -18,11 +18,11 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub fn parse_pat(&mut self) -> ParseResult> { // attempt to get the next token location as we're starting a pattern here, if // there is no token we should exit and return an error - let start = self.next_location(); + let start = self.next_pos(); // Parse the first pattern, but throw away the location information since that // will be computed at the end anyway... - let mut variants = ast_nodes![]; + let mut variants = self.nodes_with_span(vec![], start); while self.has_token() { let pat = self.parse_pat_with_if()?; @@ -42,14 +42,17 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { if variants.len() == 1 { Ok(variants.nodes.pop().unwrap()) } else { - Ok(self.node_with_joined_span(Pat::Or(OrPat { variants }), start)) + let joined = self.make_span(start.join(self.current_pos())); + variants.set_span(joined); + + Ok(AstNode::new(Pat::Or(OrPat { variants }), joined)) } } /// Parse a [Pat] with an optional `if-guard` after the singular /// pattern. pub fn parse_pat_with_if(&mut self) -> ParseResult> { - let start = self.next_location(); + let start = self.next_pos(); let pat = self.parse_singular_pat()?; match self.peek() { @@ -69,7 +72,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// pattern. pub(crate) fn parse_singular_pat(&mut self) -> ParseResult> { let (mut subject, can_continue) = self.parse_pat_component()?; - let span = subject.span(); + let span = subject.span().span; while let Some(token) = self.peek() && can_continue { subject = match token.kind { @@ -133,7 +136,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// [Pat] can be parsed. The `can_continue` flag is set to `false` if this /// produces a [Pat::Range]. fn parse_pat_component(&mut self) -> ParseResult<(AstNode, bool)> { - let start = self.next_location(); + let start = self.next_pos(); let mut has_range_pat = false; let token = *self .peek() @@ -276,7 +279,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// exported members. The function takes in a token atom because both /// syntaxes use different operators as pattern assigners. pub(crate) fn parse_module_pat_entry(&mut self) -> ParseResult> { - let start = self.current_location(); + let start = self.current_pos(); let name = self.parse_name()?; // if the next token is the correct assigning operator, attempt to parse a @@ -288,7 +291,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { let span = name.span(); let copy = self.node(*name.body()); - self.node_with_span( + AstNode::new( Pat::Binding(BindingPat { name: copy, visibility: None, mutability: None }), span, ) @@ -300,7 +303,11 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse a [ModulePat] which is comprised of a collection of /// [ModulePatEntry]s that are comma separated within a brace tree. - fn parse_module_pat(&mut self, tree: &'stream [Token], span: Span) -> ParseResult { + fn parse_module_pat( + &mut self, + tree: &'stream [Token], + span: ByteRange, + ) -> ParseResult { let mut gen = self.from_stream(tree, span); let mut fields = vec![]; @@ -321,7 +328,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } self.consume_gen(gen); - Ok(ModulePat { fields: AstNodes::new(fields, Some(span)) }) + Ok(ModulePat { fields: self.nodes_with_span(fields, span) }) } /// Parse a [`Pat::Array`] pattern from the token vector. An array pattern @@ -330,7 +337,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_array_pat( &mut self, tree: &'stream [Token], - parent_span: Span, + parent_span: ByteRange, ) -> ParseResult> { let mut gen = self.from_stream(tree, parent_span); @@ -366,14 +373,17 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { pub(crate) fn parse_tuple_pat( &mut self, tree: &'stream [Token], - parent_span: Span, + parent_span: ByteRange, ) -> ParseResult> { // check here if the tree length is 1, and the first token is the comma to check // if it is an empty tuple pattern... if let Some(token) = tree.get(0) { if token.has_kind(TokenKind::Comma) { return Ok(self.node_with_span( - Pat::Tuple(TuplePat { fields: AstNodes::empty(), spread: None }), + Pat::Tuple(TuplePat { + fields: self.nodes_with_span(vec![], parent_span), + spread: None, + }), parent_span, )); } @@ -426,7 +436,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse an entry within a tuple pattern which might contain an optional /// [Name] node. pub(crate) fn parse_tuple_pat_entry(&mut self) -> ParseResult> { - let start = self.next_location(); + let start = self.next_pos(); let (name, pat) = match self.peek() { Some(Token { kind: TokenKind::Ident(_), .. }) => { @@ -462,7 +472,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { position: usize, origin: PatOrigin, ) -> ParseResult<()> { - let start = self.next_location(); + let start = self.next_pos(); for k in 0..3 { self.parse_token_fast(TokenKind::Dot).ok_or_else(|| { @@ -470,7 +480,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::MalformedSpreadPattern(3 - k), None, None, - Some(self.next_location()), + Some(self.next_pos()), ) })?; } @@ -478,7 +488,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // Try and see if there is a identifier that is followed by the spread to try // and bind the capture to a variable let name = self.peek_resultant_fn(|g| g.parse_name()); - let span = start.join(self.current_location()); + let span = start.join(self.current_pos()); // If the spread pattern is already present, then we need to // report this as an error since, a spread pattern can only appear @@ -507,7 +517,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // Parse a mutability modifier if any let mutability = self .parse_token_fast(TokenKind::Keyword(Keyword::Mut)) - .map(|_| self.node_with_span(Mutability::Mutable, self.current_location())); + .map(|_| self.node_with_span(Mutability::Mutable, self.current_pos())); let name = self.parse_name()?; @@ -527,7 +537,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { ParseErrorKind::UnExpected, None, token.map(|t| t.kind), - token.map_or_else(|| self.next_location(), |t| t.span), + token.map_or_else(|| self.next_pos(), |t| t.span), ), } } diff --git a/compiler/hash-parser/src/parser/ty.rs b/compiler/hash-parser/src/parser/ty.rs index d7a52032f..3da84b7b8 100644 --- a/compiler/hash-parser/src/parser/ty.rs +++ b/compiler/hash-parser/src/parser/ty.rs @@ -1,6 +1,6 @@ //! Hash Compiler AST generation sources. This file contains the sources to the //! logic that transforms tokens into an AST. -use hash_ast::{ast::*, ast_nodes}; +use hash_ast::ast::*; use hash_source::identifier::IDENTS; use hash_token::{delimiter::Delimiter, keyword::Keyword, Token, TokenKind, TokenKindVector}; use hash_utils::smallvec::smallvec; @@ -22,7 +22,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// forming binary type expressions. fn parse_ty_with_precedence(&mut self, min_prec: u8) -> ParseResult> { let mut lhs = self.parse_singular_ty()?; - let lhs_span = lhs.span(); + let lhs_span = lhs.byte_range(); loop { let (op, consumed_tokens) = self.parse_ty_op(); @@ -61,7 +61,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// Parse a [Ty]. This includes only singular forms of a type. fn parse_singular_ty(&mut self) -> ParseResult> { let token = self.peek().ok_or_else(|| { - self.make_err(ParseErrorKind::ExpectedType, None, None, Some(self.next_location())) + self.make_err(ParseErrorKind::ExpectedType, None, None, Some(self.next_pos())) })?; let mut multi_ty_components = true; @@ -75,12 +75,12 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // Check if this is a raw ref let kind = self .parse_token_fast(TokenKind::Keyword(Keyword::Raw)) - .map(|_| self.node_with_span(RefKind::Raw, self.current_location())); + .map(|_| self.node_with_span(RefKind::Raw, self.current_pos())); // Parse a mutability modifier if any let mutability = self .parse_token_fast(TokenKind::Keyword(Keyword::Mut)) - .map(|_| self.node_with_span(Mutability::Mutable, self.current_location())); + .map(|_| self.node_with_span(Mutability::Mutable, self.current_pos())); Ty::Ref(RefTy { inner: self.parse_ty()?, kind, mutability }) } @@ -190,7 +190,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { }, span); Ty::Fn(FnTy { - params: ast_nodes![ty_arg], + params: self.nodes_with_span(vec![ty_arg], span), return_ty, }) } @@ -221,7 +221,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { self.parse_token(TokenKind::Lt)?; } - let start = self.current_location(); + let start = self.current_pos(); let mut ty_args = vec![]; loop { @@ -247,7 +247,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // Here, we want to use either a joined span between the name or just the span // of the parsed type let arg_span = - name.as_ref().map_or_else(|| ty.span(), |node| node.span().join(ty.span())); + name.as_ref().map_or_else(|| ty.span(), |node| node.span().join(ty.span())).span; ty_args.push(self.node_with_span(TyArg { name, ty }, arg_span)); @@ -270,8 +270,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } // Update the location of the type bound to reflect the '<' and '>' tokens... - // type_args.set_span(start.join(self.current_location())); - Ok(AstNodes::new(ty_args, Some(start.join(self.current_location())))) + Ok(self.nodes_with_joined_span(ty_args, start)) } /// Parses a [Ty::Fn] which involves a parenthesis token tree with some @@ -279,10 +278,8 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { /// [Ty] that is preceded by an `thin-arrow` (->) after the /// parentheses. e.g. `(i32) -> str` fn parse_fn_or_tuple_ty(&mut self) -> ParseResult { - let mut params = AstNodes::empty(); - let mut gen = self.parse_delim_tree(Delimiter::Paren, None)?; - params.span = gen.parent_span; + let mut params = AstNodes::empty(gen.span()); match gen.peek() { // Handle special case where there is only one comma and no following items... @@ -293,7 +290,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { _ => { params = gen.parse_separated_fn( |g| { - let start = g.next_location(); + let start = g.next_pos(); // Here we have to essentially try and parse a identifier. If this is the // case and then there is a colon present then we @@ -348,11 +345,11 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { // only be fired when the next token is a an `<` debug_assert!(matches!(self.current_token(), Token { kind: TokenKind::Lt, .. })); - let mut arg_span = self.current_location(); + let mut arg_span = self.current_pos(); let mut args = vec![]; loop { - let span = self.current_location(); + let span = self.current_pos(); let name = self.parse_name()?; let ty = match self.parse_token_fast(TokenKind::Colon) { @@ -374,7 +371,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { name: Some(name), ty, default: default.map(|node| { - let span = node.span(); + let span = node.byte_range(); self.node_with_span(Expr::Ty(TyExpr { ty: node }), span) }), origin: ParamOrigin::TyFn, @@ -389,7 +386,7 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { } Some(token) if token.has_kind(TokenKind::Gt) => { self.skip_token(); - arg_span = arg_span.join(self.current_location()); + arg_span = arg_span.join(self.current_pos()); break; } @@ -406,6 +403,6 @@ impl<'stream, 'resolver> AstGen<'stream, 'resolver> { self.parse_thin_arrow()?; let return_ty = self.parse_ty()?; - Ok(Ty::TyFn(TyFn { params: AstNodes::new(args, Some(arg_span)), return_ty })) + Ok(Ty::TyFn(TyFn { params: self.nodes_with_span(args, arg_span), return_ty })) } } diff --git a/compiler/hash-reporting/src/render.rs b/compiler/hash-reporting/src/render.rs index f65940edd..ce58bd97a 100644 --- a/compiler/hash-reporting/src/render.rs +++ b/compiler/hash-reporting/src/render.rs @@ -14,7 +14,7 @@ use std::{ }; use hash_source::{ - location::{RowCol, RowColSpan, SourceLocation}, + location::{RowCol, RowColRange, Span}, SourceMap, }; use hash_utils::highlight::{highlight, Colour, Modifier}; @@ -69,8 +69,8 @@ impl ReportCodeBlock { match self.info.get() { Some(info) => info, None => { - let SourceLocation { span, id } = self.source_location; - let source = sources.line_ranges_by_id(id); + let Span { span, id } = self.source_location; + let source = sources.line_ranges(id); // Compute offset rows and columns from the provided span let start @ RowCol { row: start_row, .. } = source.get_row_col(span.start()); @@ -88,7 +88,7 @@ impl ReportCodeBlock { .chars() .count(); - let span = RowColSpan::new(start, end); + let span = RowColRange::new(start, end); let info = ReportCodeBlockInfo { indent_width, span }; self.info.replace(Some(info)); @@ -342,7 +342,7 @@ impl ReportCodeBlock { } /// Function to render the [ReportCodeBlock] using the provided - /// [SourceLocation], message and [ReportKind]. + /// [Span], message and [ReportKind]. pub(crate) fn render( &self, f: &mut fmt::Formatter, diff --git a/compiler/hash-reporting/src/report.rs b/compiler/hash-reporting/src/report.rs index 2c1dcbb56..ff7dfb3ea 100644 --- a/compiler/hash-reporting/src/report.rs +++ b/compiler/hash-reporting/src/report.rs @@ -2,7 +2,7 @@ use std::{cell::Cell, fmt}; use hash_error_codes::error_codes::HashErrorCode; -use hash_source::location::{RowColSpan, SourceLocation}; +use hash_source::location::{RowColRange, Span}; use hash_utils::highlight::{highlight, Colour, Modifier}; /// A data type representing a comment/message on a specific span in a code @@ -13,7 +13,7 @@ pub struct ReportCodeBlockInfo { pub indent_width: usize, /// The span of the code block but using row and column indices. - pub span: RowColSpan, + pub span: RowColRange, } /// Enumeration describing the kind of [Report]; either being a warning, info or @@ -117,14 +117,14 @@ impl ReportNote { /// optional [ReportCodeBlockInfo] which adds a message pointed to a code item. #[derive(Debug, Clone)] pub struct ReportCodeBlock { - pub source_location: SourceLocation, + pub source_location: Span, pub code_message: String, pub(crate) info: Cell>, } impl ReportCodeBlock { - /// Create a new [ReportCodeBlock] from a [SourceLocation] and a message. - pub fn new(source_location: SourceLocation, code_message: impl ToString) -> Self { + /// Create a new [ReportCodeBlock] from a [Span] and a message. + pub fn new(source_location: Span, code_message: impl ToString) -> Self { Self { source_location, code_message: code_message.to_string(), info: Cell::new(None) } } } @@ -223,16 +223,12 @@ impl Report { } /// Add a code block at the given location to the [Report]. - pub fn add_span(&mut self, location: SourceLocation) -> &mut Self { + pub fn add_span(&mut self, location: Span) -> &mut Self { self.add_element(ReportElement::CodeBlock(ReportCodeBlock::new(location, ""))) } /// Add a labelled code block at the given location to the [Report]. - pub fn add_labelled_span( - &mut self, - location: SourceLocation, - message: impl ToString, - ) -> &mut Self { + pub fn add_labelled_span(&mut self, location: Span, message: impl ToString) -> &mut Self { self.add_element(ReportElement::CodeBlock(ReportCodeBlock::new( location, message.to_string(), diff --git a/compiler/hash-semantics/Cargo.toml b/compiler/hash-semantics/Cargo.toml index 3280eca6e..1508d54f9 100644 --- a/compiler/hash-semantics/Cargo.toml +++ b/compiler/hash-semantics/Cargo.toml @@ -5,7 +5,6 @@ authors = ["The Hash Language authors"] edition = "2021" [dependencies] -bimap = "0.6" dashmap = "5.1" derive_more = "0.99" num-bigint = "0.4" diff --git a/compiler/hash-semantics/src/diagnostics/error.rs b/compiler/hash-semantics/src/diagnostics/error.rs index bc263ea40..3edca8a99 100644 --- a/compiler/hash-semantics/src/diagnostics/error.rs +++ b/compiler/hash-semantics/src/diagnostics/error.rs @@ -5,7 +5,7 @@ use hash_reporting::{ self, reporter::{Reporter, Reports}, }; -use hash_source::location::SourceLocation; +use hash_source::location::Span; use hash_tir::{ environment::env::AccessToEnv, symbols::Symbol, terms::TermId, utils::common::CommonUtils, }; @@ -29,49 +29,49 @@ pub enum SemanticError { NeedMoreTypeAnnotationsToInfer { term: TermId }, /// Traits are not yet supported. - TraitsNotSupported { trait_location: SourceLocation }, + TraitsNotSupported { trait_location: Span }, /// Merge declarations are not yet supported. - MergeDeclarationsNotSupported { merge_location: SourceLocation }, + MergeDeclarationsNotSupported { merge_location: Span }, /// Module patterns are not yet supported. - ModulePatternsNotSupported { location: SourceLocation }, + ModulePatternsNotSupported { location: Span }, /// Some specified symbol was not found. - SymbolNotFound { symbol: Symbol, location: SourceLocation, looking_in: ContextKind }, + SymbolNotFound { symbol: Symbol, location: Span, looking_in: ContextKind }, /// Cannot use a module in a value position. - CannotUseModuleInValuePosition { location: SourceLocation }, + CannotUseModuleInValuePosition { location: Span }, /// Cannot use a module in a type position. - CannotUseModuleInTypePosition { location: SourceLocation }, + CannotUseModuleInTypePosition { location: Span }, /// Cannot use a module in a pattern position. - CannotUseModuleInPatternPosition { location: SourceLocation }, + CannotUseModuleInPatternPosition { location: Span }, /// Cannot use a data type in a value position. - CannotUseDataTypeInValuePosition { location: SourceLocation }, + CannotUseDataTypeInValuePosition { location: Span }, /// Cannot use a data type in a pattern position. - CannotUseDataTypeInPatternPosition { location: SourceLocation }, + CannotUseDataTypeInPatternPosition { location: Span }, /// Cannot use a constructor in a type position. - CannotUseConstructorInTypePosition { location: SourceLocation }, + CannotUseConstructorInTypePosition { location: Span }, /// Cannot use a function in type position. - CannotUseFunctionInTypePosition { location: SourceLocation }, + CannotUseFunctionInTypePosition { location: Span }, /// Cannot use a function in a pattern position. - CannotUseFunctionInPatternPosition { location: SourceLocation }, + CannotUseFunctionInPatternPosition { location: Span }, /// Cannot use a non-constant item in constant position. - CannotUseNonConstantItem { location: SourceLocation }, + CannotUseNonConstantItem { location: Span }, /// Cannot use the subject as a namespace. - InvalidNamespaceSubject { location: SourceLocation }, + InvalidNamespaceSubject { location: Span }, /// Cannot use arguments here. - UnexpectedArguments { location: SourceLocation }, + UnexpectedArguments { location: Span }, /// Type error, forwarded from the typechecker. TypeError { error: TcError }, @@ -80,10 +80,10 @@ pub enum SemanticError { ExhaustivenessError { error: ExhaustivenessError }, /// Type error, forwarded from the typechecker. - EnumTypeAnnotationMustBeOfDefiningType { location: SourceLocation }, + EnumTypeAnnotationMustBeOfDefiningType { location: Span }, /// Given data definition is not a singleton. - DataDefIsNotSingleton { location: SourceLocation }, + DataDefIsNotSingleton { location: Span }, /// An entry point was not found in the entry module. EntryPointNotFound, diff --git a/compiler/hash-semantics/src/passes/ast_utils.rs b/compiler/hash-semantics/src/passes/ast_utils.rs index d8e8d0082..f74fd76b5 100644 --- a/compiler/hash-semantics/src/passes/ast_utils.rs +++ b/compiler/hash-semantics/src/passes/ast_utils.rs @@ -2,7 +2,6 @@ use hash_ast::{ ast::{self, AstNodeRef, BodyBlock, Module, OwnsAstNode}, node_map::SourceRef, }; -use hash_source::location::{SourceLocation, Span}; use hash_tir::symbols::{sym, Symbol}; use crate::{diagnostics::error::SemanticResult, environment::sem_env::AccessToSemEnv}; @@ -40,17 +39,6 @@ pub trait AstPass: AccessToSemEnv { } pub trait AstUtils: AccessToSemEnv { - /// Create a [SourceLocation] from a [Span]. - fn source_location(&self, span: Span) -> SourceLocation { - SourceLocation { span, id: self.current_source_info().source_id() } - } - - /// Create a [SourceLocation] at the given [hash_ast::ast::AstNode]. - fn node_location(&self, node: AstNodeRef) -> SourceLocation { - let node_span = node.span(); - self.source_location(node_span) - } - /// Create a [`Symbol`] for the given [`ast::Name`], or a fresh symbol if no /// name is provided. fn new_symbol_from_ast_name(&self, name: Option<&ast::AstNode>) -> Symbol { diff --git a/compiler/hash-semantics/src/passes/discovery/defs.rs b/compiler/hash-semantics/src/passes/discovery/defs.rs index 2c2e04d39..1e398f5b7 100644 --- a/compiler/hash-semantics/src/passes/discovery/defs.rs +++ b/compiler/hash-semantics/src/passes/discovery/defs.rs @@ -19,7 +19,7 @@ use hash_utils::{ state::LightState, }; -use super::{super::ast_utils::AstUtils, DiscoveryPass}; +use super::DiscoveryPass; use crate::ops::common::CommonOps; /// An item that is discovered: either a definition or a function type. @@ -331,11 +331,7 @@ impl<'tc> DiscoveryPass<'tc> { Some(ast::Expr::Block(block)) => block.data.id(), Some(_) => node.value.as_ref().unwrap().id(), _ => { - panic_on_span!( - self.node_location(node), - self.source_map(), - "Found declaration without value" - ) + panic_on_span!(node.span(), self.source_map(), "Found declaration without value") } }; @@ -448,7 +444,7 @@ impl<'tc> DiscoveryPass<'tc> { ast::Pat::Module(_) => { // This should have been handled pre-tc semantics panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "Found module pattern in stack definition" ) @@ -482,11 +478,7 @@ impl<'tc> DiscoveryPass<'tc> { // @@Invariant: Here we assume that each branch of the or pattern has the same // members This should have already been checked at pre-tc semantics. Some(pat) => self.add_stack_members_in_pat_to_buf(pat.ast_ref(), buf), - None => panic_on_span!( - self.node_location(node), - self.source_map(), - "Found empty or pattern" - ), + None => panic_on_span!(node.span(), self.source_map(), "Found empty or pattern"), }, ast::Pat::If(if_pat) => self.add_stack_members_in_pat_to_buf(if_pat.pat.ast_ref(), buf), ast::Pat::Wild(_) => buf.push(( @@ -551,8 +543,6 @@ impl<'tc> DiscoveryPass<'tc> { def_id: DefId, originating_node: AstNodeRef, ) { - self.stores() - .location() - .add_location_to_target(def_id, self.node_location(originating_node)); + self.stores().location().add_location_to_target(def_id, originating_node.span()); } } diff --git a/compiler/hash-semantics/src/passes/discovery/params.rs b/compiler/hash-semantics/src/passes/discovery/params.rs index 14a442297..92ef78069 100644 --- a/compiler/hash-semantics/src/passes/discovery/params.rs +++ b/compiler/hash-semantics/src/passes/discovery/params.rs @@ -7,7 +7,7 @@ use hash_tir::{ }; use super::DiscoveryPass; -use crate::{ops::common::CommonOps, passes::ast_utils::AstUtils}; +use crate::ops::common::CommonOps; impl<'tc> DiscoveryPass<'tc> { /// Create a parameter list from the given AST generic parameter list, where @@ -27,9 +27,7 @@ impl<'tc> DiscoveryPass<'tc> { }) .map(|index| index.into_symbol()), ); - self.stores() - .location() - .add_locations_to_targets(params_id, |i| Some(self.source_location(params[i].span()))); + self.stores().location().add_locations_to_targets(params_id, |i| Some(params[i].span())); for (i, param) in params.iter().enumerate() { self.ast_info().params().insert(param.id(), ParamId(params_id, i)); diff --git a/compiler/hash-semantics/src/passes/discovery/visitor.rs b/compiler/hash-semantics/src/passes/discovery/visitor.rs index 4a9ae805b..10797075d 100644 --- a/compiler/hash-semantics/src/passes/discovery/visitor.rs +++ b/compiler/hash-semantics/src/passes/discovery/visitor.rs @@ -19,7 +19,7 @@ use hash_tir::{ }; use hash_utils::itertools::Itertools; -use super::{super::ast_utils::AstUtils, defs::ItemId, DiscoveryPass}; +use super::{defs::ItemId, DiscoveryPass}; use crate::{ diagnostics::error::SemanticError, environment::sem_env::AccessToSemEnv, passes::ast_utils::AstPass, @@ -70,14 +70,14 @@ impl<'tc> ast::AstVisitor for DiscoveryPass<'tc> { Some(name) => self.add_declaration_node_to_mod_def(name, node, mod_def_id), None => { return Err(SemanticError::ModulePatternsNotSupported { - location: self.node_location(node), + location: node.span(), }) } } } DefId::Data(_) => { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "found declaration in data definition scope, which should have been handled earlier" ) @@ -102,7 +102,7 @@ impl<'tc> ast::AstVisitor for DiscoveryPass<'tc> { } DefId::Fn(_) => { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "found declaration in function scope, which should instead be in a stack scope" ) @@ -110,14 +110,14 @@ impl<'tc> ast::AstVisitor for DiscoveryPass<'tc> { }, Some(ItemId::Ty(_)) => { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "found declaration in function type scope, which should instead be in a stack scope" ) } None => { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "found declaration before any scopes" ) @@ -375,9 +375,8 @@ impl<'tc> ast::AstVisitor for DiscoveryPass<'tc> { node: ast::AstNodeRef, ) -> Result { // Traits are not yet supported - self.diagnostics().add_error(SemanticError::TraitsNotSupported { - trait_location: self.node_location(node), - }); + self.diagnostics() + .add_error(SemanticError::TraitsNotSupported { trait_location: node.span() }); Ok(()) } diff --git a/compiler/hash-semantics/src/passes/resolution/defs.rs b/compiler/hash-semantics/src/passes/resolution/defs.rs index 965e9f812..aac6109cb 100644 --- a/compiler/hash-semantics/src/passes/resolution/defs.rs +++ b/compiler/hash-semantics/src/passes/resolution/defs.rs @@ -22,7 +22,7 @@ use crate::{ diagnostics::error::{SemanticError, SemanticResult}, environment::sem_env::AccessToSemEnv, ops::common::CommonOps, - passes::ast_utils::{AstPass, AstUtils}, + passes::ast_utils::AstPass, }; impl<'tc> ResolutionPass<'tc> { @@ -148,7 +148,8 @@ impl<'tc> ResolutionPass<'tc> { _ => { self.diagnostics().add_error( SemanticError::EnumTypeAnnotationMustBeOfDefiningType { - location: self.node_location(variant_ty.ast_ref())} + location: variant_ty.span() + } ); } } diff --git a/compiler/hash-semantics/src/passes/resolution/exprs.rs b/compiler/hash-semantics/src/passes/resolution/exprs.rs index b6d9905b6..ef9d5a440 100644 --- a/compiler/hash-semantics/src/passes/resolution/exprs.rs +++ b/compiler/hash-semantics/src/passes/resolution/exprs.rs @@ -53,7 +53,7 @@ use crate::{ diagnostics::error::{SemanticError, SemanticResult}, environment::sem_env::AccessToSemEnv, ops::common::CommonOps, - passes::ast_utils::{AstPass, AstUtils}, + passes::ast_utils::AstPass, }; /// This block converts AST nodes of different kinds into [`AstPath`]s, in order @@ -210,7 +210,7 @@ impl<'tc> ResolutionPass<'tc> { }; self.ast_info().terms().insert(node.id(), term_id); - self.stores().location().add_location_to_target(term_id, self.node_location(node)); + self.stores().location().add_location_to_target(term_id, node.span()); Ok(term_id) } @@ -240,9 +240,7 @@ impl<'tc> ResolutionPass<'tc> { ast::PropertyKind::NamedField(name) => { let mut root = self.expr_as_ast_path(node.body.subject.ast_ref())?.ok_or_else(|| { - SemanticError::InvalidNamespaceSubject { - location: self.node_location(node), - } + SemanticError::InvalidNamespaceSubject { location: node.span() } })?; root.push(AstPathComponent { name: *name, @@ -255,7 +253,7 @@ impl<'tc> ResolutionPass<'tc> { ast::PropertyKind::NumericField(_) => { // Should have been caught at semantics panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "Namespace followed by numeric field found" ) @@ -330,7 +328,7 @@ impl<'tc> ResolutionPass<'tc> { NonTerminalResolvedPathComponent::Mod(_) => { // Modules are not allowed in value positions Err(SemanticError::CannotUseModuleInValuePosition { - location: self.source_location(original_node_span), + location: original_node_span, }) } } @@ -342,7 +340,7 @@ impl<'tc> ResolutionPass<'tc> { } TerminalResolvedPathComponent::CtorPat(_) => { panic_on_span!( - self.source_location(original_node_span), + original_node_span, self.source_map(), "found CtorPat in value ast path" ) @@ -754,7 +752,7 @@ impl<'tc> ResolutionPass<'tc> { }) .unwrap_or_else(|| { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "Found non-stack body block in make_term_from_ast_body_block" ) @@ -797,7 +795,7 @@ impl<'tc> ResolutionPass<'tc> { // Others done during de-sugaring: ast::Block::For(_) | ast::Block::While(_) | ast::Block::If(_) => { panic_on_span!( - self.node_location(node), + node.span(), self.source_map(), "Found non-desugared block in make_term_from_ast_block_expr" ) diff --git a/compiler/hash-semantics/src/passes/resolution/params.rs b/compiler/hash-semantics/src/passes/resolution/params.rs index 5283b2b9c..60f520fca 100644 --- a/compiler/hash-semantics/src/passes/resolution/params.rs +++ b/compiler/hash-semantics/src/passes/resolution/params.rs @@ -18,7 +18,6 @@ use super::ResolutionPass; use crate::{ diagnostics::error::{SemanticError, SemanticResult}, ops::common::CommonOps, - passes::ast_utils::AstUtils, }; /// An argument group in the AST. @@ -40,14 +39,13 @@ pub enum AstArgGroup<'a> { impl AstArgGroup<'_> { /// Get the span of this argument group. - pub fn span(&self) -> Option { + pub fn span(&self) -> Span { match self { AstArgGroup::ExplicitArgs(args) => args.span(), AstArgGroup::ImplicitArgs(args) => args.span(), - AstArgGroup::ExplicitPatArgs(args, spread) => args - .span() - .and_then(|args_span| Some(args_span.join(spread.as_ref()?.span()))) - .or_else(|| Some(spread.as_ref()?.span())), + AstArgGroup::ExplicitPatArgs(args, spread) => spread + .as_ref() + .map_or_else(|| args.span(), |spread| args.span().join(spread.span())), AstArgGroup::TupleArgs(args) => args.span(), } } @@ -305,7 +303,7 @@ impl<'tc> ResolutionPass<'tc> { // Here we are trying to call a function with pattern arguments. // This is not allowed. return Err(SemanticError::CannotUseFunctionInPatternPosition { - location: self.source_location(original_span), + location: original_span, }); } } diff --git a/compiler/hash-semantics/src/passes/resolution/paths.rs b/compiler/hash-semantics/src/passes/resolution/paths.rs index 150cc3b38..658080f43 100644 --- a/compiler/hash-semantics/src/passes/resolution/paths.rs +++ b/compiler/hash-semantics/src/passes/resolution/paths.rs @@ -40,10 +40,7 @@ use super::{ scoping::{BindingKind, ContextKind}, ResolutionPass, }; -use crate::{ - diagnostics::error::{SemanticError, SemanticResult}, - passes::ast_utils::AstUtils, -}; +use crate::diagnostics::error::{SemanticError, SemanticResult}; /// A path component in the AST. /// @@ -69,8 +66,8 @@ impl AstPathComponent<'_> { /// Get the span of this path component. pub fn span(&self) -> Span { let span = self.name_span; - if let Some(last_arg) = self.args.last() && let Some(arg_span) = last_arg.span() { - span.join(arg_span) + if let Some(last_arg) = self.args.last() { + span.join(last_arg.span()) } else { span } @@ -221,9 +218,7 @@ impl<'tc> ResolutionPass<'tc> { } [first, second, _rest @ ..] => { return Err(SemanticError::UnexpectedArguments { - location: self.source_location( - first.span().unwrap().join(second.span().unwrap()), - ), + location: first.span().join(second.span()), }); } }; @@ -247,7 +242,7 @@ impl<'tc> ResolutionPass<'tc> { }), )), None => Err(SemanticError::DataDefIsNotSingleton { - location: self.source_location(component.name_span), + location: component.name_span, }), }, ( @@ -262,12 +257,12 @@ impl<'tc> ResolutionPass<'tc> { }), )), None => Err(SemanticError::DataDefIsNotSingleton { - location: self.source_location(component.name_span), + location: component.name_span, }), }, (ResolvedArgs::Pat(_, _), _) => { Err(SemanticError::CannotUseDataTypeInPatternPosition { - location: self.source_location(component.name_span), + location: component.name_span, }) } } @@ -298,9 +293,7 @@ impl<'tc> ResolutionPass<'tc> { [] => ResolvedArgs::Term(self.new_empty_args()), [arg_group] => self.make_args_from_ast_arg_group(arg_group)?, [_first, second, _rest @ ..] => { - return Err(SemanticError::UnexpectedArguments { - location: self.source_location(second.span().unwrap()), - }); + return Err(SemanticError::UnexpectedArguments { location: second.span() }); } }; @@ -399,13 +392,11 @@ impl<'tc> ResolutionPass<'tc> { ResolvedAstPathComponent::Terminal(_) => { // Cannot namespace further return Err(SemanticError::InvalidNamespaceSubject { - location: self.source_location( - path[..index] - .iter() - .map(|c| c.span()) - .reduce(|a, b| a.join(b)) - .unwrap(), - ), + location: path[..index] + .iter() + .map(|c| c.span()) + .reduce(|a, b| a.join(b)) + .unwrap(), }); } }; diff --git a/compiler/hash-semantics/src/passes/resolution/pats.rs b/compiler/hash-semantics/src/passes/resolution/pats.rs index fd0a3caa3..46e12e261 100644 --- a/compiler/hash-semantics/src/passes/resolution/pats.rs +++ b/compiler/hash-semantics/src/passes/resolution/pats.rs @@ -37,7 +37,6 @@ use super::{ use crate::{ diagnostics::error::{SemanticError, SemanticResult}, ops::common::CommonOps, - passes::ast_utils::AstUtils, }; impl ResolutionPass<'_> { @@ -115,9 +114,7 @@ impl ResolutionPass<'_> { }); Ok(subject_path) } - None => Err(SemanticError::InvalidNamespaceSubject { - location: self.node_location(node.subject.ast_ref()), - }), + None => Err(SemanticError::InvalidNamespaceSubject { location: node.subject.span() }), } } @@ -136,9 +133,7 @@ impl ResolutionPass<'_> { } None => panic!("Expected at least one path component"), }, - None => Err(SemanticError::InvalidNamespaceSubject { - location: self.node_location(node.subject.ast_ref()), - }), + None => Err(SemanticError::InvalidNamespaceSubject { location: node.subject.span() }), } } @@ -193,13 +188,13 @@ impl ResolutionPass<'_> { NonTerminalResolvedPathComponent::Data(_, _) => { // Cannot use a data type in a pattern position Err(SemanticError::CannotUseDataTypeInPatternPosition { - location: self.source_location(original_node_span), + location: original_node_span, }) } NonTerminalResolvedPathComponent::Mod(_) => { // Cannot use a module in a pattern position Err(SemanticError::CannotUseModuleInPatternPosition { - location: self.source_location(original_node_span), + location: original_node_span, }) } }, @@ -227,7 +222,7 @@ impl ResolutionPass<'_> { } TerminalResolvedPathComponent::CtorTerm(_) => { panic_on_span!( - self.source_location(original_node_span), + original_node_span, self.source_map(), "Found constructor term in pattern, expected constructor pattern" ) @@ -236,7 +231,7 @@ impl ResolutionPass<'_> { | TerminalResolvedPathComponent::FnCall(_) => { // Cannot use a function or function call in a pattern position Err(SemanticError::CannotUseFunctionInPatternPosition { - location: self.source_location(original_node_span), + location: original_node_span, }) } }, @@ -307,7 +302,7 @@ impl ResolutionPass<'_> { ast::Pat::Module(_) => { // This should be handled earlier panic_on_span!( - self.source_location(node.span()), + node.span(), self.source_map(), "Found module pattern during symbol resolution" ) @@ -341,7 +336,7 @@ impl ResolutionPass<'_> { }; self.ast_info().pats().insert(node.id(), pat_id); - self.stores().location().add_location_to_target(pat_id, self.node_location(node)); + self.stores().location().add_location_to_target(pat_id, node.span()); Ok(pat_id) } } diff --git a/compiler/hash-semantics/src/passes/resolution/scoping.rs b/compiler/hash-semantics/src/passes/resolution/scoping.rs index 3c6081579..26807b823 100644 --- a/compiler/hash-semantics/src/passes/resolution/scoping.rs +++ b/compiler/hash-semantics/src/passes/resolution/scoping.rs @@ -26,7 +26,6 @@ use crate::{ diagnostics::error::{SemanticError, SemanticResult}, environment::sem_env::{AccessToSemEnv, SemEnv}, ops::common::CommonOps, - passes::ast_utils::AstUtils, }; /// The kind of context we are in. @@ -149,12 +148,9 @@ impl<'tc> Scoping<'tc> { looking_in: ContextKind, ) -> SemanticResult<(Symbol, BindingKind)> { let name = name.into(); - let symbol = - self.lookup_symbol_by_name(name).ok_or_else(|| SemanticError::SymbolNotFound { - symbol: sym(name), - location: self.source_location(span), - looking_in, - })?; + let symbol = self.lookup_symbol_by_name(name).ok_or_else(|| { + SemanticError::SymbolNotFound { symbol: sym(name), location: span, looking_in } + })?; // @@Todo: Ensure that we are in the correct context for the binding. // if self.context().get_current_scope_kind().is_constant() { diff --git a/compiler/hash-semantics/src/passes/resolution/tys.rs b/compiler/hash-semantics/src/passes/resolution/tys.rs index ecf63b2aa..16e107830 100644 --- a/compiler/hash-semantics/src/passes/resolution/tys.rs +++ b/compiler/hash-semantics/src/passes/resolution/tys.rs @@ -33,7 +33,6 @@ use super::{ use crate::{ diagnostics::error::{SemanticError, SemanticResult}, ops::common::CommonOps, - passes::ast_utils::AstUtils, }; impl<'tc> ResolutionPass<'tc> { @@ -78,9 +77,9 @@ impl<'tc> ResolutionPass<'tc> { &self, node: AstNodeRef<'a, ast::AccessTy>, ) -> SemanticResult> { - let mut root = self.ty_as_ast_path(node.body.subject.ast_ref())?.ok_or_else(|| { - SemanticError::InvalidNamespaceSubject { location: self.node_location(node) } - })?; + let mut root = self + .ty_as_ast_path(node.body.subject.ast_ref())? + .ok_or_else(|| SemanticError::InvalidNamespaceSubject { location: node.span() })?; root.push(AstPathComponent { name: node.body.property.ident, @@ -124,7 +123,7 @@ impl<'tc> ResolutionPass<'tc> { NonTerminalResolvedPathComponent::Mod(_) => { // Modules are not allowed in type positions Err(SemanticError::CannotUseModuleInTypePosition { - location: self.source_location(original_node_span), + location: original_node_span, }) } }, @@ -134,7 +133,7 @@ impl<'tc> ResolutionPass<'tc> { } TerminalResolvedPathComponent::CtorPat(_) => { panic_on_span!( - self.source_location(original_node_span), + original_node_span, self.source_map(), "found CtorPat in type ast path" ) @@ -385,16 +384,12 @@ impl<'tc> ResolutionPass<'tc> { self.new_ty(expr) } ast::Ty::Union(_) => { - panic_on_span!( - self.node_location(node), - self.source_map(), - "Found union type after discovery" - ) + panic_on_span!(node.span(), self.source_map(), "Found union type after discovery") } }; self.ast_info().tys().insert(node.id(), ty_id); - self.stores().location().add_location_to_target(ty_id, self.node_location(node)); + self.stores().location().add_location_to_target(ty_id, node.span()); Ok(ty_id) } } diff --git a/compiler/hash-source/src/lib.rs b/compiler/hash-source/src/lib.rs index 18fa874e4..9059b65dc 100644 --- a/compiler/hash-source/src/lib.rs +++ b/compiler/hash-source/src/lib.rs @@ -19,7 +19,7 @@ use hash_utils::{ path::adjust_canonicalisation, range_map::RangeMap, }; -use location::{RowCol, RowColSpan, SourceLocation, Span}; +use location::{ByteRange, RowCol, RowColRange, Span}; use once_cell::sync::OnceCell; /// Used to check what kind of [SourceId] is being @@ -173,17 +173,11 @@ pub enum ModuleKind { pub struct LineRanges(RangeMap); impl LineRanges { - /// Create a new [LineRanges] with a specified number of slots - /// within the [RangeMap]. - pub fn with_capacity(capacity: usize) -> Self { - Self(RangeMap::with_capacity(capacity)) - } - /// Create a line range from a string slice. pub fn new_from_str(s: &str) -> Self { // Pre-allocate the line ranges to a specific size by counting the number of // newline characters within the module source. - let mut ranges = LineRanges::with_capacity(bytecount::count(s.as_bytes(), b'\n')); + let mut ranges = Self(RangeMap::with_capacity(bytecount::count(s.as_bytes(), b'\n'))); // Now, iterate through the source and record the position of each newline // range, and push it into the map. @@ -207,12 +201,12 @@ impl LineRanges { RowCol { row: line, column: index - offset } } - /// Returns the line and column of the given [Span] - pub fn span_into_row_col_span(&self, span: Span) -> RowColSpan { - let start = self.get_row_col(span.start()); - let end = self.get_row_col(span.end()); + /// Returns the line and column of the given [ByteRange] + pub fn row_cols(&self, range: ByteRange) -> RowColRange { + let start = self.get_row_col(range.start()); + let end = self.get_row_col(range.end()); - RowColSpan { start, end } + RowColRange { start, end } } } @@ -405,7 +399,7 @@ impl SourceMap { } /// Get the [LineRanges] for a specific [SourceId]. - pub fn line_ranges_by_id(&self, source_id: SourceId) -> &LineRanges { + pub fn line_ranges(&self, source_id: SourceId) -> &LineRanges { if source_id.is_interactive() { self.interactive_blocks.get(source_id.value() as usize).unwrap().line_ranges() } else { @@ -458,18 +452,18 @@ impl SourceMap { SourceId::new_interactive(id) } - /// Function to get a friendly representation of the [SourceLocation] in + /// Function to get a friendly representation of the [Span] in /// terms of row and column positions. - pub fn get_column_row_span_for(&self, location: SourceLocation) -> RowColSpan { - self.line_ranges_by_id(location.id).span_into_row_col_span(location.span) + pub fn get_row_col_for(&self, location: Span) -> RowColRange { + self.line_ranges(location.id).row_cols(location.span) } - /// Convert a [SourceLocation] in terms of the filename, row and column. + /// Convert a [Span] in terms of the filename, row and column. /// /// @@cleanup: move this out of here. - pub fn fmt_location(&self, location: SourceLocation) -> String { + pub fn fmt_location(&self, location: Span) -> String { let name = self.canonicalised_path_by_id(location.id); - let span = self.get_column_row_span_for(location); + let span = self.get_row_col_for(location); format!("{name}:{span}") } diff --git a/compiler/hash-source/src/location.rs b/compiler/hash-source/src/location.rs index 0299536f3..9a09a3d3f 100644 --- a/compiler/hash-source/src/location.rs +++ b/compiler/hash-source/src/location.rs @@ -8,25 +8,26 @@ use derive_more::Constructor; use crate::SourceId; -/// [Span] represents a location of a range of tokens within the source. +/// [ByteRange] represents a location of a range of tokens within the source. /// /// The first element of the tuple represents the starting byte offset and the /// second element represents the ending byte offset. #[derive(Debug, Eq, Hash, Clone, Copy, PartialEq)] -pub struct Span(u32, u32); +pub struct ByteRange(u32, u32); -impl Span { - /// Create a [Span] by providing a start and end byte position. +impl ByteRange { + /// Create a [ByteRange] by providing a start and end byte position. pub const fn new(start: usize, end: usize) -> Self { debug_assert!(end >= start, "invalid span. start > end"); - Span(start as u32, end as u32) + ByteRange(start as u32, end as u32) } - /// This function is used to join a [Span] to another [Span]. The assumption - /// is made that the left hand-side [Span] ends before the start of the - /// right hand side [Span]. If that is the case, then a new location is - /// created with start position of the `self`, and the end position of the - /// `other`. If that is not the case, the `self` span is returned. + /// This function is used to join a [ByteRange] to another [ByteRange]ange]. + /// The assumption is made that the left hand-side [ByteRange] ends before + /// the start of the right hand side [ByteRange]. If that is the case, then + /// a new location is created with start position of the `self`, and the + /// end position of the `other`. If that is not the case, the `self` + /// span is returned. /// /// In essence, if this was the source stream: /// ```text @@ -40,74 +41,86 @@ impl Span { #[must_use] pub fn join(&self, other: Self) -> Self { if self.end() <= other.start() { - return Span::new(self.start(), other.end()); + return ByteRange::new(self.start(), other.end()); } *self } - /// Get the start of the [Span]. + /// Get the start of the [ByteRange]. pub fn start(&self) -> usize { self.0.try_into().unwrap() } - /// Get the end of the [Span]. + /// Get the end of the [ByteRange]. pub fn end(&self) -> usize { self.1.try_into().unwrap() } - /// Compute the actual size of the [Span] by subtracting the end from start. + /// Compute the actual size of the [ByteRange] by subtracting the end + /// from start. pub fn len(&self) -> usize { self.end() - self.start() } - /// Check if the [Span] is empty. + /// Check if the [ByteRange] is empty. pub fn is_empty(&self) -> bool { self.start() == self.end() } - /// Convert the [Span] into a [SourceLocation]. - pub fn into_location(self, source_id: SourceId) -> SourceLocation { - SourceLocation::new(self, source_id) + /// Convert the [ByteRange] into a [Span]. + pub fn into_location(self, source_id: SourceId) -> Span { + Span::new(self, source_id) } } -impl Default for Span { +impl Default for ByteRange { fn default() -> Self { Self::new(0, 0) } } -impl fmt::Display for Span { +impl fmt::Display for ByteRange { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.0, self.1) } } -/// A [SourceLocation] describes the location of something that is relative to -/// a module that is within the workspace and that has an associated [Span]. +/// A [Span] describes the location of something that is relative to +/// a module that is within the workspace and that has an associated +/// [ByteRange]. /// -/// [SourceLocation]s are only used when printing reports within the +/// [Span]s are only used when printing reports within the /// `hash_reporting` crate. Ideally, data structures that need to store -/// locations of various items should use [Span] and then convert into -/// [SourceLocation]s. +/// locations of various items should use [ByteRange] and then convert into +/// [Span]s. #[derive(Debug, Clone, Copy, Constructor, PartialEq, Eq, Hash)] -pub struct SourceLocation { - /// The associated [Span] with the [SourceLocation]. - pub span: Span, +pub struct Span { + /// The associated [ByteRange] with the [Span]. + pub span: ByteRange, /// The id of the source that the span is referencing. pub id: SourceId, } -impl SourceLocation { - /// Join the span of a [SourceLocation] with another [SourceLocation]. +impl Span { + /// Join the span of a [Span] with another [Span]. /// - /// *Note*: the `id` of both [SourceLocation]s must be the same. + /// *Note*: the `id` of both [Span]s must be the same. pub fn join(self, other: Self) -> Self { - assert!(self.id == other.id); + debug_assert!(self.id == other.id); Self { id: self.id, span: self.span.join(other.span) } } + + /// Get the length of the [Span]. + pub fn len(&self) -> usize { + self.span.len() + } + + /// Check if the [Span] is empty. + pub fn is_empty(&self) -> bool { + self.span.is_empty() + } } /// Represents a position within a source using a `row` and `column` @@ -127,25 +140,25 @@ impl Display for RowCol { } } -/// [RowColSpan] is a data structure that is equivalent to [Span] but uses rows -/// and columns to denote offsets within the source file. [RowColSpan] is only -/// re-used when specific line numbers need to be reported, this shouldn't be -/// used for general purpose storage of positions of source items. +/// [RowColRange] is a data structure that is equivalent to [ByteRange] but uses +/// rows and columns to denote offsets within the source file. [RowColRange] is +/// only re-used when specific line numbers need to be reported, this shouldn't +/// be used for general purpose storage of positions of source items. #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct RowColSpan { - /// The starting position of the [RowColSpan]. +pub struct RowColRange { + /// The starting position of the [RowColRange]. pub start: RowCol, - /// The end position of the [RowColSpan]. + /// The end position of the [RowColRange]. pub end: RowCol, } -impl RowColSpan { - /// Create a new [RowColSpan] from a `start` and `end`. +impl RowColRange { + /// Create a new [RowColRange] from a `start` and `end`. pub fn new(start: RowCol, end: RowCol) -> Self { Self { start, end } } - /// Get the associated rows with the start and end of the [RowColSpan]. + /// Get the associated rows with the start and end of the [RowColRange]. pub fn rows(&self) -> (usize, usize) { (self.start.row, self.end.row) } @@ -155,7 +168,7 @@ impl RowColSpan { } } -impl Display for RowColSpan { +impl Display for RowColRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.start == self.end { write!(f, "{}", self.start) diff --git a/compiler/hash-tir/Cargo.toml b/compiler/hash-tir/Cargo.toml index 4483c6ba6..4eca41b48 100644 --- a/compiler/hash-tir/Cargo.toml +++ b/compiler/hash-tir/Cargo.toml @@ -5,7 +5,6 @@ authors = ["The Hash Language authors"] edition = "2021" [dependencies] -bimap = "0.6" derive_more = "0.99" indexmap = "1.9" num-bigint = "0.4" diff --git a/compiler/hash-tir/src/ast_info.rs b/compiler/hash-tir/src/ast_info.rs index 5e9e08dbf..31e259190 100644 --- a/compiler/hash-tir/src/ast_info.rs +++ b/compiler/hash-tir/src/ast_info.rs @@ -1,7 +1,7 @@ -use std::hash::Hash; +use std::{collections::HashMap, fmt::Debug, hash::Hash}; -use bimap::BiMap; use hash_ast::ast::AstNodeId; +use hash_storage::store::FxHashMap; use hash_utils::parking_lot::RwLock; use crate::{ @@ -17,15 +17,54 @@ use crate::{ tys::TyId, }; +/// This is used to store the relations between [AstNodeId]s and their +/// respective [`T`]. There is no assumption that the relation is uniquely +/// biderctional, e.g. multiple function definitions may point to one +/// [AstNodeId], i.e. mono-morphization. +#[derive(Debug, Default)] +struct AstMapInner { + left: FxHashMap, + right: HashMap, +} + +impl AstMapInner { + /// A new empty map. + pub fn new() -> Self { + Self { left: FxHashMap::default(), right: HashMap::default() } + } + + /// Perform an insertion. + pub fn insert(&mut self, key: AstNodeId, value: T) { + self.left.insert(key, value); + self.right.insert(value, key); + } + + /// Insert a key only into the right map. + pub fn insert_right(&mut self, key: T, value: AstNodeId) { + self.right.insert(key, value); + } + + /// Get the value by left associatation, i.e. by [AstNodeId]. This + /// will return the first item that was registered to the [AstNodeId]. + pub fn get_by_left(&self, key: AstNodeId) -> Option { + self.left.get(&key).copied() + } + + /// Get the value by right association, i.e. by [`T`]. + pub fn get_by_right(&self, key: &T) -> Option { + self.right.get(key).copied() + } +} + /// A partial mapping from AST nodes to `T` and back. #[derive(Debug)] -pub struct AstMap { - data: RwLock>, +pub struct AstMap { + data: RwLock>, } -impl AstMap { +impl AstMap { pub fn new() -> Self { - Self { data: RwLock::new(BiMap::new()) } + Self { data: RwLock::new(AstMapInner::new()) } } pub fn insert(&self, ast_id: AstNodeId, data: T) { @@ -33,7 +72,7 @@ impl AstMap { } } -impl Default for AstMap { +impl Default for AstMap { fn default() -> Self { Self::new() } @@ -41,11 +80,27 @@ impl Default for AstMap { impl AstMap { pub fn get_data_by_node(&self, ast_id: AstNodeId) -> Option { - self.data.read().get_by_left(&ast_id).copied() + self.data.read().get_by_left(ast_id) } pub fn get_node_by_data(&self, data: T) -> Option { - self.data.read().get_by_right(&data).copied() + self.data.read().get_by_right(&data) + } + + /// This will copy the node from `src` to `dest`. This is useful for + /// when we want to copy over [AstNodeId] reference from the source + /// to destination. If the `src` does not have a [AstNodeId] associated + /// with it, then this will do nothing. + pub fn copy_node(&self, src: T, dest: T) { + if src == dest { + return; + } + + let old_data = { self.data.read().get_by_right(&src) }; + + if let Some(ast_id) = old_data { + self.data.write().insert_right(dest, ast_id); + } } } diff --git a/compiler/hash-tir/src/locations.rs b/compiler/hash-tir/src/locations.rs index e04a40f9f..e3a3be111 100644 --- a/compiler/hash-tir/src/locations.rs +++ b/compiler/hash-tir/src/locations.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use hash_source::location::{SourceLocation, Span}; +use hash_source::location::Span; use hash_storage::store::SequenceStoreKey; use hash_utils::parking_lot::RwLock; @@ -24,7 +24,7 @@ macro_rules! location_targets { $( $name($ty), )* - Location(SourceLocation), + Location(Span), } #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] @@ -64,8 +64,8 @@ macro_rules! location_targets { } } - impl From for LocationTarget { - fn from(loc: SourceLocation) -> Self { + impl From for LocationTarget { + fn from(loc: Span) -> Self { Self::Location(loc) } } @@ -135,7 +135,7 @@ location_targets! { #[derive(Debug, Default)] pub struct LocationStore { // @@Performance: DashMap? - data: RwLock>, + data: RwLock>, } impl LocationStore { @@ -144,20 +144,16 @@ impl LocationStore { Self::default() } - /// Add a [SourceLocation] to a specified [LocationTarget] - pub fn add_location_to_target( - &self, - target: impl Into, - location: SourceLocation, - ) { + /// Add a [Span] to a specified [LocationTarget] + pub fn add_location_to_target(&self, target: impl Into, location: Span) { self.data.write().insert(target.into(), location); } - /// Add a set of [SourceLocation]s to a specified [IndexedLocationTarget] + /// Add a set of [Span]s to a specified [IndexedLocationTarget] pub fn add_locations_to_targets( &self, targets: impl Into, - location: impl Fn(usize) -> Option, + location: impl Fn(usize) -> Option, ) { let targets = targets.into(); for target in targets.to_index_range() { @@ -167,32 +163,14 @@ impl LocationStore { } } - /// Get a [SourceLocation] from a specified [LocationTarget] - pub fn get_location(&self, target: impl Into) -> Option { + /// Get a [Span] from a specified [LocationTarget] + pub fn get_location(&self, target: impl Into) -> Option { self.data.read().get(&target.into()).copied() } - /// Get the associated [Span] with from the specified [LocationTarget] - pub fn get_span(&self, target: impl Into) -> Option { - self.get_location(target).map(|loc| loc.span) - } - /// Get the overall [Span] covering all the members of a specified /// [IndexedLocationTarget]. - pub fn get_overall_span(&self, target: impl Into) -> Option { - let target = target.into(); - target - .to_index_range() - .map(|index| self.get_span(LocationTarget::from((target, index)))) - .fold(None, |acc, span| Some(acc?.join(span?))) - } - - /// Get the overall [SourceLocation] covering all the members of a specified - /// [IndexedLocationTarget]. - pub fn get_overall_location( - &self, - target: impl Into, - ) -> Option { + pub fn get_overall_location(&self, target: impl Into) -> Option { let target = target.into(); target .to_index_range() @@ -228,10 +206,10 @@ impl LocationStore { /// Merge the given [LocationTarget]s into a single [LocationTarget] /// provided that they can be merged in terms of order. All `ids` of the - /// [SourceLocation]s must match. + /// [Span]s must match. /// /// **Note**: At least one of the [LocationTarget]s must have an associated - /// [SourceLocation]. + /// [Span]. pub fn merge_locations( &self, locations: impl Iterator, diff --git a/compiler/hash-tir/src/utils/common.rs b/compiler/hash-tir/src/utils/common.rs index 68c1f5c1b..704ace2cb 100644 --- a/compiler/hash-tir/src/utils/common.rs +++ b/compiler/hash-tir/src/utils/common.rs @@ -2,7 +2,7 @@ use hash_source::{ identifier::{Identifier, IDENTS}, - location::SourceLocation, + location::Span, }; use hash_storage::store::{CloneStore, SequenceStore, Store, TrivialKeySequenceStore}; use hash_utils::stream_less_writeln; @@ -123,7 +123,7 @@ pub trait CommonUtils: AccessToEnv { } /// Get the location of a location target. - fn get_location(&self, target: impl Into) -> Option { + fn get_location(&self, target: impl Into) -> Option { self.stores().location().get_location(target) } diff --git a/compiler/hash-tir/src/utils/traversing.rs b/compiler/hash-tir/src/utils/traversing.rs index 6ad0dbdc9..cfcadb3f4 100644 --- a/compiler/hash-tir/src/utils/traversing.rs +++ b/compiler/hash-tir/src/utils/traversing.rs @@ -445,6 +445,8 @@ impl<'env> TraversingUtils<'env> { }?; self.stores().location().copy_location(fn_def_id, new_fn_def); + self.stores().ast_info().fn_defs().copy_node(fn_def_id, new_fn_def); + Ok(new_fn_def) } diff --git a/compiler/hash-token/src/lib.rs b/compiler/hash-token/src/lib.rs index 1469eb182..3a996f1ef 100644 --- a/compiler/hash-token/src/lib.rs +++ b/compiler/hash-token/src/lib.rs @@ -7,26 +7,26 @@ use delimiter::{Delimiter, DelimiterVariant}; use hash_source::{ constant::{InternedFloat, InternedInt, InternedStr}, identifier::Identifier, - location::Span, + location::ByteRange, }; use keyword::Keyword; use smallvec::{smallvec, SmallVec}; /// A Lexeme token that represents the smallest code unit of a hash source file. -/// The token contains a kind which is elaborated by [TokenKind] and a [Span] in -/// the source that is represented as a span. The span is the beginning byte -/// offset, and the number of bytes for the said token. +/// The token contains a kind which is elaborated by [TokenKind] and a +/// [ByteRange] in the source that is represented as a span. The span is the +/// beginning byte offset, and the number of bytes for the said token. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Token { /// The current token type. pub kind: TokenKind, /// The span of the current token. - pub span: Span, + pub span: ByteRange, } impl Token { - /// Create a new token from a kind and a provided [Span]. - pub fn new(kind: TokenKind, span: Span) -> Self { + /// Create a new token from a kind and a provided [ByteRange]. + pub fn new(kind: TokenKind, span: ByteRange) -> Self { Token { kind, span } } diff --git a/compiler/hash-typecheck/Cargo.toml b/compiler/hash-typecheck/Cargo.toml index d4f1141f6..f5adfed45 100644 --- a/compiler/hash-typecheck/Cargo.toml +++ b/compiler/hash-typecheck/Cargo.toml @@ -5,7 +5,6 @@ authors = ["The Hash Language authors"] edition = "2021" [dependencies] -bimap = "0.6" dashmap = "5.1" derive_more = "0.99" itertools = "0.10" diff --git a/compiler/hash-typecheck/src/errors.rs b/compiler/hash-typecheck/src/errors.rs index bf1fee22b..4e2807ea8 100644 --- a/compiler/hash-typecheck/src/errors.rs +++ b/compiler/hash-typecheck/src/errors.rs @@ -6,7 +6,7 @@ use hash_reporting::{ reporter::{Reporter, Reports}, writer::ReportWriter, }; -use hash_source::location::SourceLocation; +use hash_source::location::Span; use hash_storage::store::{SequenceStoreKey, TrivialSequenceStoreKey}; use hash_tir::{ environment::env::{AccessToEnv, Env}, @@ -152,7 +152,7 @@ pub enum TcError { MismatchingFns { a: FnDefId, b: FnDefId }, /// Invalid range pattern literal - InvalidRangePatternLiteral { location: SourceLocation }, + InvalidRangePatternLiteral { location: Span }, /// Invalid range pattern literal TryingToReferenceLocalsInType { ty: TyId }, diff --git a/compiler/hash-untyped-semantics/src/analysis/mod.rs b/compiler/hash-untyped-semantics/src/analysis/mod.rs index 6c14f20e9..be27e8028 100644 --- a/compiler/hash-untyped-semantics/src/analysis/mod.rs +++ b/compiler/hash-untyped-semantics/src/analysis/mod.rs @@ -7,10 +7,7 @@ pub(crate) mod params; use crossbeam_channel::Sender; use hash_ast::{ast::AstNodeRef, origin::BlockOrigin}; use hash_reporting::diagnostic::AccessToDiagnosticsMut; -use hash_source::{ - location::{SourceLocation, Span}, - SourceId, SourceMap, -}; +use hash_source::SourceMap; use crate::diagnostics::{ error::{AnalysisError, AnalysisErrorKind}, @@ -21,14 +18,16 @@ use crate::diagnostics::{ pub struct SemanticAnalyser<'s> { /// Whether the current visitor is within a loop construct. pub(crate) is_in_loop: bool, + /// Whether the current visitor is within a function definition. pub(crate) is_in_fn: bool, + /// Whether the analyser is currently checking a literal pattern pub(crate) is_in_lit_pat: bool, - /// The current id of the source that is being passed. - pub(crate) source_id: SourceId, + /// A reference to the sources of the current job. pub(crate) source_map: &'s SourceMap, + /// The current scope of the traversal, representing which block the /// analyser is walking. pub(crate) current_block: BlockOrigin, @@ -39,13 +38,12 @@ pub struct SemanticAnalyser<'s> { impl<'s> SemanticAnalyser<'s> { /// Create a new semantic analyser - pub fn new(source_map: &'s SourceMap, source_id: SourceId) -> Self { + pub fn new(source_map: &'s SourceMap) -> Self { Self { is_in_loop: false, is_in_fn: false, is_in_lit_pat: false, diagnostics: AnalyserDiagnostics::default(), - source_id, source_map, current_block: BlockOrigin::Root, } @@ -61,12 +59,12 @@ impl<'s> SemanticAnalyser<'s> { /// Append an error to [AnalyserDiagnostics] pub(crate) fn append_error(&mut self, error: AnalysisErrorKind, node: AstNodeRef) { - self.add_error(AnalysisError::new(error, node, self.source_id)) + self.add_error(AnalysisError::new(error, node)) } /// Append an warning to [AnalyserDiagnostics] pub(crate) fn append_warning(&mut self, warning: AnalysisWarningKind, node: AstNodeRef) { - self.add_warning(AnalysisWarning::new(warning, node, self.source_id)) + self.add_warning(AnalysisWarning::new(warning, node)) } /// Given a [Sender], send all of the generated warnings and messaged into @@ -74,9 +72,4 @@ impl<'s> SemanticAnalyser<'s> { pub(crate) fn send_generated_messages(self, sender: &Sender) { self.diagnostics.items.into_iter().for_each(|t| sender.send(t).unwrap()) } - - /// Create a [SourceLocation] from a [Span] - pub(crate) fn source_location(&self, span: Span) -> SourceLocation { - SourceLocation { span, id: self.source_id } - } } diff --git a/compiler/hash-untyped-semantics/src/diagnostics/error.rs b/compiler/hash-untyped-semantics/src/diagnostics/error.rs index f6b83831f..da09ad38e 100644 --- a/compiler/hash-untyped-semantics/src/diagnostics/error.rs +++ b/compiler/hash-untyped-semantics/src/diagnostics/error.rs @@ -9,7 +9,7 @@ use hash_reporting::{ report::{ReportCodeBlock, ReportElement, ReportNote, ReportNoteKind}, reporter::{Reporter, Reports}, }; -use hash_source::{identifier::Identifier, location::SourceLocation, ModuleKind, SourceId}; +use hash_source::{identifier::Identifier, location::Span, ModuleKind}; use super::directives::DirectiveArgument; use crate::analysis::params::FieldNamingExpectation; @@ -20,7 +20,7 @@ pub struct AnalysisError { kind: AnalysisErrorKind, /// Where the error occurred - location: SourceLocation, + location: Span, /// The associated [AstNodeRef] with this error, which is used /// to sort the order that errors are emitted. @@ -28,9 +28,9 @@ pub struct AnalysisError { } impl AnalysisError { - /// Create a new [AnalysisError] from a passed kind and [SourceLocation]. - pub(crate) fn new(kind: AnalysisErrorKind, node: AstNodeRef, id: SourceId) -> Self { - Self { kind, location: SourceLocation { span: node.span(), id }, id: node.id() } + /// Create a new [AnalysisError] from a passed kind and [Span]. + pub(crate) fn new(kind: AnalysisErrorKind, node: AstNodeRef) -> Self { + Self { kind, location: node.span(), id: node.id() } } /// Get the associated [AstNodeId] with this [AnalysisError]. diff --git a/compiler/hash-untyped-semantics/src/diagnostics/warning.rs b/compiler/hash-untyped-semantics/src/diagnostics/warning.rs index 6a8b1d64d..5d3ab1fb6 100644 --- a/compiler/hash-untyped-semantics/src/diagnostics/warning.rs +++ b/compiler/hash-untyped-semantics/src/diagnostics/warning.rs @@ -5,7 +5,7 @@ use hash_reporting::{ report::{ReportCodeBlock, ReportElement, ReportNote, ReportNoteKind}, reporter::{Reporter, Reports}, }; -use hash_source::{identifier::Identifier, location::SourceLocation, SourceId}; +use hash_source::{identifier::Identifier, location::Span}; /// A [AnalysisWarning] is warning that can occur during the semantic pass pub struct AnalysisWarning { @@ -13,7 +13,7 @@ pub struct AnalysisWarning { kind: AnalysisWarningKind, /// Where the warning occurred - location: SourceLocation, + location: Span, /// The associated [AstNodeRef] with this error, which is used /// to sort the order that errors are emitted. @@ -21,9 +21,9 @@ pub struct AnalysisWarning { } impl AnalysisWarning { - /// Create a new [AnalysisWarning] from a passed kind and [SourceLocation]. - pub(crate) fn new(kind: AnalysisWarningKind, node: AstNodeRef, id: SourceId) -> Self { - Self { kind, location: SourceLocation { span: node.span(), id }, id: node.id() } + /// Create a new [AnalysisWarning] from a passed kind and [Span]. + pub(crate) fn new(kind: AnalysisWarningKind, node: AstNodeRef) -> Self { + Self { kind, location: node.span(), id: node.id() } } /// Get the associated [AstNodeId] with this [AnalysisWarning]. diff --git a/compiler/hash-untyped-semantics/src/lib.rs b/compiler/hash-untyped-semantics/src/lib.rs index a24c2353f..911ba772a 100644 --- a/compiler/hash-untyped-semantics/src/lib.rs +++ b/compiler/hash-untyped-semantics/src/lib.rs @@ -66,7 +66,7 @@ impl CompilerStage for UntypedSemanti let source = node_map.get_interactive_block(entry_point.into()); // setup a visitor and the context - let mut visitor = SemanticAnalyser::new(source_map, entry_point); + let mut visitor = SemanticAnalyser::new(source_map); visitor.visit_body_block(source.node_ref()).unwrap(); visitor.send_generated_messages(&sender); @@ -83,7 +83,7 @@ impl CompilerStage for UntypedSemanti continue; } - let mut visitor = SemanticAnalyser::new(source_map, source_id); + let mut visitor = SemanticAnalyser::new(source_map); // Check that all of the root scope statements are only declarations let errors = visitor.visit_module(module.node_ref()).unwrap(); @@ -100,7 +100,7 @@ impl CompilerStage for UntypedSemanti let sender = sender.clone(); scope.spawn(move |_| { - let mut visitor = SemanticAnalyser::new(source_map, source_id); + let mut visitor = SemanticAnalyser::new(source_map); visitor.visit_expr(expr.ast_ref()).unwrap(); visitor.send_generated_messages(&sender); diff --git a/compiler/hash-untyped-semantics/src/visitor.rs b/compiler/hash-untyped-semantics/src/visitor.rs index b84976991..7301aa960 100644 --- a/compiler/hash-untyped-semantics/src/visitor.rs +++ b/compiler/hash-untyped-semantics/src/visitor.rs @@ -113,7 +113,8 @@ impl<'s> SemanticAnalyser<'s> { // Here we should check if in the event that an `intrinsics` directive // is being used only within the `prelude` module. if name == IDENTS.intrinsics { - let module_kind = self.source_map.module_kind_by_id(self.source_id); + let id = directive.span().id; + let module_kind = self.source_map.module_kind_by_id(id); if !matches!(module_kind, Some(ModuleKind::Prelude)) { self.append_error( @@ -398,7 +399,7 @@ impl AstVisitorMutSelf for SemanticAnalyser<'_> { node: hash_ast::ast::AstNodeRef, ) -> Result { panic_on_span!( - self.source_location(node.span()), + node.span(), self.source_map, "hit non de-sugared for-block whilst performing semantic analysis" ); @@ -411,7 +412,7 @@ impl AstVisitorMutSelf for SemanticAnalyser<'_> { node: hash_ast::ast::AstNodeRef, ) -> Result { panic_on_span!( - self.source_location(node.span()), + node.span(), self.source_map, "hit non de-sugared while-block whilst performing semantic analysis" ); @@ -444,7 +445,7 @@ impl AstVisitorMutSelf for SemanticAnalyser<'_> { node: hash_ast::ast::AstNodeRef, ) -> Result { panic_on_span!( - self.source_location(node.span()), + node.span(), self.source_map, "hit non de-sugared if-clause whilst performing semantic analysis" ); @@ -457,7 +458,7 @@ impl AstVisitorMutSelf for SemanticAnalyser<'_> { node: hash_ast::ast::AstNodeRef, ) -> Result { panic_on_span!( - self.source_location(node.span()), + node.span(), self.source_map, "hit non de-sugared if-block whilst performing semantic analysis" );