From abb552283133a9966ebf63137229b978384a0a8d Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Sat, 24 Feb 2024 23:45:42 +0000 Subject: [PATCH] Add a collection context and symbol collection step. --- sway-core/src/lib.rs | 9 +++ sway-core/src/semantic_analysis.rs | 1 + .../ast_node/declaration/declaration.rs | 72 ++++++++++++++++++- .../src/semantic_analysis/ast_node/mod.rs | 21 +++++- .../semantic_analysis/collection_context.rs | 64 +++++++++++++++++ sway-core/src/semantic_analysis/module.rs | 61 +++++++++++++++- .../namespace/lexical_scope.rs | 14 ++++ .../src/semantic_analysis/namespace/mod.rs | 5 +- .../src/semantic_analysis/namespace/module.rs | 8 +-- .../semantic_analysis/namespace/namespace.rs | 31 +++++++- sway-core/src/semantic_analysis/program.rs | 23 +++++- 11 files changed, 294 insertions(+), 15 deletions(-) create mode 100644 sway-core/src/semantic_analysis/collection_context.rs diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 51bb6d05c4b..ab9c64e4bcc 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -486,6 +486,15 @@ pub fn parsed_to_ast( let modules_dep_graph = ty::TyModule::build_dep_graph(handler, &parse_program.root)?; let module_eval_order = modules_dep_graph.compute_order(handler)?; + // Collect the program symbols. + let _collection_ctx = ty::TyProgram::collect( + handler, + engines, + parse_program, + initial_namespace.clone(), + &module_eval_order, + )?; + // Type check the program. let typed_program_opt = ty::TyProgram::type_check( handler, diff --git a/sway-core/src/semantic_analysis.rs b/sway-core/src/semantic_analysis.rs index 7fc8db838e9..2988080309e 100644 --- a/sway-core/src/semantic_analysis.rs +++ b/sway-core/src/semantic_analysis.rs @@ -2,6 +2,7 @@ pub mod ast_node; pub(crate) mod cei_pattern_analysis; pub(crate) mod coins_analysis; +pub mod collection_context; mod module; pub mod namespace; mod node_dependencies; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index d064e6266ed..252c7a6a495 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -1,5 +1,5 @@ use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Named, Spanned}; +use sway_types::{BaseIdent, Named, Spanned}; use crate::{ decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, @@ -10,13 +10,79 @@ use crate::{ }, namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ - type_check_context::EnforceTypeArguments, TypeCheckAnalysis, TypeCheckAnalysisContext, - TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, + collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments, + TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, + TypeCheckFinalizationContext, }, type_system::*, + Engines, }; impl TyDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: parsed::Declaration, + ) -> Result<(), ErrorEmitted> { + match &decl { + parsed::Declaration::VariableDeclaration(decl_id) => { + let var_decl = engines.pe().get_variable(decl_id); + ctx.insert_parsed_symbol(handler, var_decl.name.clone(), decl)?; + } + parsed::Declaration::ConstantDeclaration(decl_id) => { + let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, const_decl.name.clone(), decl)?; + } + parsed::Declaration::TraitTypeDeclaration(decl_id) => { + let trait_type_decl = engines.pe().get_trait_type(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, trait_type_decl.name.clone(), decl)?; + } + parsed::Declaration::EnumDeclaration(decl_id) => { + let enum_decl = engines.pe().get_enum(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, enum_decl.name.clone(), decl)?; + } + parsed::Declaration::FunctionDeclaration(decl_id) => { + let fn_decl = engines.pe().get_function(decl_id); + let _ = ctx.insert_parsed_symbol(handler, fn_decl.name.clone(), decl); + } + parsed::Declaration::TraitDeclaration(decl_id) => { + let trait_decl = engines.pe().get_trait(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, trait_decl.name.clone(), decl)?; + } + parsed::Declaration::ImplTrait(decl_id) => { + let impl_trait = engines.pe().get_impl_trait(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, impl_trait.trait_name.suffix.clone(), decl)?; + } + parsed::Declaration::ImplSelf(decl_id) => { + let impl_self = engines.pe().get_impl_self(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol( + handler, + BaseIdent::new(impl_self.implementing_for.span), + decl, + )?; + } + parsed::Declaration::StructDeclaration(decl_id) => { + let struct_decl = engines.pe().get_struct(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, struct_decl.name.clone(), decl)?; + } + parsed::Declaration::AbiDeclaration(decl_id) => { + let abi_decl = engines.pe().get_abi(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, abi_decl.name.clone(), decl)?; + } + parsed::Declaration::StorageDeclaration(decl_id) => { + let _storage_decl = engines.pe().get_storage(decl_id).as_ref().clone(); + //ctx.insert_parsed_symbol(handler, storage_decl.name.clone(), decl)?; + } + parsed::Declaration::TypeAliasDeclaration(decl_id) => { + let type_alias_decl = engines.pe().get_type_alias(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, type_alias_decl.name, decl.clone())?; + } + }; + + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 73e3650962e..cc37c28a903 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -10,7 +10,7 @@ use crate::{ language::{parsed::*, ty}, semantic_analysis::*, type_system::*, - Ident, + Engines, Ident, }; use sway_error::{ @@ -19,7 +19,26 @@ use sway_error::{ }; use sway_types::{span::Span, Spanned}; +use super::collection_context::SymbolCollectionContext; + impl ty::TyAstNode { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + node: &AstNode, + ) -> Result<(), ErrorEmitted> { + match node.content.clone() { + AstNodeContent::UseStatement(_a) => {} + AstNodeContent::IncludeStatement(_i) => (), + AstNodeContent::Declaration(decl) => ty::TyDecl::collect(handler, engines, ctx, decl)?, + AstNodeContent::Expression(_expr) => (), + AstNodeContent::Error(_spans, _err) => (), + }; + + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/collection_context.rs b/sway-core/src/semantic_analysis/collection_context.rs new file mode 100644 index 00000000000..b29eb3321ca --- /dev/null +++ b/sway-core/src/semantic_analysis/collection_context.rs @@ -0,0 +1,64 @@ +use crate::{ + language::{parsed::Declaration, Visibility}, + semantic_analysis::Namespace, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{span::Span, Ident}; + +#[derive(Clone)] +/// Contextual state tracked and accumulated throughout symbol collecting. +pub struct SymbolCollectionContext { + /// The namespace context accumulated throughout symbol collecting. + pub(crate) namespace: Namespace, +} + +impl SymbolCollectionContext { + /// Initialize a context at the top-level of a module with its namespace. + pub fn new(namespace: Namespace) -> Self { + Self { namespace } + } + + /// Scope the `CollectionContext` with a new lexical scope. + pub fn scoped( + mut self, + with_scoped_ctx: impl FnOnce(SymbolCollectionContext) -> Result, + ) -> Result { + self.namespace.module_mut().push_new_lexical_scope(); + let ret = with_scoped_ctx(self.clone()); + self.namespace.module_mut().pop_lexical_scope(); + ret + } + + /// Enter the submodule with the given name and produce a collection context ready for + /// collecting its content. + /// + /// Returns the result of the given `with_submod_ctx` function. + pub fn enter_submodule( + &mut self, + mod_name: Ident, + visibility: Visibility, + module_span: Span, + with_submod_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T, + ) -> T { + self.namespace + .push_new_submodule(mod_name, visibility, module_span); + //let Self { namespace, .. } = self; + //let mut submod_ns = namespace.enter_submodule(mod_name, visibility, module_span); + let ret = with_submod_ctx(self); + self.namespace.pop_submodule(); + ret + } + + /// Short-hand for calling [Items::insert_parsed_symbol]. + pub(crate) fn insert_parsed_symbol( + &mut self, + _handler: &Handler, + name: Ident, + item: Declaration, + ) -> Result<(), ErrorEmitted> { + self.namespace + .module_mut() + .current_items_mut() + .insert_parsed_symbol(name, item) + } +} diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 1066e3605c3..09752ec50b9 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -23,7 +23,9 @@ use crate::{ Engines, TypeInfo, }; -use super::declaration::auto_impl::AutoImplAbiEncodeContext; +use super::{ + collection_context::SymbolCollectionContext, declaration::auto_impl::AutoImplAbiEncodeContext, +}; #[derive(Clone, Debug)] pub struct ModuleDepGraphEdge(); @@ -215,6 +217,44 @@ impl ty::TyModule { Ok(dep_graph) } + /// Collects the given parsed module to produce a module symbol map. + /// + /// Recursively collects submodules first. + pub fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + parsed: &ParseModule, + module_eval_order: &ModuleEvaluationOrder, + ) -> Result<(), ErrorEmitted> { + let ParseModule { + submodules, + tree, + attributes: _, + span: _, + hash: _, + .. + } = parsed; + + // Analyze submodules first in order of evaluation previously computed by the dependency graph. + module_eval_order.iter().for_each(|eval_mod_name| { + let (name, submodule) = submodules + .iter() + .find(|(submod_name, _submodule)| eval_mod_name == submod_name) + .unwrap(); + let _ = ty::TySubmodule::collect(handler, engines, ctx, name.clone(), submodule); + }); + + let _ = tree + .root_nodes + .iter() + .map(|node| ty::TyAstNode::collect(handler, engines, ctx, node)) + .filter_map(|res| res.ok()) + .collect::>(); + + Ok(()) + } + /// Type-check the given parsed module to produce a typed module. /// /// Recursively type-checks submodules first. @@ -394,6 +434,25 @@ impl ty::TySubmodule { Ok(()) } + pub fn collect( + handler: &Handler, + engines: &Engines, + parent_ctx: &mut SymbolCollectionContext, + mod_name: ModName, + submodule: &ParseSubmodule, + ) -> Result<(), ErrorEmitted> { + let ParseSubmodule { + module, + mod_name_span: _, + visibility, + } = submodule; + let modules_dep_graph = ty::TyModule::build_dep_graph(handler, module)?; + let module_eval_order = modules_dep_graph.compute_order(handler)?; + parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| { + ty::TyModule::collect(handler, engines, submod_ctx, module, &module_eval_order) + }) + } + pub fn type_check( handler: &Handler, parent_ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index f0665e1a670..d84642c58eb 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -2,6 +2,7 @@ use crate::{ decl_engine::*, engine_threading::Engines, language::{ + parsed::Declaration, ty::{self, StructAccessInfo, TyDecl, TyStorageDecl}, CallPath, }, @@ -27,6 +28,7 @@ pub(crate) enum GlobImport { No, } +pub(super) type ParsedSymbolMap = im::OrdMap; pub(super) type SymbolMap = im::OrdMap; // The final `bool` field of `UseSynonyms` is true if the `Vec` path is absolute. pub(super) type UseSynonyms = im::HashMap, GlobImport, ty::TyDecl, bool)>; @@ -55,6 +57,8 @@ pub struct LexicalScope { /// The set of items that exist within some lexical scope via declaration or importing. #[derive(Clone, Debug, Default)] pub struct Items { + /// An ordered map from `Ident`s to their associated parsed declarations. + pub(crate) parsed_symbols: ParsedSymbolMap, /// An ordered map from `Ident`s to their associated typed declarations. pub(crate) symbols: SymbolMap, pub(crate) implemented_traits: TraitMap, @@ -123,6 +127,16 @@ impl Items { self.symbols().keys() } + pub(crate) fn insert_parsed_symbol( + &mut self, + name: Ident, + item: Declaration, + ) -> Result<(), ErrorEmitted> { + self.parsed_symbols.insert(name, item); + + Ok(()) + } + pub(crate) fn insert_symbol( &mut self, handler: &Handler, diff --git a/sway-core/src/semantic_analysis/namespace/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index bf6a1875bf7..ddd3b607f82 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -17,7 +17,8 @@ pub(super) use trait_map::TraitMap; use sway_types::Ident; -type ModuleName = String; - pub type Path = [Ident]; pub type PathBuf = Vec; + +type ModuleName = String; +pub type ModulePath = PathBuf; diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 8cfbdfe10d3..d34240f1b51 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -15,7 +15,7 @@ use super::{ lexical_scope::{GlobImport, Items, LexicalScope, SymbolMap}, root::Root, trait_map::TraitMap, - LexicalScopeId, ModuleName, Path, PathBuf, + LexicalScopeId, ModuleName, ModulePath, Path, }; use sway_ast::ItemConst; @@ -61,7 +61,7 @@ pub struct Module { /// /// When this is the root module, this is equal to `[]`. When this is a /// submodule of the root called "foo", this would be equal to `[foo]`. - pub mod_path: PathBuf, + pub mod_path: ModulePath, } impl Default for Module { @@ -245,12 +245,12 @@ impl Module { .unwrap() } - /// The collection of items declared by this module's root lexical scope. + /// The collection of items declared by this module's current lexical scope. pub fn current_items(&self) -> &Items { &self.current_lexical_scope().items } - /// The mutable collection of items declared by this module's root lexical scope. + /// The mutable collection of items declared by this module's curent lexical scope. pub fn current_items_mut(&mut self) -> &mut Items { &mut self.current_lexical_scope_mut().items } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 89d3b9bfae6..4a4d8e1ca71 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -3,7 +3,9 @@ use crate::{ Engines, Ident, TypeId, }; -use super::{module::Module, root::Root, submodule_namespace::SubmoduleNamespace, Path, PathBuf}; +use super::{ + module::Module, root::Root, submodule_namespace::SubmoduleNamespace, ModulePath, Path, PathBuf, +}; use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::span::Span; @@ -37,7 +39,7 @@ pub struct Namespace { /// /// E.g. when type-checking the root module, this is equal to `[]`. When type-checking a /// submodule of the root called "foo", this would be equal to `[foo]`. - pub(crate) mod_path: PathBuf, + pub(crate) mod_path: ModulePath, } impl Namespace { @@ -248,4 +250,29 @@ impl Namespace { parent_mod_path, } } + + /// Pushes a new submodule to the namespace's module hierarchy. + pub fn push_new_submodule( + &mut self, + mod_name: Ident, + visibility: Visibility, + module_span: Span, + ) { + let module = Module { + name: Some(mod_name.clone()), + visibility, + span: Some(module_span), + ..Default::default() + }; + self.module_mut() + .submodules + .entry(mod_name.to_string()) + .or_insert(module); + self.mod_path.push(mod_name); + } + + /// Pops the current submodule from the namespace's module hierarchy. + pub fn pop_submodule(&mut self) { + self.mod_path.pop(); + } } diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index df27655ab05..9aae688ffce 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -14,11 +14,30 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_ir::{Context, Module}; use super::{ - module::ModuleEvaluationOrder, TypeCheckAnalysis, TypeCheckAnalysisContext, - TypeCheckFinalization, TypeCheckFinalizationContext, + collection_context::SymbolCollectionContext, module::ModuleEvaluationOrder, TypeCheckAnalysis, + TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext, }; impl TyProgram { + /// Collects the given parsed program to produce a symbol map and module evaluation order. + /// + /// The given `initial_namespace` acts as an initial state for each module within this program. + /// It should contain a submodule for each library package dependency. + pub fn collect( + handler: &Handler, + engines: &Engines, + parsed: &ParseProgram, + initial_namespace: namespace::Module, + module_eval_order: &ModuleEvaluationOrder, + ) -> Result { + let namespace = Namespace::init_root(initial_namespace); + let mut ctx = SymbolCollectionContext::new(namespace); + let ParseProgram { root, kind: _ } = parsed; + + ty::TyModule::collect(handler, engines, &mut ctx, root, module_eval_order)?; + Ok(ctx) + } + /// Type-check the given parsed program to produce a typed program. /// /// The given `initial_namespace` acts as an initial state for each module within this program.