From fa00b9bd08d252921672a54daf4f232bdfe4cf2f Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Fri, 23 Aug 2024 12:47:39 +0100 Subject: [PATCH 01/12] Implement `DebugWithEngines` for `Span`. --- sway-core/src/engine_threading.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index e0e151249eb..f4ad12632ef 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -217,6 +217,12 @@ impl DebugWithEngines for Vec { } } +impl DebugWithEngines for Span { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + DisplayWithEngines::fmt(self, f, engines) + } +} + pub trait HashWithEngines { fn hash(&self, state: &mut H, engines: &Engines); } From 5f67287bf4069d74314aa180d6367cc39e6950cb Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Sep 2024 16:34:16 +0100 Subject: [PATCH 02/12] Introduce the collection context in the type check context. --- sway-core/src/lib.rs | 3 +- .../semantic_analysis/ast_node/code_block.rs | 6 +- .../ast_node/declaration/abi.rs | 2 +- .../ast_node/declaration/auto_impl.rs | 4 +- .../ast_node/declaration/declaration.rs | 7 +- .../ast_node/declaration/enum.rs | 2 +- .../ast_node/declaration/function.rs | 4 +- .../ast_node/declaration/impl_trait.rs | 4 +- .../ast_node/declaration/struct.rs | 2 +- .../ast_node/declaration/trait.rs | 317 +++++++++--------- .../ast_node/declaration/trait_fn.rs | 2 +- .../typed/typed_match_branch.rs | 2 +- .../typed/typed_match_expression.rs | 5 +- .../ast_node/expression/typed_expression.rs | 13 +- .../typed_expression/struct_instantiation.rs | 2 +- .../namespace/contract_helpers.rs | 8 +- .../src/semantic_analysis/namespace/module.rs | 20 +- .../semantic_analysis/namespace/namespace.rs | 10 +- .../src/semantic_analysis/namespace/root.rs | 2 +- sway-core/src/semantic_analysis/program.rs | 6 +- .../symbol_collection_context.rs | 14 +- .../symbol_resolve_context.rs | 5 +- .../semantic_analysis/type_check_context.rs | 185 +++++++--- 23 files changed, 382 insertions(+), 243 deletions(-) diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index c744255156d..fcc524ce8a0 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -570,7 +570,7 @@ pub fn parsed_to_ast( let namespace = Namespace::init_root(initial_namespace); // Collect the program symbols. - let _collection_ctx = + let mut collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; // Type check the program. @@ -578,6 +578,7 @@ pub fn parsed_to_ast( handler, engines, parse_program, + &mut collection_ctx, namespace, package_name, build_config, diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index 731a02457bb..7cb40357bca 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -28,7 +28,7 @@ impl ty::TyCodeBlock { is_root: bool, ) -> Result { if !is_root { - let code_block_result = ctx.by_ref().scoped(|mut ctx| { + let code_block_result = ctx.by_ref().scoped(Some(code_block.span()), |mut ctx| { let evaluated_contents = code_block .contents .iter() @@ -57,7 +57,7 @@ impl ty::TyCodeBlock { ctx.by_ref() .with_collecting_unifications() .with_code_block_first_pass(true) - .scoped(|mut ctx| { + .scoped(Some(code_block.span()), |mut ctx| { code_block.contents.iter().for_each(|node| { ty::TyAstNode::type_check(&Handler::default(), ctx.by_ref(), node).ok(); }); @@ -66,7 +66,7 @@ impl ty::TyCodeBlock { ctx.engines.te().reapply_unifications(ctx.engines()); - ctx.by_ref().scoped(|mut ctx| { + ctx.by_ref().scoped(Some(code_block.span()), |mut ctx| { let evaluated_contents = code_block .contents .iter() diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 5e1c6196964..780bfc4b3aa 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -55,7 +55,7 @@ impl ty::TyAbiDecl { // A temporary namespace for checking within this scope. ctx.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None)) .with_self_type(Some(self_type_id)) - .scoped(|mut ctx| { + .scoped(Some(span.clone()), |mut ctx| { // Insert the "self" type param into the namespace. self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref()); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 7d31ce74e83..a08b76d7912 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -324,7 +324,7 @@ where assert!(!handler.has_warnings(), "{:?}", handler); let ctx = self.ctx.by_ref(); - let r = ctx.scoped_and_namespace(|ctx| { + let r = ctx.scoped_and_namespace(None, |ctx| { TyDecl::type_check( &handler, ctx, @@ -375,7 +375,7 @@ where assert!(!handler.has_errors(), "{:?}", handler); let ctx = self.ctx.by_ref(); - let r = ctx.scoped_and_namespace(|ctx| { + let r = ctx.scoped_and_namespace(None, |ctx| { TyDecl::type_check(&handler, ctx, Declaration::ImplSelfOrTrait(decl)) }); 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 49a2b6a636e..a54435f508f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -59,9 +59,10 @@ impl TyDecl { let decl_id = *decl_id; let mut fn_decl = engines.pe().get_function(&decl_id).as_ref().clone(); let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl); - let (_ret, lexical_scope_id) = ctx.scoped(engines, |scoped_ctx| { - TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) - }); + let (_ret, lexical_scope_id) = + ctx.scoped(fn_decl.span.clone(), engines, |scoped_ctx| { + TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) + }); fn_decl.lexical_scope = lexical_scope_id; engines.pe().replace(decl_id, fn_decl); } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index f07975ee2d7..d57740026dc 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -22,7 +22,7 @@ impl ty::TyEnumDecl { } = decl; // create a namespace for the decl, used to create a scope for generics - ctx.scoped(|mut ctx| { + ctx.scoped(Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 6582c0d3c87..6113ab6ab15 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -85,7 +85,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(|mut ctx| { + .scoped(None, |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, @@ -182,7 +182,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(|mut ctx| { + .scoped(None, |mut ctx| { let FunctionDeclaration { body, .. } = fn_decl; let ty::TyFunctionDecl { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 15266d2d2a7..a7f5070f729 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -57,7 +57,7 @@ impl TyImplSelfOrTrait { .with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .with_self_type(Some(self_type_id)) .allow_functions() - .scoped(|mut ctx| { + .scoped(Some(block_span.clone()), |mut ctx| { // Type check the type parameters let new_impl_type_parameters = TypeParameter::type_check_type_params( handler, @@ -304,7 +304,7 @@ impl TyImplSelfOrTrait { // create the namespace for the impl ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .allow_functions() - .scoped(|mut ctx| { + .scoped(Some(block_span.clone()), |mut ctx| { // Create a new type parameter for the "self type". let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span()); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index a04efa0f274..3cd28a9c0fe 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -22,7 +22,7 @@ impl ty::TyStructDecl { } = decl; // create a namespace for the decl, used to create a scope for generics - ctx.scoped(|mut ctx| { + ctx.scoped(Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 552bab4bba8..38f247fe87c 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -55,172 +55,177 @@ impl TyTraitDecl { let self_type = self_type_param.type_id; // A temporary namespace for checking within the trait's scope. - ctx.with_self_type(Some(self_type)).scoped(|mut ctx| { - // Type check the type parameters. - let new_type_parameters = TypeParameter::type_check_type_params( - handler, - ctx.by_ref(), - type_parameters, - Some(self_type_param.clone()), - )?; - - // Recursively make the interface surfaces and methods of the - // supertraits available to this trait. - insert_supertraits_into_namespace( - handler, - ctx.by_ref(), - self_type, - &supertraits, - &SupertraitOf::Trait, - )?; - - // type check the interface surface - let mut new_interface_surface = vec![]; - let mut dummy_interface_surface = vec![]; - - let mut ids: HashSet = HashSet::default(); - - for item in interface_surface.clone().into_iter() { - let decl_name = match item { - TraitItem::TraitFn(_) => None, - TraitItem::Constant(_) => None, - TraitItem::Type(decl_id) => { - let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone(); - let type_decl = - ty::TyTraitType::type_check(handler, ctx.by_ref(), type_decl.clone())?; - let decl_ref = decl_engine.insert(type_decl.clone(), Some(&decl_id)); - dummy_interface_surface.push(ty::TyImplItem::Type(decl_ref.clone())); - new_interface_surface - .push(ty::TyTraitInterfaceItem::Type(decl_ref.clone())); - - Some(type_decl.name) - } - TraitItem::Error(_, _) => None, - }; + ctx.with_self_type(Some(self_type)) + .scoped(Some(span.clone()), |mut ctx| { + // Type check the type parameters. + let new_type_parameters = TypeParameter::type_check_type_params( + handler, + ctx.by_ref(), + type_parameters, + Some(self_type_param.clone()), + )?; + + // Recursively make the interface surfaces and methods of the + // supertraits available to this trait. + insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + self_type, + &supertraits, + &SupertraitOf::Trait, + )?; + + // type check the interface surface + let mut new_interface_surface = vec![]; + let mut dummy_interface_surface = vec![]; + + let mut ids: HashSet = HashSet::default(); + + for item in interface_surface.clone().into_iter() { + let decl_name = match item { + TraitItem::TraitFn(_) => None, + TraitItem::Constant(_) => None, + TraitItem::Type(decl_id) => { + let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone(); + let type_decl = ty::TyTraitType::type_check( + handler, + ctx.by_ref(), + type_decl.clone(), + )?; + let decl_ref = decl_engine.insert(type_decl.clone(), Some(&decl_id)); + dummy_interface_surface.push(ty::TyImplItem::Type(decl_ref.clone())); + new_interface_surface + .push(ty::TyTraitInterfaceItem::Type(decl_ref.clone())); + + Some(type_decl.name) + } + TraitItem::Error(_, _) => None, + }; - if let Some(decl_name) = decl_name { - if !ids.insert(decl_name.clone()) { - handler.emit_err(CompileError::MultipleDefinitionsOfName { - name: decl_name.clone(), - span: decl_name.span(), - }); + if let Some(decl_name) = decl_name { + if !ids.insert(decl_name.clone()) { + handler.emit_err(CompileError::MultipleDefinitionsOfName { + name: decl_name.clone(), + span: decl_name.span(), + }); + } } } - } - // insert placeholder functions representing the interface surface - // to allow methods to use those functions - ctx.insert_trait_implementation( - handler, - CallPath::ident_to_fullpath(name.clone(), ctx.namespace), - new_type_parameters.iter().map(|x| x.into()).collect(), - self_type, - &dummy_interface_surface, - &span, - None, - IsImplSelf::No, - IsExtendingExistingImpl::No, - )?; - let mut dummy_interface_surface = vec![]; - - for item in interface_surface.into_iter() { - let decl_name = match item { - TraitItem::TraitFn(decl_id) => { - let method = engines.pe().get_trait_fn(&decl_id); - let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), &method)?; - let decl_ref = decl_engine.insert(method.clone(), Some(&decl_id)); - dummy_interface_surface.push(ty::TyImplItem::Fn( - decl_engine - .insert( - method.to_dummy_func(AbiMode::NonAbi, Some(self_type)), - None, - ) - .with_parent(decl_engine, (*decl_ref.id()).into()), - )); - new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(decl_ref)); - Some(method.name.clone()) - } - TraitItem::Constant(decl_id) => { - let const_decl = engines.pe().get_constant(&decl_id).as_ref().clone(); - let const_decl = - ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl)?; - let decl_ref = ctx.engines.de().insert(const_decl.clone(), Some(&decl_id)); - new_interface_surface - .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); - - let const_name = const_decl.call_path.suffix.clone(); - ctx.insert_symbol( - handler, - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - decl_id: *decl_ref.id(), - }), - )?; - - Some(const_name) - } - TraitItem::Type(_) => None, - TraitItem::Error(_, _) => { - continue; - } - }; + // insert placeholder functions representing the interface surface + // to allow methods to use those functions + ctx.insert_trait_implementation( + handler, + CallPath::ident_to_fullpath(name.clone(), ctx.namespace), + new_type_parameters.iter().map(|x| x.into()).collect(), + self_type, + &dummy_interface_surface, + &span, + None, + IsImplSelf::No, + IsExtendingExistingImpl::No, + )?; + let mut dummy_interface_surface = vec![]; + + for item in interface_surface.into_iter() { + let decl_name = match item { + TraitItem::TraitFn(decl_id) => { + let method = engines.pe().get_trait_fn(&decl_id); + let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), &method)?; + let decl_ref = decl_engine.insert(method.clone(), Some(&decl_id)); + dummy_interface_surface.push(ty::TyImplItem::Fn( + decl_engine + .insert( + method.to_dummy_func(AbiMode::NonAbi, Some(self_type)), + None, + ) + .with_parent(decl_engine, (*decl_ref.id()).into()), + )); + new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(decl_ref)); + Some(method.name.clone()) + } + TraitItem::Constant(decl_id) => { + let const_decl = engines.pe().get_constant(&decl_id).as_ref().clone(); + let const_decl = + ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl)?; + let decl_ref = + ctx.engines.de().insert(const_decl.clone(), Some(&decl_id)); + new_interface_surface + .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); + + let const_name = const_decl.call_path.suffix.clone(); + ctx.insert_symbol( + handler, + const_name.clone(), + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + decl_id: *decl_ref.id(), + }), + )?; + + Some(const_name) + } + TraitItem::Type(_) => None, + TraitItem::Error(_, _) => { + continue; + } + }; - if let Some(decl_name) = decl_name { - if !ids.insert(decl_name.clone()) { - handler.emit_err(CompileError::MultipleDefinitionsOfName { - name: decl_name.clone(), - span: decl_name.span(), - }); + if let Some(decl_name) = decl_name { + if !ids.insert(decl_name.clone()) { + handler.emit_err(CompileError::MultipleDefinitionsOfName { + name: decl_name.clone(), + span: decl_name.span(), + }); + } } } - } - // insert placeholder functions representing the interface surface - // to allow methods to use those functions - ctx.insert_trait_implementation( - handler, - CallPath::ident_to_fullpath(name.clone(), ctx.namespace()), - new_type_parameters.iter().map(|x| x.into()).collect(), - self_type, - &dummy_interface_surface, - &span, - None, - IsImplSelf::No, - IsExtendingExistingImpl::Yes, - )?; - - // Type check the items. - let mut new_items = vec![]; - for method_decl_id in methods.into_iter() { - let method = engines.pe().get_function(&method_decl_id); - let method = ty::TyFunctionDecl::type_check( + // insert placeholder functions representing the interface surface + // to allow methods to use those functions + ctx.insert_trait_implementation( handler, - ctx.by_ref(), - &method, - true, - false, - Some(self_type_param.type_id), - ) - .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); - new_items.push(ty::TyTraitItem::Fn( - decl_engine.insert(method, Some(&method_decl_id)), - )); - } + CallPath::ident_to_fullpath(name.clone(), ctx.namespace()), + new_type_parameters.iter().map(|x| x.into()).collect(), + self_type, + &dummy_interface_surface, + &span, + None, + IsImplSelf::No, + IsExtendingExistingImpl::Yes, + )?; + + // Type check the items. + let mut new_items = vec![]; + for method_decl_id in methods.into_iter() { + let method = engines.pe().get_function(&method_decl_id); + let method = ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + &method, + true, + false, + Some(self_type_param.type_id), + ) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); + new_items.push(ty::TyTraitItem::Fn( + decl_engine.insert(method, Some(&method_decl_id)), + )); + } - let typed_trait_decl = ty::TyTraitDecl { - name: name.clone(), - type_parameters: new_type_parameters, - self_type: self_type_param, - interface_surface: new_interface_surface, - items: new_items, - supertraits, - visibility, - attributes, - call_path: CallPath::from(name).to_fullpath(ctx.engines(), ctx.namespace()), - span, - }; - Ok(typed_trait_decl) - }) + let typed_trait_decl = ty::TyTraitDecl { + name: name.clone(), + type_parameters: new_type_parameters, + self_type: self_type_param, + interface_surface: new_interface_surface, + items: new_items, + supertraits, + visibility, + attributes, + call_path: CallPath::from(name).to_fullpath(ctx.engines(), ctx.namespace()), + span, + }; + Ok(typed_trait_decl) + }) } /// Retrieves the interface surface and implemented items for this trait. diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 241fb856db7..dbc646217e6 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -31,7 +31,7 @@ impl ty::TyTraitFn { let engines = ctx.engines(); // Create a namespace for the trait function. - ctx.by_ref().scoped(|mut ctx| { + ctx.by_ref().scoped(None, |mut ctx| { // TODO: when we add type parameters to trait fns, type check them here // Type check the parameters. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index 0a1c3870106..fb486e6b63f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -128,7 +128,7 @@ impl ty::TyMatchBranch { )?; // create a new namespace for this branch result - ctx.scoped(|mut scoped_ctx| { + ctx.scoped(Some(branch_span.clone()), |mut scoped_ctx| { // for every variable that comes into result block, create a variable declaration, // insert it into the branch namespace, and add it to the block of code statements let mut code_block_contents: Vec = vec![]; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index 7abdfbc54a3..7af98dda5cd 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -607,10 +607,12 @@ impl ty::TyMatchExpression { matched_or_variant_index_vars, condition, result, + span: branch_span, .. } in self.branches.iter().rev() { if let ControlFlow::Break(_) = self.convert_to_typed_if_expression_inner_branch( + branch_span.clone(), &mut typed_if_exp, condition, result, @@ -629,6 +631,7 @@ impl ty::TyMatchExpression { #[allow(clippy::too_many_arguments)] fn convert_to_typed_if_expression_inner_branch( &self, + branch_span: Span, typed_if_exp: &mut Option, condition: &Option, result: &TyExpression, @@ -655,7 +658,7 @@ impl ty::TyMatchExpression { }; } let ctx = ctx.by_ref().with_type_annotation(self.return_type_id); - ctx.scoped(|mut branch_ctx| { + ctx.scoped(Some(branch_span), |mut branch_ctx| { let result_span = result.span.clone(); let condition = condition .clone() diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index f7505d07b0a..9f3084f1a95 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -2768,6 +2768,7 @@ mod tests { use super::*; use crate::{Engines, ExperimentalFlags}; use sway_error::type_error::TypeError; + use symbol_collection_context::SymbolCollectionContext; fn do_type_check( handler: &Handler, @@ -2776,6 +2777,9 @@ mod tests { type_annotation: TypeId, experimental: ExperimentalFlags, ) -> Result { + let collection_ctx_ns = Namespace::new(); + let mut collection_ctx = SymbolCollectionContext::new(collection_ctx_ns); + let root_module_name = sway_types::Ident::new_no_span("do_type_check_test".to_string()); let mut root_module = namespace::Root::from(namespace::Module::new( root_module_name, @@ -2783,8 +2787,13 @@ mod tests { None, )); let mut namespace = Namespace::init_root(&mut root_module); - let ctx = TypeCheckContext::from_namespace(&mut namespace, engines, experimental) - .with_type_annotation(type_annotation); + let ctx = TypeCheckContext::from_namespace( + &mut namespace, + &mut collection_ctx, + engines, + experimental, + ) + .with_type_annotation(type_annotation); ty::TyExpression::type_check(handler, ctx, expr) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index a6b331768ec..0b1d1211d2a 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -305,7 +305,7 @@ pub(crate) fn struct_instantiation( let instantiation_span = inner_span.clone(); ctx.with_generic_shadowing_mode(GenericShadowingMode::Allow) - .scoped(|mut scoped_ctx| { + .scoped(None, |mut scoped_ctx| { // Insert struct type parameter into namespace. // This is required so check_type_parameter_bounds can resolve generic trait type parameters. for type_parameter in struct_decl.type_parameters.iter() { diff --git a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs index 9a58cd80c64..822d4262156 100644 --- a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs +++ b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs @@ -12,7 +12,7 @@ use crate::{ ty::{TyAstNode, TyAstNodeContent}, Visibility, }, - semantic_analysis::TypeCheckContext, + semantic_analysis::{symbol_collection_context::SymbolCollectionContext, TypeCheckContext}, transform::to_parsed_lang, Engines, Namespace, }; @@ -106,8 +106,12 @@ fn default_with_contract_id_inner( }; let mut root = Root::from(Module::new(ns_name.clone(), Visibility::Public, None)); let mut ns = Namespace::init_root(&mut root); + + let symbol_ctx_ns = Namespace::default(); + let mut symbol_ctx = SymbolCollectionContext::new(symbol_ctx_ns); // This is pretty hacky but that's okay because of this code is being removed pretty soon - let type_check_ctx = TypeCheckContext::from_namespace(&mut ns, engines, experimental); + let type_check_ctx = + TypeCheckContext::from_namespace(&mut ns, &mut symbol_ctx, engines, experimental); let typed_node = TyAstNode::type_check(handler, type_check_ctx, &ast_node).unwrap(); // get the decl out of the typed node: // we know as an invariant this must be a const decl, as we hardcoded a const decl in diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 9230af73984..df65cf9321e 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -7,7 +7,7 @@ use super::{ }; use rustc_hash::FxHasher; -use std::hash::BuildHasherDefault; +use std::{collections::HashMap, hash::BuildHasherDefault}; use sway_error::handler::Handler; use sway_error::{error::CompileError, handler::ErrorEmitted}; use sway_types::{span::Span, Spanned}; @@ -34,6 +34,8 @@ pub struct Module { pub lexical_scopes: Vec, /// Current lexical scope id in the lexical scope hierarchy stack. pub current_lexical_scope_id: LexicalScopeId, + /// Maps between a span and the corresponding lexical scope id. + pub lexical_scopes_spans: HashMap, /// Name of the module, package name for root module, module name for other modules. /// Module name used is the same as declared in `mod name;`. name: Ident, @@ -51,12 +53,19 @@ pub struct Module { pub(crate) mod_path: ModulePathBuf, } +impl Default for Module { + fn default() -> Self { + Self::new(Ident::dummy(), Visibility::Public, None) + } +} + impl Module { pub fn new(name: Ident, visibility: Visibility, span: Option) -> Self { Self { visibility, submodules: Default::default(), lexical_scopes: vec![LexicalScope::default()], + lexical_scopes_spans: Default::default(), current_lexical_scope_id: 0, name, span, @@ -78,6 +87,7 @@ impl Module { visibility, submodules: self.submodules.clone(), lexical_scopes: self.lexical_scopes.clone(), + lexical_scopes_spans: self.lexical_scopes_spans.clone(), current_lexical_scope_id: self.current_lexical_scope_id, name, span, @@ -221,8 +231,13 @@ impl Module { self.current_lexical_scope_id } + /// Enters the scope with the given span in the module's lexical scope hierarchy. + pub fn enter_lexical_scope(&mut self, _span: Span) -> LexicalScopeId { + todo!() + } + /// Pushes a new scope to the module's lexical scope hierarchy. - pub fn push_new_lexical_scope(&mut self) -> LexicalScopeId { + pub fn push_new_lexical_scope(&mut self, span: Span) -> LexicalScopeId { let previous_scope_id = self.current_lexical_scope_id(); let new_scoped_id = { self.lexical_scopes.push(LexicalScope { @@ -234,6 +249,7 @@ impl Module { let previous_scope = self.lexical_scopes.get_mut(previous_scope_id).unwrap(); previous_scope.children.push(new_scoped_id); self.current_lexical_scope_id = new_scoped_id; + self.lexical_scopes_spans.insert(span, new_scoped_id); new_scoped_id } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index a3aed9205c9..47bb53e3138 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -23,7 +23,7 @@ pub enum TryInsertingTraitImplOnFailure { } /// The set of items that represent the namespace context passed throughout type checking. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Namespace { /// An immutable namespace that consists of the names that should always be present, no matter /// what module or scope we are currently checking. @@ -47,6 +47,14 @@ pub struct Namespace { } impl Namespace { + pub fn new() -> Self { + Self { + init: Module::default(), + mod_path: vec![], + root: Root::default(), + } + } + pub fn program_id(&self, engines: &Engines) -> &Module { self.root .module diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index a9da70d1881..fd19ca3e5fa 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -159,7 +159,7 @@ impl ResolvedDeclaration { /// canonical paths, or that use canonical paths internally, are *only* called from the root. This /// normally includes methods that first lookup some canonical path via `use_synonyms` before using /// that canonical path to look up the symbol declaration. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Root { pub(crate) module: Module, } diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index c70a442fc1a..581a630d9b6 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -44,6 +44,7 @@ impl TyProgram { handler: &Handler, engines: &Engines, parsed: &ParseProgram, + collection_ctx: &mut SymbolCollectionContext, mut namespace: namespace::Namespace, package_name: &str, build_config: Option<&BuildConfig>, @@ -55,8 +56,9 @@ impl TyProgram { new_encoding: false, }); - let mut ctx = TypeCheckContext::from_root(&mut namespace, engines, experimental) - .with_kind(parsed.kind); + let mut ctx = + TypeCheckContext::from_root(&mut namespace, collection_ctx, engines, experimental) + .with_kind(parsed.kind); let ParseProgram { root, kind } = parsed; diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index ca8d1c2b961..e7b2b14809d 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -39,13 +39,14 @@ impl SymbolCollectionContext { /// Scope the `CollectionContext` with a new lexical scope. pub fn scoped( &mut self, + span: Span, engines: &Engines, with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> (Result, LexicalScopeId) { let lexical_scope_id: LexicalScopeId = self .namespace .module_mut(engines) - .write(engines, |m| m.push_new_lexical_scope()); + .write(engines, |m| m.push_new_lexical_scope(span.clone())); let ret = with_scoped_ctx(self); self.namespace .module_mut(engines) @@ -53,18 +54,19 @@ impl SymbolCollectionContext { (ret, lexical_scope_id) } - /// Enter the lexical scope and produce a collection context ready for - /// collecting its content. + /// Enter the lexical scope corresponding to the given span and produce a + /// collection context ready for collecting its content. /// /// Returns the result of the given `with_ctx` function. pub fn enter_lexical_scope( &mut self, engines: &Engines, - with_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T, - ) -> T { + span: Span, + with_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, + ) -> Result { self.namespace .module_mut(engines) - .write(engines, |m| m.push_new_lexical_scope()); + .write(engines, |m| m.enter_lexical_scope(span.clone())); let ret = with_ctx(self); self.namespace .module_mut(engines) diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index c2558697fe8..4c127a0f013 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -79,13 +79,14 @@ impl<'a> SymbolResolveContext<'a> { } /// Scope the `SymbolResolveContext` with a new namespace lexical scope. - pub fn scoped( + pub fn enter_lexical_scope( self, + span: Span, with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result, ) -> Result { let engines = self.engines; self.symbol_collection_ctx - .enter_lexical_scope(engines, |sub_scope_collect_ctx| { + .enter_lexical_scope(engines, span, |sub_scope_collect_ctx| { let sub_scope_resolve_ctx = SymbolResolveContext::new(engines, sub_scope_collect_ctx); with_scoped_ctx(sub_scope_resolve_ctx) diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index faf8fa72647..ce7fea269d4 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -27,7 +27,7 @@ use sway_error::{ use sway_types::{span::Span, Ident, Spanned}; use sway_utils::iter_prefixes; -use super::GenericShadowingMode; +use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; /// Contextual state tracked and accumulated throughout type-checking. pub struct TypeCheckContext<'a> { @@ -46,6 +46,9 @@ pub struct TypeCheckContext<'a> { /// Set of experimental flags. pub(crate) experimental: ExperimentalFlags, + /// Keeps the accumulated symbols previously collected. + pub(crate) collection_ctx: &'a mut SymbolCollectionContext, + // The following set of fields are intentionally private. When a `TypeCheckContext` is passed // into a new node during type checking, these fields should be updated using the `with_*` // methods which provides a new `TypeCheckContext`, ensuring we don't leak our changes into @@ -108,12 +111,14 @@ impl<'a> TypeCheckContext<'a> { /// Initialize a type-checking context with a namespace. pub fn from_namespace( namespace: &'a mut Namespace, + collection_ctx: &'a mut SymbolCollectionContext, engines: &'a Engines, experimental: ExperimentalFlags, ) -> Self { Self { namespace, engines, + collection_ctx, type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), unify_generic: false, @@ -141,18 +146,21 @@ impl<'a> TypeCheckContext<'a> { /// - help_text: "" pub fn from_root( root_namespace: &'a mut Namespace, + collection_ctx: &'a mut SymbolCollectionContext, engines: &'a Engines, experimental: ExperimentalFlags, ) -> Self { - Self::from_module_namespace(root_namespace, engines, experimental) + Self::from_module_namespace(root_namespace, collection_ctx, engines, experimental) } fn from_module_namespace( namespace: &'a mut Namespace, + collection_ctx: &'a mut SymbolCollectionContext, engines: &'a Engines, experimental: ExperimentalFlags, ) -> Self { Self { + collection_ctx, namespace, engines, type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), @@ -184,6 +192,7 @@ impl<'a> TypeCheckContext<'a> { pub fn by_ref(&mut self) -> TypeCheckContext<'_> { TypeCheckContext { namespace: self.namespace, + collection_ctx: self.collection_ctx, type_annotation: self.type_annotation, function_type_annotation: self.function_type_annotation, unify_generic: self.unify_generic, @@ -203,60 +212,121 @@ impl<'a> TypeCheckContext<'a> { } } - /// Scope the `TypeCheckContext` with a new namespace. + /// Scope the `TypeCheckContext` with a new namespace, and set up the collection context + /// so it enters the lexical scope corresponding to the given span. pub fn scoped( self, + span: Option, with_scoped_ctx: impl FnOnce(TypeCheckContext) -> Result, ) -> Result { let mut namespace = self.namespace.clone(); - let ctx = TypeCheckContext { - namespace: &mut namespace, - type_annotation: self.type_annotation, - function_type_annotation: self.function_type_annotation, - unify_generic: self.unify_generic, - self_type: self.self_type, - type_subst: self.type_subst, - abi_mode: self.abi_mode, - const_shadowing_mode: self.const_shadowing_mode, - generic_shadowing_mode: self.generic_shadowing_mode, - help_text: self.help_text, - kind: self.kind, - engines: self.engines, - disallow_functions: self.disallow_functions, - storage_declaration: self.storage_declaration, - experimental: self.experimental, - collecting_unifications: self.collecting_unifications, - code_block_first_pass: self.code_block_first_pass, - }; - with_scoped_ctx(ctx) + if let Some(span) = span { + self.collection_ctx + .enter_lexical_scope(self.engines, span, |scoped_collection_ctx| { + let ctx = TypeCheckContext { + namespace: &mut namespace, + collection_ctx: scoped_collection_ctx, + type_annotation: self.type_annotation, + function_type_annotation: self.function_type_annotation, + unify_generic: self.unify_generic, + self_type: self.self_type, + type_subst: self.type_subst, + abi_mode: self.abi_mode, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + help_text: self.help_text, + kind: self.kind, + engines: self.engines, + disallow_functions: self.disallow_functions, + storage_declaration: self.storage_declaration, + experimental: self.experimental, + collecting_unifications: self.collecting_unifications, + code_block_first_pass: self.code_block_first_pass, + }; + with_scoped_ctx(ctx) + }) + } else { + let ctx = TypeCheckContext { + collection_ctx: self.collection_ctx, + namespace: &mut namespace, + type_annotation: self.type_annotation, + function_type_annotation: self.function_type_annotation, + unify_generic: self.unify_generic, + self_type: self.self_type, + type_subst: self.type_subst, + abi_mode: self.abi_mode, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + help_text: self.help_text, + kind: self.kind, + engines: self.engines, + disallow_functions: self.disallow_functions, + storage_declaration: self.storage_declaration, + experimental: self.experimental, + collecting_unifications: self.collecting_unifications, + code_block_first_pass: self.code_block_first_pass, + }; + with_scoped_ctx(ctx) + } } /// Scope the `TypeCheckContext` with a new namespace and returns it in case of success. + /// Also sets up the collection context so it enters the lexical scope corresponding to + /// the given span. pub fn scoped_and_namespace( self, + span: Option, with_scoped_ctx: impl FnOnce(TypeCheckContext) -> Result, ) -> Result<(T, Namespace), ErrorEmitted> { let mut namespace = self.namespace.clone(); - let ctx = TypeCheckContext { - namespace: &mut namespace, - type_annotation: self.type_annotation, - function_type_annotation: self.function_type_annotation, - unify_generic: self.unify_generic, - self_type: self.self_type, - type_subst: self.type_subst, - abi_mode: self.abi_mode, - const_shadowing_mode: self.const_shadowing_mode, - generic_shadowing_mode: self.generic_shadowing_mode, - help_text: self.help_text, - kind: self.kind, - engines: self.engines, - disallow_functions: self.disallow_functions, - storage_declaration: self.storage_declaration, - experimental: self.experimental, - collecting_unifications: self.collecting_unifications, - code_block_first_pass: self.code_block_first_pass, - }; - Ok((with_scoped_ctx(ctx)?, namespace)) + if let Some(span) = span { + self.collection_ctx + .enter_lexical_scope(self.engines, span, |scoped_collection_ctx| { + let ctx = TypeCheckContext { + collection_ctx: scoped_collection_ctx, + namespace: &mut namespace, + type_annotation: self.type_annotation, + function_type_annotation: self.function_type_annotation, + unify_generic: self.unify_generic, + self_type: self.self_type, + type_subst: self.type_subst, + abi_mode: self.abi_mode, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + help_text: self.help_text, + kind: self.kind, + engines: self.engines, + disallow_functions: self.disallow_functions, + storage_declaration: self.storage_declaration, + experimental: self.experimental, + collecting_unifications: self.collecting_unifications, + code_block_first_pass: self.code_block_first_pass, + }; + Ok((with_scoped_ctx(ctx)?, namespace)) + }) + } else { + let ctx = TypeCheckContext { + collection_ctx: self.collection_ctx, + namespace: &mut namespace, + type_annotation: self.type_annotation, + function_type_annotation: self.function_type_annotation, + unify_generic: self.unify_generic, + self_type: self.self_type, + type_subst: self.type_subst, + abi_mode: self.abi_mode, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + help_text: self.help_text, + kind: self.kind, + engines: self.engines, + disallow_functions: self.disallow_functions, + storage_declaration: self.storage_declaration, + experimental: self.experimental, + collecting_unifications: self.collecting_unifications, + code_block_first_pass: self.code_block_first_pass, + }; + Ok((with_scoped_ctx(ctx)?, namespace)) + } } /// Enter the submodule with the given name and produce a type-check context ready for @@ -264,7 +334,7 @@ impl<'a> TypeCheckContext<'a> { /// /// Returns the result of the given `with_submod_ctx` function. pub fn enter_submodule( - mut self, + self, mod_name: Ident, visibility: Visibility, module_span: Span, @@ -275,11 +345,28 @@ impl<'a> TypeCheckContext<'a> { // We're checking a submodule, so no need to pass through anything other than the // namespace and the engines. let engines = self.engines; - let mut submod_ns = - self.namespace_mut() - .enter_submodule(engines, mod_name, visibility, module_span); - let submod_ctx = TypeCheckContext::from_namespace(&mut submod_ns, engines, experimental); - with_submod_ctx(submod_ctx) + let mut submod_ns = self.namespace.enter_submodule( + engines, + mod_name.clone(), + visibility, + module_span.clone(), + ); + + self.collection_ctx.enter_submodule( + engines, + mod_name, + visibility, + module_span, + |submod_collection_ctx| { + let submod_ctx = TypeCheckContext::from_namespace( + &mut submod_ns, + submod_collection_ctx, + engines, + experimental, + ); + with_submod_ctx(submod_ctx) + }, + ) } /// Returns a mutable reference to the current namespace. From b48613ce0fa87a9af8718c1a202a0d5d0e889181 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Sep 2024 19:39:56 +0100 Subject: [PATCH 03/12] Implement scope handling and collection for more decls. --- .../language/parsed/declaration/function.rs | 2 -- .../ast_node/declaration/abi.rs | 24 ++++++++++++++--- .../ast_node/declaration/declaration.rs | 25 +++++++++--------- .../ast_node/declaration/enum.rs | 11 ++++++++ .../ast_node/declaration/function.rs | 14 ++++++++++ .../ast_node/declaration/impl_trait.rs | 26 ++++++++++++++++++- .../ast_node/declaration/struct.rs | 17 ++++++++++++ .../ast_node/declaration/trait.rs | 20 +++++++++++++- .../src/semantic_analysis/namespace/module.rs | 7 +++-- .../symbol_collection_context.rs | 2 +- .../to_parsed_lang/convert_parse_tree.rs | 1 - 11 files changed, 124 insertions(+), 25 deletions(-) diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index afd61ef54d3..716f545ef0e 100644 --- a/sway-core/src/language/parsed/declaration/function.rs +++ b/sway-core/src/language/parsed/declaration/function.rs @@ -1,7 +1,6 @@ use crate::{ engine_threading::*, language::{parsed::*, *}, - namespace::LexicalScopeId, transform::{self, AttributeKind}, type_system::*, }; @@ -29,7 +28,6 @@ pub struct FunctionDeclaration { pub where_clause: Vec<(Ident, Vec)>, pub kind: FunctionDeclarationKind, pub implementing_type: Option, - pub lexical_scope: LexicalScopeId, } impl EqWithEngines for FunctionDeclaration {} diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 780bfc4b3aa..4cddd5b1a7d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -5,13 +5,13 @@ use sway_types::{Ident, Named, Span, Spanned}; use crate::{ decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, DeclEngineInsertArc, DeclId}, - language::ty::TyAbiDecl, + language::ty::{TyAbiDecl, TyFunctionDecl}, namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, semantic_analysis::{ - TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization, - TypeCheckFinalizationContext, + symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis, + TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext, }, - TypeParameter, + Engines, TypeParameter, }; use sway_error::handler::{ErrorEmitted, Handler}; @@ -29,6 +29,22 @@ use crate::{ }; impl ty::TyAbiDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + abi_decl: &AbiDeclaration, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, abi_decl.span.clone(), |scoped_ctx| { + abi_decl.methods.iter().for_each(|m| { + let method_decl = engines.pe().get_function(m).as_ref().clone(); + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); + }); + Ok(()) + }); + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, ctx: TypeCheckContext, 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 a54435f508f..77bbd1000b3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -2,13 +2,13 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Named, Spanned}; use crate::{ - decl_engine::{ - parsed_engine::ParsedDeclEngineReplace, DeclEngineGet, DeclEngineInsert, DeclRef, - ReplaceFunctionImplementingType, - }, + decl_engine::{DeclEngineGet, DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, language::{ parsed::{self, StorageEntry}, - ty::{self, FunctionDecl, TyCodeBlock, TyDecl, TyStorageField}, + ty::{ + self, FunctionDecl, TyAbiDecl, TyDecl, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, + TyStorageField, TyStructDecl, TyTraitDecl, + }, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf, ResolvedDeclaration}, @@ -53,22 +53,18 @@ impl TyDecl { parsed::Declaration::EnumDeclaration(decl_id) => { let enum_decl = engines.pe().get_enum(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, enum_decl.name.clone(), decl)?; + TyEnumDecl::collect(handler, engines, ctx, &enum_decl)? } parsed::Declaration::EnumVariantDeclaration(_decl) => {} parsed::Declaration::FunctionDeclaration(decl_id) => { - let decl_id = *decl_id; - let mut fn_decl = engines.pe().get_function(&decl_id).as_ref().clone(); + let fn_decl = engines.pe().get_function(decl_id).as_ref().clone(); let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl); - let (_ret, lexical_scope_id) = - ctx.scoped(fn_decl.span.clone(), engines, |scoped_ctx| { - TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) - }); - fn_decl.lexical_scope = lexical_scope_id; - engines.pe().replace(decl_id, fn_decl); + TyFunctionDecl::collect(handler, engines, ctx, &fn_decl)? } parsed::Declaration::TraitDeclaration(decl_id) => { let trait_decl = engines.pe().get_trait(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, trait_decl.name.clone(), decl)?; + TyTraitDecl::collect(handler, engines, ctx, &trait_decl)? } parsed::Declaration::ImplSelfOrTrait(decl_id) => { let impl_trait = engines @@ -82,14 +78,17 @@ impl TyDecl { impl_trait.trait_name.suffix.clone(), decl, )?; + TyImplSelfOrTrait::collect(handler, engines, ctx, &impl_trait)? } parsed::Declaration::StructDeclaration(decl_id) => { let struct_decl = engines.pe().get_struct(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, struct_decl.name.clone(), decl)?; + TyStructDecl::collect(handler, engines, ctx, &struct_decl)? } parsed::Declaration::AbiDeclaration(decl_id) => { let abi_decl = engines.pe().get_abi(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, abi_decl.name.clone(), decl)?; + TyAbiDecl::collect(handler, engines, ctx, &abi_decl)? } parsed::Declaration::StorageDeclaration(decl_id) => { let _storage_decl = engines.pe().get_storage(decl_id).as_ref().clone(); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index d57740026dc..66d23613bcc 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -2,10 +2,21 @@ use crate::{ language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, + Engines, }; use sway_error::handler::{ErrorEmitted, Handler}; +use symbol_collection_context::SymbolCollectionContext; impl ty::TyEnumDecl { + pub(crate) fn collect( + _handler: &Handler, + _engines: &Engines, + _ctx: &mut SymbolCollectionContext, + _decl: &EnumDeclaration, + ) -> Result<(), ErrorEmitted> { + Ok(()) + } + pub fn type_check( handler: &Handler, ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 6113ab6ab15..5d06f69dc4d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -5,6 +5,7 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; +use symbol_collection_context::SymbolCollectionContext; use crate::{ decl_engine::{DeclId, DeclRefFunction}, @@ -15,10 +16,23 @@ use crate::{ }, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, + Engines, }; use sway_types::{style::is_snake_case, Spanned}; impl ty::TyFunctionDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + fn_decl: &FunctionDeclaration, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, fn_decl.span.clone(), |scoped_ctx| { + TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) + }); + Ok(()) + } + pub fn type_check( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index a7f5070f729..7f3b68ff175 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -15,11 +15,15 @@ use crate::{ engine_threading::*, language::{ parsed::*, - ty::{self, TyDecl, TyImplItem, TyImplSelfOrTrait, TyTraitInterfaceItem, TyTraitItem}, + ty::{ + self, TyDecl, TyFunctionDecl, TyImplItem, TyImplSelfOrTrait, TyTraitInterfaceItem, + TyTraitItem, + }, *, }, namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, semantic_analysis::{ + symbol_collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments, AbiMode, ConstShadowingMode, TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, @@ -28,6 +32,26 @@ use crate::{ }; impl TyImplSelfOrTrait { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &ImplSelfOrTrait, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, decl.block_span.clone(), |scoped_ctx| { + decl.items.iter().for_each(|item| match item { + ImplItem::Fn(decl_id) => { + let fn_decl = engines.pe().get_function(decl_id).as_ref().clone(); + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &fn_decl); + } + ImplItem::Constant(_) => {} + ImplItem::Type(_) => {} + }); + Ok(()) + }); + Ok(()) + } + pub(crate) fn type_check_impl_trait( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 3cd28a9c0fe..5bc3c4da23a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -2,10 +2,27 @@ use crate::{ language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, + Engines, }; use sway_error::handler::{ErrorEmitted, Handler}; +use symbol_collection_context::SymbolCollectionContext; impl ty::TyStructDecl { + pub(crate) fn collect( + _handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &StructDeclaration, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, decl.span.clone(), |_scoped_ctx| { + decl.fields.iter().for_each(|_field| { + //let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); + }); + Ok(()) + }); + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 38f247fe87c..bcbbda38919 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -11,19 +11,37 @@ use crate::{ decl_engine::*, language::{ parsed::*, - ty::{self, TyImplItem, TyTraitDecl, TyTraitItem}, + ty::{self, TyFunctionDecl, TyImplItem, TyTraitDecl, TyTraitItem}, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ declaration::{insert_supertraits_into_namespace, SupertraitOf}, + symbol_collection_context::SymbolCollectionContext, AbiMode, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, }, type_system::*, + Engines, }; impl TyTraitDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &TraitDeclaration, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, decl.span.clone(), |scoped_ctx| { + decl.methods.iter().for_each(|m| { + let method_decl = engines.pe().get_function(m).as_ref().clone(); + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); + }); + Ok(()) + }); + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index df65cf9321e..7564c7fee1b 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -232,8 +232,11 @@ impl Module { } /// Enters the scope with the given span in the module's lexical scope hierarchy. - pub fn enter_lexical_scope(&mut self, _span: Span) -> LexicalScopeId { - todo!() + pub fn enter_lexical_scope(&mut self, span: Span) -> LexicalScopeId { + let id_opt = self.lexical_scopes_spans.get(&span); + let id = *id_opt.unwrap(); + self.current_lexical_scope_id = id; + id } /// Pushes a new scope to the module's lexical scope hierarchy. diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index e7b2b14809d..f90aa8128fa 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -39,8 +39,8 @@ impl SymbolCollectionContext { /// Scope the `CollectionContext` with a new lexical scope. pub fn scoped( &mut self, - span: Span, engines: &Engines, + span: Span, with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> (Result, LexicalScopeId) { let lexical_scope_id: LexicalScopeId = self diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 642badfeadf..25e0782f21d 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -598,7 +598,6 @@ pub fn item_fn_to_function_declaration( .unwrap_or(vec![]), kind, implementing_type, - lexical_scope: 0, }; let decl_id = engines.pe().insert(fn_decl); Ok(decl_id) From 8f4aa67b6fd9510e0ed91c859f887baaaa1fbe9e Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Sep 2024 16:49:11 +0100 Subject: [PATCH 04/12] Improve error handling when a scope is not found. --- .../semantic_analysis/ast_node/code_block.rs | 49 ++++++++++--------- .../ast_node/declaration/abi.rs | 2 +- .../ast_node/declaration/auto_impl.rs | 4 +- .../ast_node/declaration/enum.rs | 2 +- .../ast_node/declaration/function.rs | 4 +- .../ast_node/declaration/impl_trait.rs | 4 +- .../ast_node/declaration/struct.rs | 2 +- .../ast_node/declaration/trait.rs | 2 +- .../ast_node/declaration/trait_fn.rs | 2 +- .../typed/typed_match_branch.rs | 2 +- .../typed/typed_match_expression.rs | 2 +- .../typed_expression/struct_instantiation.rs | 2 +- .../src/semantic_analysis/namespace/module.rs | 26 ++++++++-- .../symbol_collection_context.rs | 7 +-- .../symbol_resolve_context.rs | 11 +++-- .../semantic_analysis/type_check_context.rs | 22 ++++++--- 16 files changed, 91 insertions(+), 52 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index 7cb40357bca..ed180446825 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -28,17 +28,21 @@ impl ty::TyCodeBlock { is_root: bool, ) -> Result { if !is_root { - let code_block_result = ctx.by_ref().scoped(Some(code_block.span()), |mut ctx| { - let evaluated_contents = code_block - .contents - .iter() - .filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok()) - .collect::>(); - Ok(ty::TyCodeBlock { - contents: evaluated_contents, - whole_block_span: code_block.whole_block_span.clone(), - }) - })?; + let code_block_result = + ctx.by_ref() + .scoped(handler, Some(code_block.span()), |mut ctx| { + let evaluated_contents = code_block + .contents + .iter() + .filter_map(|node| { + ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok() + }) + .collect::>(); + Ok(ty::TyCodeBlock { + contents: evaluated_contents, + whole_block_span: code_block.whole_block_span.clone(), + }) + })?; return Ok(code_block_result); } @@ -57,7 +61,7 @@ impl ty::TyCodeBlock { ctx.by_ref() .with_collecting_unifications() .with_code_block_first_pass(true) - .scoped(Some(code_block.span()), |mut ctx| { + .scoped(handler, Some(code_block.span()), |mut ctx| { code_block.contents.iter().for_each(|node| { ty::TyAstNode::type_check(&Handler::default(), ctx.by_ref(), node).ok(); }); @@ -66,18 +70,19 @@ impl ty::TyCodeBlock { ctx.engines.te().reapply_unifications(ctx.engines()); - ctx.by_ref().scoped(Some(code_block.span()), |mut ctx| { - let evaluated_contents = code_block - .contents - .iter() - .filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok()) - .collect::>(); + ctx.by_ref() + .scoped(handler, Some(code_block.span()), |mut ctx| { + let evaluated_contents = code_block + .contents + .iter() + .filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok()) + .collect::>(); - Ok(ty::TyCodeBlock { - contents: evaluated_contents, - whole_block_span: code_block.whole_block_span.clone(), + Ok(ty::TyCodeBlock { + contents: evaluated_contents, + whole_block_span: code_block.whole_block_span.clone(), + }) }) - }) } pub fn compute_return_type_and_span( diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 4cddd5b1a7d..b3a757e056e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -71,7 +71,7 @@ impl ty::TyAbiDecl { // A temporary namespace for checking within this scope. ctx.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None)) .with_self_type(Some(self_type_id)) - .scoped(Some(span.clone()), |mut ctx| { + .scoped(handler, Some(span.clone()), |mut ctx| { // Insert the "self" type param into the namespace. self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref()); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index a08b76d7912..1ec59406269 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -324,7 +324,7 @@ where assert!(!handler.has_warnings(), "{:?}", handler); let ctx = self.ctx.by_ref(); - let r = ctx.scoped_and_namespace(None, |ctx| { + let r = ctx.scoped_and_namespace(&handler, None, |ctx| { TyDecl::type_check( &handler, ctx, @@ -375,7 +375,7 @@ where assert!(!handler.has_errors(), "{:?}", handler); let ctx = self.ctx.by_ref(); - let r = ctx.scoped_and_namespace(None, |ctx| { + let r = ctx.scoped_and_namespace(&handler, None, |ctx| { TyDecl::type_check(&handler, ctx, Declaration::ImplSelfOrTrait(decl)) }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 66d23613bcc..d1eadfc2fc4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -33,7 +33,7 @@ impl ty::TyEnumDecl { } = decl; // create a namespace for the decl, used to create a scope for generics - ctx.scoped(Some(span.clone()), |mut ctx| { + ctx.scoped(handler, Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 5d06f69dc4d..22c3074ce03 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -99,7 +99,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(None, |mut ctx| { + .scoped(handler, None, |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, @@ -196,7 +196,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(None, |mut ctx| { + .scoped(handler, None, |mut ctx| { let FunctionDeclaration { body, .. } = fn_decl; let ty::TyFunctionDecl { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 7f3b68ff175..8083fe56bee 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -81,7 +81,7 @@ impl TyImplSelfOrTrait { .with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .with_self_type(Some(self_type_id)) .allow_functions() - .scoped(Some(block_span.clone()), |mut ctx| { + .scoped(handler, Some(block_span.clone()), |mut ctx| { // Type check the type parameters let new_impl_type_parameters = TypeParameter::type_check_type_params( handler, @@ -328,7 +328,7 @@ impl TyImplSelfOrTrait { // create the namespace for the impl ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .allow_functions() - .scoped(Some(block_span.clone()), |mut ctx| { + .scoped(handler, Some(block_span.clone()), |mut ctx| { // Create a new type parameter for the "self type". let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span()); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 5bc3c4da23a..4291e567a99 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -39,7 +39,7 @@ impl ty::TyStructDecl { } = decl; // create a namespace for the decl, used to create a scope for generics - ctx.scoped(Some(span.clone()), |mut ctx| { + ctx.scoped(handler, Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index bcbbda38919..7ebe9d6210c 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -74,7 +74,7 @@ impl TyTraitDecl { // A temporary namespace for checking within the trait's scope. ctx.with_self_type(Some(self_type)) - .scoped(Some(span.clone()), |mut ctx| { + .scoped(handler, Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index dbc646217e6..4c10b17ce80 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -31,7 +31,7 @@ impl ty::TyTraitFn { let engines = ctx.engines(); // Create a namespace for the trait function. - ctx.by_ref().scoped(None, |mut ctx| { + ctx.by_ref().scoped(handler, None, |mut ctx| { // TODO: when we add type parameters to trait fns, type check them here // Type check the parameters. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index fb486e6b63f..f8b530e2107 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -128,7 +128,7 @@ impl ty::TyMatchBranch { )?; // create a new namespace for this branch result - ctx.scoped(Some(branch_span.clone()), |mut scoped_ctx| { + ctx.scoped(handler, Some(branch_span.clone()), |mut scoped_ctx| { // for every variable that comes into result block, create a variable declaration, // insert it into the branch namespace, and add it to the block of code statements let mut code_block_contents: Vec = vec![]; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index 7af98dda5cd..bd271a7f638 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -658,7 +658,7 @@ impl ty::TyMatchExpression { }; } let ctx = ctx.by_ref().with_type_annotation(self.return_type_id); - ctx.scoped(Some(branch_span), |mut branch_ctx| { + ctx.scoped(handler, Some(branch_span), |mut branch_ctx| { let result_span = result.span.clone(); let condition = condition .clone() diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 0b1d1211d2a..11b1495bdc4 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -305,7 +305,7 @@ pub(crate) fn struct_instantiation( let instantiation_span = inner_span.clone(); ctx.with_generic_shadowing_mode(GenericShadowingMode::Allow) - .scoped(None, |mut scoped_ctx| { + .scoped(handler, None, |mut scoped_ctx| { // Insert struct type parameter into namespace. // This is required so check_type_parameter_bounds can resolve generic trait type parameters. for type_parameter in struct_decl.type_parameters.iter() { diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 7564c7fee1b..057b189c148 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -232,11 +232,29 @@ impl Module { } /// Enters the scope with the given span in the module's lexical scope hierarchy. - pub fn enter_lexical_scope(&mut self, span: Span) -> LexicalScopeId { + pub fn enter_lexical_scope( + &mut self, + handler: &Handler, + engines: &Engines, + span: Span, + ) -> Result { let id_opt = self.lexical_scopes_spans.get(&span); - let id = *id_opt.unwrap(); - self.current_lexical_scope_id = id; - id + if id_opt.is_none() { + eprintln!("Error: {:?}", engines.help_out(span.clone())); + panic!(); + } + match id_opt { + Some(id) => { + self.current_lexical_scope_id = *id; + Ok(*id) + } + None => { + Err(handler.emit_err(CompileError::Internal( + "Could not find a valid lexical scope for this source location.", + span.clone(), + ))) + } + } } /// Pushes a new scope to the module's lexical scope hierarchy. diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index f90aa8128fa..2a3be6aa35d 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -60,13 +60,14 @@ impl SymbolCollectionContext { /// Returns the result of the given `with_ctx` function. pub fn enter_lexical_scope( &mut self, + handler: &Handler, engines: &Engines, span: Span, with_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> Result { - self.namespace - .module_mut(engines) - .write(engines, |m| m.enter_lexical_scope(span.clone())); + self.namespace.module_mut(engines).write(engines, |m| { + m.enter_lexical_scope(handler, engines, span.clone()) + })?; let ret = with_ctx(self); self.namespace .module_mut(engines) diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 4c127a0f013..0e88ffd543c 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -81,16 +81,21 @@ impl<'a> SymbolResolveContext<'a> { /// Scope the `SymbolResolveContext` with a new namespace lexical scope. pub fn enter_lexical_scope( self, + handler: &Handler, span: Span, with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result, ) -> Result { let engines = self.engines; - self.symbol_collection_ctx - .enter_lexical_scope(engines, span, |sub_scope_collect_ctx| { + self.symbol_collection_ctx.enter_lexical_scope( + handler, + engines, + span, + |sub_scope_collect_ctx| { let sub_scope_resolve_ctx = SymbolResolveContext::new(engines, sub_scope_collect_ctx); with_scoped_ctx(sub_scope_resolve_ctx) - }) + }, + ) } /// Enter the submodule with the given name and a symbol resolve context ready for diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index ce7fea269d4..5aea74634da 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -216,13 +216,17 @@ impl<'a> TypeCheckContext<'a> { /// so it enters the lexical scope corresponding to the given span. pub fn scoped( self, + handler: &Handler, span: Option, with_scoped_ctx: impl FnOnce(TypeCheckContext) -> Result, ) -> Result { let mut namespace = self.namespace.clone(); if let Some(span) = span { - self.collection_ctx - .enter_lexical_scope(self.engines, span, |scoped_collection_ctx| { + self.collection_ctx.enter_lexical_scope( + handler, + self.engines, + span, + |scoped_collection_ctx| { let ctx = TypeCheckContext { namespace: &mut namespace, collection_ctx: scoped_collection_ctx, @@ -244,7 +248,8 @@ impl<'a> TypeCheckContext<'a> { code_block_first_pass: self.code_block_first_pass, }; with_scoped_ctx(ctx) - }) + }, + ) } else { let ctx = TypeCheckContext { collection_ctx: self.collection_ctx, @@ -275,13 +280,17 @@ impl<'a> TypeCheckContext<'a> { /// the given span. pub fn scoped_and_namespace( self, + handler: &Handler, span: Option, with_scoped_ctx: impl FnOnce(TypeCheckContext) -> Result, ) -> Result<(T, Namespace), ErrorEmitted> { let mut namespace = self.namespace.clone(); if let Some(span) = span { - self.collection_ctx - .enter_lexical_scope(self.engines, span, |scoped_collection_ctx| { + self.collection_ctx.enter_lexical_scope( + handler, + self.engines, + span, + |scoped_collection_ctx| { let ctx = TypeCheckContext { collection_ctx: scoped_collection_ctx, namespace: &mut namespace, @@ -303,7 +312,8 @@ impl<'a> TypeCheckContext<'a> { code_block_first_pass: self.code_block_first_pass, }; Ok((with_scoped_ctx(ctx)?, namespace)) - }) + }, + ) } else { let ctx = TypeCheckContext { collection_ctx: self.collection_ctx, From 86c4fc73d37b5488b5fb4d2e17387146dec138f8 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 26 Aug 2024 16:00:36 +0100 Subject: [PATCH 05/12] Implement collection handling for expressions. --- .../ast_node/expression/typed_expression.rs | 126 ++++++++++++++++++ .../src/semantic_analysis/ast_node/mod.rs | 4 +- .../src/semantic_analysis/namespace/module.rs | 10 +- 3 files changed, 133 insertions(+), 7 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 9f3084f1a95..15ee7faccfd 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -49,6 +49,7 @@ use sway_error::{ warning::{CompileWarning, Warning}, }; use sway_types::{integer_bits::IntegerBits, u256::U256, Ident, Named, Span, Spanned}; +use symbol_collection_context::SymbolCollectionContext; #[allow(clippy::too_many_arguments)] impl ty::TyExpression { @@ -138,6 +139,131 @@ impl ty::TyExpression { Ok(exp) } + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + expr: &Expression, + ) -> Result<(), ErrorEmitted> { + match &expr.kind { + ExpressionKind::Error(_, _) => {} + ExpressionKind::Literal(_) => {} + ExpressionKind::AmbiguousPathExpression(expr) => { + let _ = expr.args.iter().for_each(|arg_expr| { + let _ = Self::collect(handler, engines, ctx, arg_expr); + }); + } + ExpressionKind::FunctionApplication(expr) => { + let _ = expr.arguments.iter().for_each(|arg_expr| { + let _ = Self::collect(handler, engines, ctx, arg_expr); + }); + } + ExpressionKind::LazyOperator(expr) => { + Self::collect(handler, engines, ctx, &expr.lhs)?; + Self::collect(handler, engines, ctx, &expr.rhs)?; + } + ExpressionKind::AmbiguousVariableExpression(_) => {} + ExpressionKind::Variable(_) => {} + ExpressionKind::Tuple(exprs) => { + let _ = exprs.iter().for_each(|expr| { + let _ = Self::collect(handler, engines, ctx, expr); + }); + } + ExpressionKind::TupleIndex(expr) => { + Self::collect(handler, engines, ctx, &expr.prefix)?; + } + ExpressionKind::Array(expr) => { + let _ = expr.contents.iter().for_each(|expr| { + let _ = Self::collect(handler, engines, ctx, &expr); + }); + } + ExpressionKind::Struct(expr) => { + let _ = expr.fields.iter().for_each(|field| { + let _ = Self::collect(handler, engines, ctx, &field.value); + }); + } + ExpressionKind::CodeBlock(code_block) => { + TyCodeBlock::collect(handler, engines, ctx, code_block)? + } + ExpressionKind::If(if_expr) => { + Self::collect(handler, engines, ctx, &if_expr.condition)?; + Self::collect(handler, engines, ctx, &if_expr.then)?; + if let Some(r#else) = &if_expr.r#else { + Self::collect(handler, engines, ctx, r#else)? + } + } + ExpressionKind::Match(expr) => { + Self::collect(handler, engines, ctx, &expr.value)?; + let _ = expr.branches.iter().for_each(|branch| { + // create a new namespace for this branch result + let _ = ctx.scoped(engines, branch.span.clone(), |scoped_ctx| { + Self::collect(handler, engines, scoped_ctx, &branch.result) + }); + }); + } + ExpressionKind::Asm(_) => {} + ExpressionKind::MethodApplication(expr) => { + let _ = expr.arguments.iter().for_each(|expr| { + let _ = Self::collect(handler, engines, ctx, expr); + }); + } + ExpressionKind::Subfield(expr) => { + Self::collect(handler, engines, ctx, &expr.prefix)?; + } + ExpressionKind::DelineatedPath(expr) => { + if let Some(expr_args) = &expr.args { + let _ = expr_args.iter().for_each(|arg_expr| { + let _ = Self::collect(handler, engines, ctx, arg_expr); + }); + } + } + ExpressionKind::AbiCast(expr) => { + Self::collect(handler, engines, ctx, &expr.address)?; + } + ExpressionKind::ArrayIndex(expr) => { + Self::collect(handler, engines, ctx, &expr.prefix)?; + Self::collect(handler, engines, ctx, &expr.index)?; + } + ExpressionKind::StorageAccess(_) => {} + ExpressionKind::IntrinsicFunction(expr) => { + let _ = expr.arguments.iter().for_each(|arg_expr| { + let _ = Self::collect(handler, engines, ctx, arg_expr); + }); + } + ExpressionKind::WhileLoop(expr) => { + Self::collect(handler, engines, ctx, &expr.condition)?; + TyCodeBlock::collect(handler, engines, ctx, &expr.body)? + } + ExpressionKind::ForLoop(expr) => { + Self::collect(handler, engines, ctx, &expr.desugared)?; + } + ExpressionKind::Break => {} + ExpressionKind::Continue => {} + ExpressionKind::Reassignment(expr) => { + match &expr.lhs { + ReassignmentTarget::ElementAccess(expr) => { + Self::collect(handler, engines, ctx, expr)?; + } + ReassignmentTarget::Deref(expr) => { + Self::collect(handler, engines, ctx, expr)?; + } + } + Self::collect(handler, engines, ctx, &expr.rhs)?; + } + ExpressionKind::ImplicitReturn(expr) => Self::collect(handler, engines, ctx, &expr)?, + ExpressionKind::Return(expr) => { + Self::collect(handler, engines, ctx, &expr)?; + } + ExpressionKind::Ref(expr) => { + Self::collect(handler, engines, ctx, &expr.value)?; + } + ExpressionKind::Deref(expr) => { + Self::collect(handler, engines, ctx, &expr)?; + } + } + 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 04aab70d407..3a6ea5f2153 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -34,7 +34,9 @@ impl ty::TyAstNode { } AstNodeContent::IncludeStatement(_i) => (), AstNodeContent::Declaration(decl) => ty::TyDecl::collect(handler, engines, ctx, decl)?, - AstNodeContent::Expression(_expr) => (), + AstNodeContent::Expression(expr) => { + ty::TyExpression::collect(handler, engines, ctx, &expr)? + } AstNodeContent::Error(_spans, _err) => (), }; diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 057b189c148..db0d1b970b2 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -248,12 +248,10 @@ impl Module { self.current_lexical_scope_id = *id; Ok(*id) } - None => { - Err(handler.emit_err(CompileError::Internal( - "Could not find a valid lexical scope for this source location.", - span.clone(), - ))) - } + None => Err(handler.emit_err(CompileError::Internal( + "Could not find a valid lexical scope for this source location.", + span.clone(), + ))), } } From 620fb940bb65b8d29cb8b125a257d0944d416549 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 26 Aug 2024 16:05:39 +0100 Subject: [PATCH 06/12] Implement namespaces collection for all the declarations. --- .../semantic_analysis/ast_node/code_block.rs | 16 ++-- .../ast_node/declaration/enum.rs | 8 +- .../ast_node/declaration/function.rs | 5 +- .../ast_node/declaration/struct.rs | 1 + .../ast_node/declaration/trait.rs | 13 +++- .../ast_node/declaration/trait_fn.rs | 23 +++++- .../ast_node/expression/typed_expression.rs | 78 +++++++++++-------- 7 files changed, 95 insertions(+), 49 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index ed180446825..330b8e4e4e9 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -11,13 +11,15 @@ impl ty::TyCodeBlock { ctx: &mut SymbolCollectionContext, code_block: &CodeBlock, ) -> Result<(), ErrorEmitted> { - let _ = code_block - .contents - .iter() - .map(|node| ty::TyAstNode::collect(handler, engines, ctx, node)) - .filter_map(|res| res.ok()) - .collect::>(); - + let _ = ctx.scoped(engines, code_block.whole_block_span.clone(), |scoped_ctx| { + let _ = code_block + .contents + .iter() + .map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node)) + .filter_map(|res| res.ok()) + .collect::>(); + Ok(()) + }); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index d1eadfc2fc4..765cd669071 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -10,10 +10,12 @@ use symbol_collection_context::SymbolCollectionContext; impl ty::TyEnumDecl { pub(crate) fn collect( _handler: &Handler, - _engines: &Engines, - _ctx: &mut SymbolCollectionContext, - _decl: &EnumDeclaration, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &EnumDeclaration, ) -> Result<(), ErrorEmitted> { + // create a namespace for the decl, used to create a scope for generics + let _ = ctx.scoped(engines, decl.span.clone(), |mut _ctx| Ok(())); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 22c3074ce03..52c7b0057e4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -27,6 +27,7 @@ impl ty::TyFunctionDecl { ctx: &mut SymbolCollectionContext, fn_decl: &FunctionDeclaration, ) -> Result<(), ErrorEmitted> { + // create a namespace for the function let _ = ctx.scoped(engines, fn_decl.span.clone(), |scoped_ctx| { TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) }); @@ -99,7 +100,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(handler, None, |mut ctx| { + .scoped(handler, Some(span.clone()), |mut ctx| { // Type check the type parameters. let new_type_parameters = TypeParameter::type_check_type_params( handler, @@ -196,7 +197,7 @@ impl ty::TyFunctionDecl { ctx.by_ref() .with_const_shadowing_mode(ConstShadowingMode::Sequential) .disallow_functions() - .scoped(handler, None, |mut ctx| { + .scoped(handler, Some(fn_decl.span.clone()), |mut ctx| { let FunctionDeclaration { body, .. } = fn_decl; let ty::TyFunctionDecl { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 4291e567a99..1da30398105 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -14,6 +14,7 @@ impl ty::TyStructDecl { ctx: &mut SymbolCollectionContext, decl: &StructDeclaration, ) -> Result<(), ErrorEmitted> { + // create a namespace for the decl, used to create a scope for generics let _ = ctx.scoped(engines, decl.span.clone(), |_scoped_ctx| { decl.fields.iter().for_each(|_field| { //let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 7ebe9d6210c..9981627f295 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -11,7 +11,7 @@ use crate::{ decl_engine::*, language::{ parsed::*, - ty::{self, TyFunctionDecl, TyImplItem, TyTraitDecl, TyTraitItem}, + ty::{self, TyFunctionDecl, TyImplItem, TyTraitDecl, TyTraitFn, TyTraitItem}, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf}, @@ -32,7 +32,18 @@ impl TyTraitDecl { ctx: &mut SymbolCollectionContext, decl: &TraitDeclaration, ) -> Result<(), ErrorEmitted> { + // A temporary namespace for checking within the trait's scope. let _ = ctx.scoped(engines, decl.span.clone(), |scoped_ctx| { + decl.interface_surface.iter().for_each(|item| match item { + TraitItem::TraitFn(decl_id) => { + let trait_fn = engines.pe().get_trait_fn(decl_id).as_ref().clone(); + let _ = TyTraitFn::collect(handler, engines, scoped_ctx, &trait_fn); + } + TraitItem::Constant(_) => todo!(), + TraitItem::Type(_) => {} + TraitItem::Error(_, _) => todo!(), + }); + decl.methods.iter().for_each(|m| { let method_decl = engines.pe().get_function(m).as_ref().clone(); let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 4c10b17ce80..15ad27c4823 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -2,8 +2,15 @@ use sway_types::Spanned; use crate::{ decl_engine::DeclId, - language::{parsed, ty, CallPath, Visibility}, - semantic_analysis::type_check_context::EnforceTypeArguments, + language::{ + parsed::{self, TraitFn}, + ty, CallPath, Visibility, + }, + semantic_analysis::{ + symbol_collection_context::SymbolCollectionContext, + type_check_context::EnforceTypeArguments, + }, + Engines, }; use sway_error::handler::{ErrorEmitted, Handler}; @@ -13,6 +20,16 @@ use crate::{ }; impl ty::TyTraitFn { + pub(crate) fn collect( + _handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &TraitFn, + ) -> Result<(), ErrorEmitted> { + let _ = ctx.scoped(engines, decl.span.clone(), |_scoped_ctx| Ok(())); + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, mut ctx: TypeCheckContext, @@ -31,7 +48,7 @@ impl ty::TyTraitFn { let engines = ctx.engines(); // Create a namespace for the trait function. - ctx.by_ref().scoped(handler, None, |mut ctx| { + ctx.by_ref().scoped(handler, Some(span.clone()), |mut ctx| { // TODO: when we add type parameters to trait fns, type check them here // Type check the parameters. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 15ee7faccfd..f02e51b9987 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -149,14 +149,16 @@ impl ty::TyExpression { ExpressionKind::Error(_, _) => {} ExpressionKind::Literal(_) => {} ExpressionKind::AmbiguousPathExpression(expr) => { - let _ = expr.args.iter().for_each(|arg_expr| { - let _ = Self::collect(handler, engines, ctx, arg_expr); - }); + expr.args + .iter() + .map(|arg_expr| Self::collect(handler, engines, ctx, arg_expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::FunctionApplication(expr) => { - let _ = expr.arguments.iter().for_each(|arg_expr| { - let _ = Self::collect(handler, engines, ctx, arg_expr); - }); + expr.arguments + .iter() + .map(|arg_expr| Self::collect(handler, engines, ctx, arg_expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::LazyOperator(expr) => { Self::collect(handler, engines, ctx, &expr.lhs)?; @@ -165,22 +167,25 @@ impl ty::TyExpression { ExpressionKind::AmbiguousVariableExpression(_) => {} ExpressionKind::Variable(_) => {} ExpressionKind::Tuple(exprs) => { - let _ = exprs.iter().for_each(|expr| { - let _ = Self::collect(handler, engines, ctx, expr); - }); + exprs + .iter() + .map(|expr| Self::collect(handler, engines, ctx, expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::TupleIndex(expr) => { Self::collect(handler, engines, ctx, &expr.prefix)?; } ExpressionKind::Array(expr) => { - let _ = expr.contents.iter().for_each(|expr| { - let _ = Self::collect(handler, engines, ctx, &expr); - }); + expr.contents + .iter() + .map(|expr| Self::collect(handler, engines, ctx, expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::Struct(expr) => { - let _ = expr.fields.iter().for_each(|field| { - let _ = Self::collect(handler, engines, ctx, &field.value); - }); + expr.fields + .iter() + .map(|field| Self::collect(handler, engines, ctx, &field.value)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::CodeBlock(code_block) => { TyCodeBlock::collect(handler, engines, ctx, code_block)? @@ -194,27 +199,33 @@ impl ty::TyExpression { } ExpressionKind::Match(expr) => { Self::collect(handler, engines, ctx, &expr.value)?; - let _ = expr.branches.iter().for_each(|branch| { - // create a new namespace for this branch result - let _ = ctx.scoped(engines, branch.span.clone(), |scoped_ctx| { - Self::collect(handler, engines, scoped_ctx, &branch.result) - }); - }); + expr.branches + .iter() + .map(|branch| { + // create a new namespace for this branch result + ctx.scoped(engines, branch.span.clone(), |scoped_ctx| { + Self::collect(handler, engines, scoped_ctx, &branch.result) + }) + .0 + }) + .collect::, ErrorEmitted>>()?; } ExpressionKind::Asm(_) => {} ExpressionKind::MethodApplication(expr) => { - let _ = expr.arguments.iter().for_each(|expr| { - let _ = Self::collect(handler, engines, ctx, expr); - }); + expr.arguments + .iter() + .map(|expr| Self::collect(handler, engines, ctx, expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::Subfield(expr) => { Self::collect(handler, engines, ctx, &expr.prefix)?; } ExpressionKind::DelineatedPath(expr) => { if let Some(expr_args) = &expr.args { - let _ = expr_args.iter().for_each(|arg_expr| { - let _ = Self::collect(handler, engines, ctx, arg_expr); - }); + expr_args + .iter() + .map(|arg_expr| Self::collect(handler, engines, ctx, arg_expr)) + .collect::, ErrorEmitted>>()?; } } ExpressionKind::AbiCast(expr) => { @@ -226,9 +237,10 @@ impl ty::TyExpression { } ExpressionKind::StorageAccess(_) => {} ExpressionKind::IntrinsicFunction(expr) => { - let _ = expr.arguments.iter().for_each(|arg_expr| { - let _ = Self::collect(handler, engines, ctx, arg_expr); - }); + expr.arguments + .iter() + .map(|arg_expr| Self::collect(handler, engines, ctx, arg_expr)) + .collect::, ErrorEmitted>>()?; } ExpressionKind::WhileLoop(expr) => { Self::collect(handler, engines, ctx, &expr.condition)?; @@ -250,15 +262,15 @@ impl ty::TyExpression { } Self::collect(handler, engines, ctx, &expr.rhs)?; } - ExpressionKind::ImplicitReturn(expr) => Self::collect(handler, engines, ctx, &expr)?, + ExpressionKind::ImplicitReturn(expr) => Self::collect(handler, engines, ctx, expr)?, ExpressionKind::Return(expr) => { - Self::collect(handler, engines, ctx, &expr)?; + Self::collect(handler, engines, ctx, expr)?; } ExpressionKind::Ref(expr) => { Self::collect(handler, engines, ctx, &expr.value)?; } ExpressionKind::Deref(expr) => { - Self::collect(handler, engines, ctx, &expr)?; + Self::collect(handler, engines, ctx, expr)?; } } Ok(()) From 8f17afe3239db09b2343ef48a310b3428e38ced9 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Sep 2024 16:55:50 +0100 Subject: [PATCH 07/12] Extract `VariableDeclaration` type checking code into its own file. --- .../src/language/ty/declaration/variable.rs | 40 ++---- .../ast_node/declaration/declaration.rs | 96 ++------------ .../ast_node/declaration/mod.rs | 1 + .../ast_node/declaration/variable.rs | 120 ++++++++++++++++++ 4 files changed, 145 insertions(+), 112 deletions(-) create mode 100644 sway-core/src/semantic_analysis/ast_node/declaration/variable.rs diff --git a/sway-core/src/language/ty/declaration/variable.rs b/sway-core/src/language/ty/declaration/variable.rs index 4b6663f8ba0..e19a4fb30a8 100644 --- a/sway-core/src/language/ty/declaration/variable.rs +++ b/sway-core/src/language/ty/declaration/variable.rs @@ -1,15 +1,10 @@ use std::hash::{Hash, Hasher}; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::Ident; +use sway_types::{Ident, Named, Spanned}; use crate::{ engine_threading::*, language::{parsed::VariableDeclaration, ty::*}, - semantic_analysis::{ - TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization, - TypeCheckFinalizationContext, - }, type_system::*, }; @@ -26,6 +21,18 @@ impl TyDeclParsedType for TyVariableDecl { type ParsedType = VariableDeclaration; } +impl Named for TyVariableDecl { + fn name(&self) -> &sway_types::BaseIdent { + &self.name + } +} + +impl Spanned for TyVariableDecl { + fn span(&self) -> sway_types::Span { + self.name.span() + } +} + impl EqWithEngines for TyVariableDecl {} impl PartialEqWithEngines for TyVariableDecl { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { @@ -65,24 +72,3 @@ impl SubstTypes for TyVariableDecl { self.body.subst(type_mapping, ctx) } } - -impl TypeCheckAnalysis for TyVariableDecl { - fn type_check_analyze( - &self, - handler: &Handler, - ctx: &mut TypeCheckAnalysisContext, - ) -> Result<(), ErrorEmitted> { - self.body.type_check_analyze(handler, ctx)?; - Ok(()) - } -} - -impl TypeCheckFinalization for TyVariableDecl { - fn type_check_finalize( - &mut self, - handler: &Handler, - ctx: &mut TypeCheckFinalizationContext, - ) -> Result<(), ErrorEmitted> { - self.body.type_check_finalize(handler, ctx) - } -} 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 77bbd1000b3..3608a672fbe 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -11,7 +11,7 @@ use crate::{ }, CallPath, }, - namespace::{IsExtendingExistingImpl, IsImplSelf, ResolvedDeclaration}, + namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ symbol_collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments, ConstShadowingMode, GenericShadowingMode, @@ -114,89 +114,15 @@ impl TyDecl { let decl = match decl { parsed::Declaration::VariableDeclaration(decl_id) => { - let var_decl = engines.pe().get_variable(&decl_id); - let mut type_ascription = var_decl.type_ascription.clone(); - - type_ascription.type_id = ctx - .resolve_type( - handler, - type_ascription.type_id, - &type_ascription.span, - EnforceTypeArguments::Yes, - None, - ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); - let mut ctx = ctx - .with_type_annotation(type_ascription.type_id) - .with_help_text( - "Variable declaration's type annotation does not match up \ - with the assigned expression's type.", - ); - let result = ty::TyExpression::type_check(handler, ctx.by_ref(), &var_decl.body); - let body = result.unwrap_or_else(|err| { - ty::TyExpression::error(err, var_decl.name.span(), engines) - }); - - // TODO: Integers shouldn't be anything special. RHS expressions should be written in - // a way to always use the context provided from the LHS, and if the LHS is - // an integer, RHS should properly unify or type check should fail. - // Remove this special case as a part of the initiative of improving type inference. - // Integers are special in the sense that we can't only rely on the type of `body` - // to get the type of the variable. The type of the variable *has* to follow - // `type_ascription` if `type_ascription` is a concrete integer type that does not - // conflict with the type of `body` (i.e. passes the type checking above). - let return_type = match &*type_engine.get(type_ascription.type_id) { - TypeInfo::UnsignedInteger(_) => type_ascription.type_id, - _ => match &*type_engine.get(body.return_type) { - // If RHS type check ends up in an error we want to use the - // provided type ascription as the variable type. E.g.: - // let v: Struct = Struct { x: 0 }; // `v` should be "Struct". - // let v: ExistingType = non_existing_identifier; // `v` should be "ExistingType". - // let v = ; // `v` will remain "{unknown}". - // TODO: Refine and improve this further. E.g., - // let v: Struct { /* MISSING FIELDS */ }; // Despite the error, `v` should be of type "Struct". - TypeInfo::ErrorRecovery(_) => type_ascription.type_id, - _ => body.return_type, - }, + let decl = engines.pe().get_variable(&decl_id).as_ref().clone(); + let name = decl.name.clone(); + let span = decl.name.span(); + let var_decl = match ty::TyVariableDecl::type_check(handler, ctx.by_ref(), decl) { + Ok(res) => res, + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; - - if !ctx.code_block_first_pass() { - let previous_symbol = ctx - .namespace() - .module(engines) - .current_items() - .check_symbols_unique_while_collecting_unifications(&var_decl.name.clone()) - .ok(); - - if let Some(ResolvedDeclaration::Typed(ty::TyDecl::VariableDecl( - variable_decl, - ))) = previous_symbol - { - type_engine.unify( - handler, - engines, - body.return_type, - variable_decl.body.return_type, - &decl.span(engines), - "", - None, - ); - } - } - - let typed_var_decl = ty::TyDecl::VariableDecl(Box::new(ty::TyVariableDecl { - name: var_decl.name.clone(), - body, - mutability: ty::VariableMutability::new_from_ref_mut( - false, - var_decl.is_mutable, - ), - return_type, - type_ascription, - })); - ctx.insert_symbol(handler, var_decl.name.clone(), typed_var_decl.clone())?; + let typed_var_decl = ty::TyDecl::VariableDecl(Box::new(var_decl)); + ctx.insert_symbol(handler, name, typed_var_decl.clone())?; typed_var_decl } parsed::Declaration::ConstantDeclaration(decl_id) => { @@ -665,8 +591,8 @@ impl TypeCheckAnalysis for TyDecl { ctx: &mut TypeCheckAnalysisContext, ) -> Result<(), ErrorEmitted> { match self { - TyDecl::VariableDecl(node) => { - node.type_check_analyze(handler, ctx)?; + TyDecl::VariableDecl(var_decl) => { + var_decl.type_check_analyze(handler, ctx)?; } TyDecl::ConstantDecl(node) => { let const_decl = ctx.engines.de().get_constant(&node.decl_id); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs b/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs index 525055e892e..ba84c359614 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs @@ -14,5 +14,6 @@ mod r#trait; mod trait_fn; mod trait_type; mod type_alias; +mod variable; pub(crate) use supertrait::*; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs new file mode 100644 index 00000000000..e99700ba79c --- /dev/null +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -0,0 +1,120 @@ +use crate::{ + language::{ + parsed::*, + ty::{self, TyVariableDecl}, + }, + namespace::ResolvedDeclaration, + semantic_analysis::{type_check_context::EnforceTypeArguments, *}, + type_system::*, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Spanned; + +impl ty::TyVariableDecl { + pub fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + var_decl: VariableDeclaration, + ) -> Result { + let engines = &ctx.engines(); + let type_engine = engines.te(); + + let mut type_ascription = var_decl.type_ascription.clone(); + + type_ascription.type_id = ctx + .resolve_type( + handler, + type_ascription.type_id, + &type_ascription.span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + let mut ctx = ctx + .with_type_annotation(type_ascription.type_id) + .with_help_text( + "Variable declaration's type annotation does not match up \ + with the assigned expression's type.", + ); + let result = ty::TyExpression::type_check(handler, ctx.by_ref(), &var_decl.body); + let body = result + .unwrap_or_else(|err| ty::TyExpression::error(err, var_decl.name.span(), engines)); + + // TODO: Integers shouldn't be anything special. RHS expressions should be written in + // a way to always use the context provided from the LHS, and if the LHS is + // an integer, RHS should properly unify or type check should fail. + // Remove this special case as a part of the initiative of improving type inference. + // Integers are special in the sense that we can't only rely on the type of `body` + // to get the type of the variable. The type of the variable *has* to follow + // `type_ascription` if `type_ascription` is a concrete integer type that does not + // conflict with the type of `body` (i.e. passes the type checking above). + let return_type = match &*type_engine.get(type_ascription.type_id) { + TypeInfo::UnsignedInteger(_) => type_ascription.type_id, + _ => match &*type_engine.get(body.return_type) { + // If RHS type check ends up in an error we want to use the + // provided type ascription as the variable type. E.g.: + // let v: Struct = Struct { x: 0 }; // `v` should be "Struct". + // let v: ExistingType = non_existing_identifier; // `v` should be "ExistingType". + // let v = ; // `v` will remain "{unknown}". + // TODO: Refine and improve this further. E.g., + // let v: Struct { /* MISSING FIELDS */ }; // Despite the error, `v` should be of type "Struct". + TypeInfo::ErrorRecovery(_) => type_ascription.type_id, + _ => body.return_type, + }, + }; + + if !ctx.code_block_first_pass() { + let previous_symbol = ctx + .namespace() + .module(engines) + .current_items() + .check_symbols_unique_while_collecting_unifications(&var_decl.name.clone()) + .ok(); + + if let Some(ResolvedDeclaration::Typed(ty::TyDecl::VariableDecl(variable_decl))) = + previous_symbol + { + type_engine.unify( + handler, + engines, + body.return_type, + variable_decl.body.return_type, + &variable_decl.span(), + "", + None, + ); + } + } + + let typed_var_decl = ty::TyVariableDecl { + name: var_decl.name.clone(), + body, + mutability: ty::VariableMutability::new_from_ref_mut(false, var_decl.is_mutable), + return_type, + type_ascription, + }; + + Ok(typed_var_decl) + } +} + +impl TypeCheckAnalysis for TyVariableDecl { + fn type_check_analyze( + &self, + handler: &Handler, + ctx: &mut TypeCheckAnalysisContext, + ) -> Result<(), ErrorEmitted> { + self.body.type_check_analyze(handler, ctx)?; + Ok(()) + } +} + +impl TypeCheckFinalization for TyVariableDecl { + fn type_check_finalize( + &mut self, + handler: &Handler, + ctx: &mut TypeCheckFinalizationContext, + ) -> Result<(), ErrorEmitted> { + self.body.type_check_finalize(handler, ctx) + } +} From 8f67021224cf82cd4ac98e2f01e8d4717807d505 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 28 Aug 2024 12:23:30 +0100 Subject: [PATCH 08/12] Implement symbol collection for variable decls. --- .../ast_node/declaration/declaration.rs | 3 ++- .../ast_node/declaration/variable.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) 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 3608a672fbe..e07baab22c5 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -7,7 +7,7 @@ use crate::{ parsed::{self, StorageEntry}, ty::{ self, FunctionDecl, TyAbiDecl, TyDecl, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, - TyStorageField, TyStructDecl, TyTraitDecl, + TyStorageField, TyStructDecl, TyTraitDecl, TyVariableDecl, }, CallPath, }, @@ -33,6 +33,7 @@ impl TyDecl { parsed::Declaration::VariableDeclaration(decl_id) => { let var_decl = engines.pe().get_variable(decl_id); ctx.insert_parsed_symbol(handler, engines, var_decl.name.clone(), decl)?; + TyVariableDecl::collect(handler, engines, ctx, &var_decl)? } parsed::Declaration::ConstantDeclaration(decl_id) => { let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs index e99700ba79c..aeca035b8c8 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -1,16 +1,27 @@ use crate::{ language::{ parsed::*, - ty::{self, TyVariableDecl}, + ty::{self, TyExpression, TyVariableDecl}, }, namespace::ResolvedDeclaration, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, + Engines, }; use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Spanned; +use symbol_collection_context::SymbolCollectionContext; impl ty::TyVariableDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl: &VariableDeclaration, + ) -> Result<(), ErrorEmitted> { + TyExpression::collect(handler, engines, ctx, &decl.body) + } + pub fn type_check( handler: &Handler, mut ctx: TypeCheckContext, From fca8153d3368f86e5784077269c7f533009ce40c Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 28 Aug 2024 12:24:05 +0100 Subject: [PATCH 09/12] Implement collection for auto impl code. --- .../ast_node/declaration/auto_impl.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 1ec59406269..55ef6a25e79 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -323,6 +323,17 @@ where } assert!(!handler.has_warnings(), "{:?}", handler); + let ctx = self.ctx.by_ref(); + let _r = TyDecl::collect( + &handler, + engines, + ctx.collection_ctx, + Declaration::FunctionDeclaration(decl), + ); + if handler.has_errors() { + return Err(handler); + } + let ctx = self.ctx.by_ref(); let r = ctx.scoped_and_namespace(&handler, None, |ctx| { TyDecl::type_check( @@ -375,6 +386,16 @@ where assert!(!handler.has_errors(), "{:?}", handler); let ctx = self.ctx.by_ref(); + let _r = TyDecl::collect( + &handler, + engines, + ctx.collection_ctx, + Declaration::ImplSelfOrTrait(decl), + ); + if handler.has_errors() { + return Err(handler); + } + let r = ctx.scoped_and_namespace(&handler, None, |ctx| { TyDecl::type_check(&handler, ctx, Declaration::ImplSelfOrTrait(decl)) }); From 571957985c1def9693f323cad83993a89f5bb360 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 28 Aug 2024 12:26:49 +0100 Subject: [PATCH 10/12] Remove development-specific error handling code. --- sway-core/src/semantic_analysis/namespace/module.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index db0d1b970b2..b7e01925767 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -239,10 +239,6 @@ impl Module { span: Span, ) -> Result { let id_opt = self.lexical_scopes_spans.get(&span); - if id_opt.is_none() { - eprintln!("Error: {:?}", engines.help_out(span.clone())); - panic!(); - } match id_opt { Some(id) => { self.current_lexical_scope_id = *id; From 5101f1654cfe891c6ea2a5890f5d755600852bdd Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Sep 2024 19:53:18 +0100 Subject: [PATCH 11/12] More thorough declaration collection handling. --- .../ast_node/declaration/abi.rs | 24 ++++++-- .../ast_node/declaration/configurable.rs | 29 ++++++++- .../ast_node/declaration/constant.rs | 23 ++++++- .../ast_node/declaration/declaration.rs | 60 +++++-------------- .../ast_node/declaration/enum.rs | 15 ++++- .../ast_node/declaration/function.rs | 12 +++- .../ast_node/declaration/impl_trait.rs | 29 ++++++--- .../ast_node/declaration/storage.rs | 19 +++++- .../ast_node/declaration/struct.rs | 20 ++++--- .../ast_node/declaration/trait.rs | 49 ++++++++++----- .../ast_node/declaration/trait_fn.rs | 17 ++++-- .../ast_node/declaration/trait_type.rs | 19 +++++- .../ast_node/declaration/type_alias.rs | 29 ++++++++- .../ast_node/declaration/variable.rs | 12 +++- .../src/semantic_analysis/namespace/module.rs | 2 +- 15 files changed, 256 insertions(+), 103 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index b3a757e056e..bb0bc9e2fb8 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -4,7 +4,10 @@ use sway_error::error::CompileError; use sway_types::{Ident, Named, Span, Spanned}; use crate::{ - decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, DeclEngineInsertArc, DeclId}, + decl_engine::{ + parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclEngineInsertArc, + DeclId, + }, language::ty::{TyAbiDecl, TyFunctionDecl}, namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, semantic_analysis::{ @@ -33,12 +36,23 @@ impl ty::TyAbiDecl { handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - abi_decl: &AbiDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { + let abi_decl = engines.pe().get_abi(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + abi_decl.name.clone(), + Declaration::AbiDeclaration(*decl_id), + )?; + let _ = ctx.scoped(engines, abi_decl.span.clone(), |scoped_ctx| { - abi_decl.methods.iter().for_each(|m| { - let method_decl = engines.pe().get_function(m).as_ref().clone(); - let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); + abi_decl.interface_surface.iter().for_each(|item| { + let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); + }); + + abi_decl.methods.iter().for_each(|decl_id| { + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); }); Ok(()) }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs index 7619d1d2f02..3702214d9dd 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs @@ -6,19 +6,42 @@ use sway_error::{ warning::{CompileWarning, Warning}, }; use sway_types::{style::is_screaming_snake_case, Spanned}; +use symbol_collection_context::SymbolCollectionContext; use crate::{ - decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, ReplaceDecls}, + decl_engine::{ + parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, ReplaceDecls, + }, language::{ parsed::*, - ty::{self, TyConfigurableDecl}, + ty::{self, TyConfigurableDecl, TyExpression}, CallPath, }, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, - SubstTypes, SubstTypesContext, TypeArgument, TypeBinding, TypeCheckTypeBinding, TypeInfo, + Engines, SubstTypes, SubstTypesContext, TypeArgument, TypeBinding, TypeCheckTypeBinding, + TypeInfo, }; impl ty::TyConfigurableDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + let configurable_decl = engines.pe().get_configurable(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + configurable_decl.name.clone(), + Declaration::ConfigurableDeclaration(*decl_id), + )?; + if let Some(value) = &configurable_decl.value { + TyExpression::collect(handler, engines, ctx, value)?; + } + Ok(()) + } + pub fn type_check( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs index 4a9f903b282..63ad0a9bbb7 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -3,11 +3,13 @@ use sway_error::{ warning::{CompileWarning, Warning}, }; use sway_types::{style::is_screaming_snake_case, Spanned}; +use symbol_collection_context::SymbolCollectionContext; use crate::{ + decl_engine::parsed_id::ParsedDeclId, language::{ parsed::{self, *}, - ty::{self, TyConstantDecl}, + ty::{self, TyConstantDecl, TyExpression}, CallPath, }, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, @@ -15,6 +17,25 @@ use crate::{ }; impl ty::TyConstantDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + let constant_decl = engines.pe().get_constant(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + constant_decl.name.clone(), + Declaration::ConstantDeclaration(*decl_id), + )?; + if let Some(value) = &constant_decl.value { + TyExpression::collect(handler, engines, ctx, value)?; + } + Ok(()) + } + pub fn type_check( handler: &Handler, mut ctx: TypeCheckContext, 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 e07baab22c5..34f48f85491 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -6,8 +6,9 @@ use crate::{ language::{ parsed::{self, StorageEntry}, ty::{ - self, FunctionDecl, TyAbiDecl, TyDecl, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, - TyStorageField, TyStructDecl, TyTraitDecl, TyVariableDecl, + self, FunctionDecl, TyAbiDecl, TyConfigurableDecl, TyConstantDecl, TyDecl, TyEnumDecl, + TyFunctionDecl, TyImplSelfOrTrait, TyStorageDecl, TyStorageField, TyStructDecl, + TyTraitDecl, TyTraitFn, TyTraitType, TyTypeAliasDecl, TyVariableDecl, }, CallPath, }, @@ -31,73 +32,44 @@ impl TyDecl { ) -> Result<(), ErrorEmitted> { match &decl { parsed::Declaration::VariableDeclaration(decl_id) => { - let var_decl = engines.pe().get_variable(decl_id); - ctx.insert_parsed_symbol(handler, engines, var_decl.name.clone(), decl)?; - TyVariableDecl::collect(handler, engines, ctx, &var_decl)? + TyVariableDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::ConstantDeclaration(decl_id) => { - let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, const_decl.name.clone(), decl)?; + TyConstantDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::ConfigurableDeclaration(decl_id) => { - let config_decl = engines.pe().get_configurable(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, config_decl.name.clone(), decl)?; + TyConfigurableDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::TraitTypeDeclaration(decl_id) => { - let trait_type_decl = engines.pe().get_trait_type(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, trait_type_decl.name.clone(), decl)?; + TyTraitType::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::TraitFnDeclaration(decl_id) => { - let trait_fn_decl = engines.pe().get_trait_fn(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, trait_fn_decl.name.clone(), decl)?; + TyTraitFn::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::EnumDeclaration(decl_id) => { - let enum_decl = engines.pe().get_enum(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, enum_decl.name.clone(), decl)?; - TyEnumDecl::collect(handler, engines, ctx, &enum_decl)? + TyEnumDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::EnumVariantDeclaration(_decl) => {} parsed::Declaration::FunctionDeclaration(decl_id) => { - let fn_decl = engines.pe().get_function(decl_id).as_ref().clone(); - let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl); - TyFunctionDecl::collect(handler, engines, ctx, &fn_decl)? + TyFunctionDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::TraitDeclaration(decl_id) => { - let trait_decl = engines.pe().get_trait(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, trait_decl.name.clone(), decl)?; - TyTraitDecl::collect(handler, engines, ctx, &trait_decl)? + TyTraitDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::ImplSelfOrTrait(decl_id) => { - let impl_trait = engines - .pe() - .get_impl_self_or_trait(decl_id) - .as_ref() - .clone(); - ctx.insert_parsed_symbol( - handler, - engines, - impl_trait.trait_name.suffix.clone(), - decl, - )?; - TyImplSelfOrTrait::collect(handler, engines, ctx, &impl_trait)? + TyImplSelfOrTrait::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::StructDeclaration(decl_id) => { - let struct_decl = engines.pe().get_struct(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, struct_decl.name.clone(), decl)?; - TyStructDecl::collect(handler, engines, ctx, &struct_decl)? + TyStructDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::AbiDeclaration(decl_id) => { - let abi_decl = engines.pe().get_abi(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, abi_decl.name.clone(), decl)?; - TyAbiDecl::collect(handler, engines, ctx, &abi_decl)? + TyAbiDecl::collect(handler, engines, ctx, decl_id)? } 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)?; + TyStorageDecl::collect(handler, engines, ctx, decl_id)? } parsed::Declaration::TypeAliasDeclaration(decl_id) => { - let type_alias_decl = engines.pe().get_type_alias(decl_id).as_ref().clone(); - ctx.insert_parsed_symbol(handler, engines, type_alias_decl.name, decl.clone())?; + TyTypeAliasDecl::collect(handler, engines, ctx, decl_id)? } }; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 765cd669071..7dc878e858f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -1,4 +1,5 @@ use crate::{ + decl_engine::parsed_id::ParsedDeclId, language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, @@ -9,13 +10,21 @@ use symbol_collection_context::SymbolCollectionContext; impl ty::TyEnumDecl { pub(crate) fn collect( - _handler: &Handler, + handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &EnumDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { + let enum_decl = engines.pe().get_enum(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + enum_decl.name.clone(), + Declaration::EnumDeclaration(*decl_id), + )?; + // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, decl.span.clone(), |mut _ctx| Ok(())); + let _ = ctx.scoped(engines, enum_decl.span.clone(), |mut _ctx| Ok(())); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 52c7b0057e4..7ce58ac20cb 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -8,7 +8,7 @@ use sway_error::{ use symbol_collection_context::SymbolCollectionContext; use crate::{ - decl_engine::{DeclId, DeclRefFunction}, + decl_engine::{parsed_id::ParsedDeclId, DeclId, DeclRefFunction}, language::{ parsed::*, ty::{self, TyCodeBlock, TyFunctionDecl}, @@ -25,8 +25,16 @@ impl ty::TyFunctionDecl { handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - fn_decl: &FunctionDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { + let fn_decl = engines.pe().get_function(decl_id); + let _ = ctx.insert_parsed_symbol( + handler, + engines, + fn_decl.name.clone(), + Declaration::FunctionDeclaration(*decl_id), + ); + // create a namespace for the function let _ = ctx.scoped(engines, fn_decl.span.clone(), |scoped_ctx| { TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 8083fe56bee..3fa1c1a602b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -16,8 +16,8 @@ use crate::{ language::{ parsed::*, ty::{ - self, TyDecl, TyFunctionDecl, TyImplItem, TyImplSelfOrTrait, TyTraitInterfaceItem, - TyTraitItem, + self, TyConstantDecl, TyDecl, TyFunctionDecl, TyImplItem, TyImplSelfOrTrait, + TyTraitInterfaceItem, TyTraitItem, TyTraitType, }, *, }, @@ -36,16 +36,27 @@ impl TyImplSelfOrTrait { handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &ImplSelfOrTrait, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { - let _ = ctx.scoped(engines, decl.block_span.clone(), |scoped_ctx| { - decl.items.iter().for_each(|item| match item { + let impl_trait = engines.pe().get_impl_self_or_trait(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + impl_trait.trait_name.suffix.clone(), + Declaration::ImplSelfOrTrait(*decl_id), + )?; + + let _ = ctx.scoped(engines, impl_trait.block_span.clone(), |scoped_ctx| { + impl_trait.items.iter().for_each(|item| match item { ImplItem::Fn(decl_id) => { - let fn_decl = engines.pe().get_function(decl_id).as_ref().clone(); - let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &fn_decl); + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Constant(decl_id) => { + let _ = TyConstantDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Type(decl_id) => { + let _ = TyTraitType::collect(handler, engines, scoped_ctx, decl_id); } - ImplItem::Constant(_) => {} - ImplItem::Type(_) => {} }); Ok(()) }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index 8b0028f7333..08e0984b7ed 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -1,16 +1,20 @@ use std::collections::HashMap; use crate::{ + decl_engine::parsed_id::ParsedDeclId, fuel_prelude::fuel_tx::StorageSlot, ir_generation::{ const_eval::compile_constant_expression_to_constant, storage::{get_storage_key_string, serialize_to_storage_slots}, }, - language::ty::{self, TyExpression, TyStorageField}, + language::{ + parsed::StorageDeclaration, + ty::{self, TyExpression, TyStorageField}, + }, metadata::MetadataManager, semantic_analysis::{ - TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization, - TypeCheckFinalizationContext, + symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis, + TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext, }, Engines, }; @@ -24,6 +28,15 @@ use sway_ir::{ConstantValue, Context, Module}; use sway_types::{u256::U256, Spanned}; impl ty::TyStorageDecl { + pub(crate) fn collect( + _handler: &Handler, + _engines: &Engines, + _ctx: &mut SymbolCollectionContext, + _decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + Ok(()) + } + pub(crate) fn get_initialized_storage_slots( &self, handler: &Handler, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 1da30398105..77688776b3b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -1,4 +1,5 @@ use crate::{ + decl_engine::parsed_id::ParsedDeclId, language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, @@ -9,18 +10,21 @@ use symbol_collection_context::SymbolCollectionContext; impl ty::TyStructDecl { pub(crate) fn collect( - _handler: &Handler, + handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &StructDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { + let struct_decl = engines.pe().get_struct(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + struct_decl.name.clone(), + Declaration::StructDeclaration(*decl_id), + )?; + // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, decl.span.clone(), |_scoped_ctx| { - decl.fields.iter().for_each(|_field| { - //let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); - }); - Ok(()) - }); + let _ = ctx.scoped(engines, struct_decl.span.clone(), |_scoped_ctx| Ok(())); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 9981627f295..6beb4ea7f4f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, HashSet}; +use parsed_id::ParsedDeclId; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, @@ -11,7 +12,10 @@ use crate::{ decl_engine::*, language::{ parsed::*, - ty::{self, TyFunctionDecl, TyImplItem, TyTraitDecl, TyTraitFn, TyTraitItem}, + ty::{ + self, TyConstantDecl, TyFunctionDecl, TyImplItem, TyTraitDecl, TyTraitFn, TyTraitItem, + TyTraitType, + }, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf}, @@ -25,28 +29,45 @@ use crate::{ Engines, }; +impl TyTraitItem { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + item: &TraitItem, + ) -> Result<(), ErrorEmitted> { + match item { + TraitItem::TraitFn(decl_id) => TyTraitFn::collect(handler, engines, ctx, decl_id), + TraitItem::Constant(decl_id) => TyConstantDecl::collect(handler, engines, ctx, decl_id), + TraitItem::Type(decl_id) => TyTraitType::collect(handler, engines, ctx, decl_id), + TraitItem::Error(_, _) => Ok(()), + } + } +} + impl TyTraitDecl { pub(crate) fn collect( handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &TraitDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { + let trait_decl = engines.pe().get_trait(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + trait_decl.name.clone(), + Declaration::TraitDeclaration(*decl_id), + )?; + // A temporary namespace for checking within the trait's scope. - let _ = ctx.scoped(engines, decl.span.clone(), |scoped_ctx| { - decl.interface_surface.iter().for_each(|item| match item { - TraitItem::TraitFn(decl_id) => { - let trait_fn = engines.pe().get_trait_fn(decl_id).as_ref().clone(); - let _ = TyTraitFn::collect(handler, engines, scoped_ctx, &trait_fn); - } - TraitItem::Constant(_) => todo!(), - TraitItem::Type(_) => {} - TraitItem::Error(_, _) => todo!(), + let _ = ctx.scoped(engines, trait_decl.span.clone(), |scoped_ctx| { + trait_decl.interface_surface.iter().for_each(|item| { + let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); }); - decl.methods.iter().for_each(|m| { - let method_decl = engines.pe().get_function(m).as_ref().clone(); - let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, &method_decl); + trait_decl.methods.iter().for_each(|decl_id| { + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); }); Ok(()) }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 15ad27c4823..e6b45f08919 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -1,9 +1,9 @@ use sway_types::Spanned; use crate::{ - decl_engine::DeclId, + decl_engine::{parsed_id::ParsedDeclId, DeclId}, language::{ - parsed::{self, TraitFn}, + parsed::{self, Declaration, TraitFn}, ty, CallPath, Visibility, }, semantic_analysis::{ @@ -21,12 +21,19 @@ use crate::{ impl ty::TyTraitFn { pub(crate) fn collect( - _handler: &Handler, + handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &TraitFn, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { - let _ = ctx.scoped(engines, decl.span.clone(), |_scoped_ctx| Ok(())); + let trait_fn = engines.pe().get_trait_fn(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + trait_fn.name.clone(), + Declaration::TraitFnDeclaration(*decl_id), + )?; + let _ = ctx.scoped(engines, trait_fn.span.clone(), |_scoped_ctx| Ok(())); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs index 103c721321e..c387ecdb27b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs @@ -5,11 +5,13 @@ use sway_error::{ use sway_types::Span; use crate::{ + decl_engine::parsed_id::ParsedDeclId, language::{ - parsed, + parsed::{self, Declaration, TraitTypeDeclaration}, ty::{self, TyTraitType}, }, semantic_analysis::{ + symbol_collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, }, @@ -18,6 +20,21 @@ use crate::{ }; impl ty::TyTraitType { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + let trait_type_decl = engines.pe().get_trait_type(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + trait_type_decl.name.clone(), + Declaration::TraitTypeDeclaration(*decl_id), + ) + } + pub(crate) fn type_check( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/type_alias.rs b/sway-core/src/semantic_analysis/ast_node/declaration/type_alias.rs index 90eb2ad673e..7bcf3fb06c3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/type_alias.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/type_alias.rs @@ -1,9 +1,34 @@ use crate::{ - language::ty::TyTypeAliasDecl, - semantic_analysis::{TypeCheckFinalization, TypeCheckFinalizationContext}, + decl_engine::parsed_id::ParsedDeclId, + language::{ + parsed::{Declaration, TypeAliasDeclaration}, + ty::TyTypeAliasDecl, + }, + semantic_analysis::{ + symbol_collection_context::SymbolCollectionContext, TypeCheckFinalization, + TypeCheckFinalizationContext, + }, + Engines, }; use sway_error::handler::{ErrorEmitted, Handler}; +impl TyTypeAliasDecl { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + let type_alias = engines.pe().get_type_alias(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + type_alias.name.clone(), + Declaration::TypeAliasDeclaration(*decl_id), + ) + } +} + impl TypeCheckFinalization for TyTypeAliasDecl { fn type_check_finalize( &mut self, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs index aeca035b8c8..32dccb078db 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -1,4 +1,5 @@ use crate::{ + decl_engine::parsed_id::ParsedDeclId, language::{ parsed::*, ty::{self, TyExpression, TyVariableDecl}, @@ -17,9 +18,16 @@ impl ty::TyVariableDecl { handler: &Handler, engines: &Engines, ctx: &mut SymbolCollectionContext, - decl: &VariableDeclaration, + decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { - TyExpression::collect(handler, engines, ctx, &decl.body) + let var_decl = engines.pe().get_variable(decl_id); + ctx.insert_parsed_symbol( + handler, + engines, + var_decl.name.clone(), + Declaration::VariableDeclaration(*decl_id), + )?; + TyExpression::collect(handler, engines, ctx, &var_decl.body) } pub fn type_check( diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index b7e01925767..36f14f2050f 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -235,7 +235,7 @@ impl Module { pub fn enter_lexical_scope( &mut self, handler: &Handler, - engines: &Engines, + _engines: &Engines, span: Span, ) -> Result { let id_opt = self.lexical_scopes_spans.get(&span); From dca621f7fe4d55cb2d3ecaf00593b4bfd7abfbb6 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 26 Aug 2024 12:08:37 +0100 Subject: [PATCH 12/12] Rework parsed module storage and ordering algorithm. --- sway-core/src/concurrent_slab_mut.rs | 131 ++++++++++++ sway-core/src/engine_threading.rs | 8 + sway-core/src/language/module.rs | 12 +- sway-core/src/language/parsed/mod.rs | 2 + sway-core/src/language/parsed/module.rs | 62 +++++- .../language/parsed/parsed_module_engine.rs | 81 +++++++ sway-core/src/language/parsed/program.rs | 6 +- sway-core/src/lib.rs | 199 ++++++++++++------ sway-core/src/semantic_analysis.rs | 2 +- sway-core/src/semantic_analysis/module.rs | 158 +++++++++----- .../src/semantic_analysis/namespace/module.rs | 2 +- sway-core/src/semantic_analysis/program.rs | 10 +- .../src/semantic_analysis/symbol_resolve.rs | 10 +- sway-error/src/error.rs | 2 +- sway-lsp/src/core/session.rs | 28 ++- sway-module-order/Forc.lock | 3 + sway-module-order/Forc.toml | 8 + sway-module-order/src/a.sw | 3 + sway-module-order/src/a/inner_a.sw | 3 + sway-module-order/src/b.sw | 3 + sway-module-order/src/b/inner_b.sw | 3 + sway-module-order/src/lib.sw | 4 + 22 files changed, 585 insertions(+), 155 deletions(-) create mode 100644 sway-core/src/concurrent_slab_mut.rs create mode 100644 sway-core/src/language/parsed/parsed_module_engine.rs create mode 100644 sway-module-order/Forc.lock create mode 100644 sway-module-order/Forc.toml create mode 100644 sway-module-order/src/a.sw create mode 100644 sway-module-order/src/a/inner_a.sw create mode 100644 sway-module-order/src/b.sw create mode 100644 sway-module-order/src/b/inner_b.sw create mode 100644 sway-module-order/src/lib.sw diff --git a/sway-core/src/concurrent_slab_mut.rs b/sway-core/src/concurrent_slab_mut.rs new file mode 100644 index 00000000000..03d22121d07 --- /dev/null +++ b/sway-core/src/concurrent_slab_mut.rs @@ -0,0 +1,131 @@ +use std::{ + fmt, + sync::{Arc, RwLock}, +}; + +#[derive(Debug, Clone)] +pub struct Inner { + pub items: Vec>>>, + pub free_list: Vec, +} + +impl Default for Inner { + fn default() -> Self { + Self { + items: Default::default(), + free_list: Default::default(), + } + } +} + +#[derive(Debug)] +pub(crate) struct ConcurrentSlabMut { + pub inner: RwLock>, +} + +impl Clone for ConcurrentSlabMut +where + T: Clone, +{ + fn clone(&self) -> Self { + let inner = self.inner.read().unwrap(); + Self { + inner: RwLock::new(inner.clone()), + } + } +} + +impl Default for ConcurrentSlabMut { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +pub struct ListDisplay { + pub list: I, +} + +impl fmt::Display for ListDisplay +where + I::Item: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fmt_elems = self + .list + .clone() + .into_iter() + .enumerate() + .map(|(i, value)| format!("{i:<10}\t->\t{value}")) + .collect::>(); + write!(f, "{}", fmt_elems.join("\n")) + } +} + +impl ConcurrentSlabMut +where + T: Clone, +{ + #[allow(dead_code)] + pub fn len(&self) -> usize { + let inner = self.inner.read().unwrap(); + inner.items.len() + } + + #[allow(dead_code)] + pub fn values(&self) -> Vec>> { + let inner = self.inner.read().unwrap(); + inner.items.iter().filter_map(|x| x.clone()).collect() + } + + pub fn insert(&self, value: T) -> usize { + self.insert_arc(Arc::new(RwLock::new(value))) + } + + pub fn insert_arc(&self, value: Arc>) -> usize { + let mut inner = self.inner.write().unwrap(); + + if let Some(free) = inner.free_list.pop() { + assert!(inner.items[free].is_none()); + inner.items[free] = Some(value); + free + } else { + inner.items.push(Some(value)); + inner.items.len() - 1 + } + } + + pub fn get(&self, index: usize) -> Arc> { + let inner = self.inner.read().unwrap(); + inner.items[index] + .as_ref() + .expect("invalid slab index for ConcurrentSlab::get") + .clone() + } + + #[allow(dead_code)] + pub fn retain(&self, predicate: impl Fn(&usize, &mut Arc>) -> bool) { + let mut inner = self.inner.write().unwrap(); + + let Inner { items, free_list } = &mut *inner; + for (idx, item) in items.iter_mut().enumerate() { + if let Some(arc) = item { + if !predicate(&idx, arc) { + free_list.push(idx); + item.take(); + } + } + } + } + + #[allow(dead_code)] + pub fn clear(&self) { + let mut inner = self.inner.write().unwrap(); + inner.items.clear(); + inner.items.shrink_to(0); + + inner.free_list.clear(); + inner.free_list.shrink_to(0); + } +} diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index f4ad12632ef..1e245eac7ac 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -1,5 +1,6 @@ use crate::{ decl_engine::{parsed_engine::ParsedDeclEngine, DeclEngine}, + language::parsed::ParsedModuleEngine, query_engine::QueryEngine, type_system::TypeEngine, }; @@ -15,6 +16,7 @@ pub struct Engines { type_engine: TypeEngine, decl_engine: DeclEngine, parsed_decl_engine: ParsedDeclEngine, + parsed_module_engine: ParsedModuleEngine, query_engine: QueryEngine, source_engine: SourceEngine, } @@ -32,6 +34,10 @@ impl Engines { &self.parsed_decl_engine } + pub fn pme(&self) -> &ParsedModuleEngine { + &self.parsed_module_engine + } + pub fn qe(&self) -> &QueryEngine { &self.query_engine } @@ -46,6 +52,7 @@ impl Engines { self.type_engine.clear_program(program_id); self.decl_engine.clear_program(program_id); self.parsed_decl_engine.clear_program(program_id); + // self.parsed_module_engine.clear_program(program_id); } /// Removes all data associated with `source_id` from the declaration and type engines. @@ -54,6 +61,7 @@ impl Engines { self.type_engine.clear_module(source_id); self.decl_engine.clear_module(source_id); self.parsed_decl_engine.clear_module(source_id); + // self.parsed_module_engine.clear_module(source_id); } /// Helps out some `thing: T` by adding `self` as context. diff --git a/sway-core/src/language/module.rs b/sway-core/src/language/module.rs index 2649ddd416e..0bd5be93262 100644 --- a/sway-core/src/language/module.rs +++ b/sway-core/src/language/module.rs @@ -1,14 +1,23 @@ use sway_types::Ident; +use super::parsed::ParseModuleId; + /// The name used within a module to refer to one of its submodules. /// /// If an alias was given to the `mod`, this will be the alias. If not, this is the submodule's /// library name. pub type ModName = Ident; +pub type ModPath = Vec; + +pub trait HasModuleId +{ + /// Returns the associated module id. + fn module_id(&self) -> ParseModuleId; +} + pub trait HasModule where - T: HasSubmodules, Self: Sized, { /// Returns the module of this submodule. @@ -17,7 +26,6 @@ where pub trait HasSubmodules where - E: HasModule, Self: Sized, { /// Returns the submodules of this module. diff --git a/sway-core/src/language/parsed/mod.rs b/sway-core/src/language/parsed/mod.rs index bf19ed600c3..9c70b2574ce 100644 --- a/sway-core/src/language/parsed/mod.rs +++ b/sway-core/src/language/parsed/mod.rs @@ -4,6 +4,7 @@ pub mod declaration; mod expression; mod include_statement; mod module; +mod parsed_module_engine; mod program; mod use_statement; @@ -12,6 +13,7 @@ pub use declaration::*; pub use expression::*; pub use include_statement::IncludeStatement; pub use module::{ModuleEvaluationOrder, ParseModule, ParseSubmodule}; +pub use parsed_module_engine::*; pub use program::{ParseProgram, TreeType}; use sway_error::handler::ErrorEmitted; use sway_types::span::Span; diff --git a/sway-core/src/language/parsed/module.rs b/sway-core/src/language/parsed/module.rs index 7a29701a040..18fe5ac051c 100644 --- a/sway-core/src/language/parsed/module.rs +++ b/sway-core/src/language/parsed/module.rs @@ -1,17 +1,25 @@ use crate::{ - language::{HasModule, HasSubmodules, ModName, Visibility}, - transform, + language::{HasModule, HasModuleId, HasSubmodules, ModName, Visibility}, + namespace::ModulePath, + transform, Engines, }; -use super::ParseTree; +use super::{ParseModuleId, ParseTree}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Span; pub type ModuleHash = u64; -pub type ModuleEvaluationOrder = Vec; +pub type ModuleEvaluationOrder = Vec; /// A module and its submodules in the form of a tree. #[derive(Debug, Clone)] pub struct ParseModule { + pub id: ParseModuleId, + /// Parent module id or `None` if its a root module. + pub parent: Option, /// The content of this module in the form of a `ParseTree`. pub tree: ParseTree, /// Submodules introduced within this module using the `dep` syntax in order of declaration. @@ -25,6 +33,40 @@ pub struct ParseModule { pub span: Span, /// an hash used for caching the module pub hash: ModuleHash, + pub name: Option, +} + +impl ParseModule { + /// Lookup the submodule at the given path. + pub fn lookup_submodule( + &self, + handler: &Handler, + engines: &Engines, + path: &ModulePath, + ) -> Result { + let pme = engines.pme(); + let mut module_id = self.id; + for ident in path.iter() { + let module_arc = pme.get(&module_id); + let module = module_arc.read().unwrap(); + match module.submodules.iter().find(|(name, _)| name == ident) { + Some((_name, submod)) => module_id = submod.module, + None => { + return Err(handler.emit_err(CompileError::Internal( + "Cannot find submodule", + Span::dummy(), + ))) + } + } + } + Ok(module_id) + } +} + +impl HasModuleId for ParseModule { + fn module_id(&self) -> ParseModuleId { + self.id + } } /// A library module that was declared as a `mod` of another module. @@ -32,13 +74,19 @@ pub struct ParseModule { /// Only submodules are guaranteed to be a `library`. #[derive(Debug, Clone)] pub struct ParseSubmodule { - pub module: ParseModule, + pub module: ParseModuleId, pub mod_name_span: Span, pub visibility: Visibility, } -impl HasModule for ParseSubmodule { - fn module(&self) -> &ParseModule { +impl HasModuleId for ParseSubmodule { + fn module_id(&self) -> ParseModuleId { + self.module + } +} + +impl HasModule for ParseSubmodule { + fn module(&self) -> &ParseModuleId { &self.module } } diff --git a/sway-core/src/language/parsed/parsed_module_engine.rs b/sway-core/src/language/parsed/parsed_module_engine.rs new file mode 100644 index 00000000000..472d0335291 --- /dev/null +++ b/sway-core/src/language/parsed/parsed_module_engine.rs @@ -0,0 +1,81 @@ +use std::sync::{Arc, RwLock}; + +use crate::{concurrent_slab_mut::ConcurrentSlabMut, engine_threading::DebugWithEngines}; + +use super::ParseModule; + +/// A identifier to uniquely refer to our parsed modules. +#[derive(Default, PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] +pub struct ParseModuleId(usize); + +impl ParseModuleId { + pub fn new(index: usize) -> Self { + ParseModuleId(index) + } + + /// Returns the index that identifies the type. + pub fn index(&self) -> usize { + self.0 + } + + pub(crate) fn get(&self, engines: &crate::Engines) -> Arc> { + engines.pme().get(self) + } + + pub fn read(&self, engines: &crate::Engines, f: impl Fn(&ParseModule) -> R) -> R { + let value = self.get(engines); + let value = value.read().unwrap(); + f(&value) + } + + pub fn write( + &self, + engines: &crate::Engines, + mut f: impl FnMut(&mut ParseModule) -> R, + ) -> R { + let value = self.get(engines); + let mut value = value.write().unwrap(); + f(&mut value) + } +} + +impl DebugWithEngines for ParseModuleId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>, engines: &crate::Engines) -> std::fmt::Result { + let name = self.read(engines, |m| m.name.clone()); + write!(f, "{:?}", name) + } +} + +/// The Parsed Module Engine manages a relationship between module ids and their corresponding +/// parsed module structures. +#[derive(Debug, Default, Clone)] +pub struct ParsedModuleEngine { + slab: ConcurrentSlabMut, +} + +impl ParsedModuleEngine { + /// This function provides the namespace module corresponding to a specified module ID. + pub fn get(&self, module_id: &ParseModuleId) -> Arc> { + self.slab.get(module_id.index()) + } + + pub fn read(&self, module_id: &ParseModuleId, f: impl Fn(&ParseModule) -> R) -> R { + let value = self.slab.get(module_id.index()); + let value = value.read().unwrap(); + f(&value) + } + + pub fn write(&self, module_id: &ParseModuleId, f: impl Fn(&mut ParseModule) -> R) -> R { + let value = self.slab.get(module_id.index()); + let mut value = value.write().unwrap(); + f(&mut value) + } + + pub fn insert(&self, value: ParseModule) -> ParseModuleId { + let id = ParseModuleId(self.slab.insert(value)); + self.write(&id, |m| { + m.id = id; + }); + id + } +} diff --git a/sway-core/src/language/parsed/program.rs b/sway-core/src/language/parsed/program.rs index 29311c20705..f36455cda9e 100644 --- a/sway-core/src/language/parsed/program.rs +++ b/sway-core/src/language/parsed/program.rs @@ -2,7 +2,7 @@ use strum::EnumString; use crate::Engines; -use super::ParseModule; +use super::ParseModuleId; /// A parsed, but not yet type-checked, Sway program. /// @@ -10,7 +10,7 @@ use super::ParseModule; #[derive(Debug, Clone)] pub struct ParseProgram { pub kind: TreeType, - pub root: ParseModule, + pub root: ParseModuleId, } /// A Sway program can be either a contract, script, predicate, or a library. @@ -46,6 +46,6 @@ impl std::fmt::Display for TreeType { impl ParseProgram { /// Excludes all test functions from the parse tree. pub(crate) fn exclude_tests(&mut self, engines: &Engines) { - self.root.tree.exclude_tests(engines) + self.root.write(engines, |m| m.tree.exclude_tests(engines)) } } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index fcc524ce8a0..19e9019c264 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -12,6 +12,7 @@ mod asm_lang; mod build_config; pub mod compiler_generated; mod concurrent_slab; +mod concurrent_slab_mut; mod control_flow_analysis; mod debug_generation; pub mod decl_engine; @@ -34,9 +35,12 @@ pub use build_config::{BuildConfig, BuildTarget, LspConfig, OptLevel, PrintAsm, use control_flow_analysis::ControlFlowGraph; pub use debug_generation::write_dwarf; use indexmap::IndexMap; +use language::parsed::ParseModuleId; use metadata::MetadataManager; use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, ProgramsCacheEntry}; +use semantic_analysis::module::ModuleDepGraph; use std::collections::hash_map::DefaultHasher; +use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -113,6 +117,7 @@ pub fn parse( config.include_tests, config.experimental, config.lsp_mode.as_ref(), + None, ) .map( |ParsedModuleTree { @@ -217,6 +222,8 @@ fn parse_in_memory( let submodules = Vec::default(); let attributes = module_attrs_to_map(handler, &module.attribute_list)?; let root = parsed::ParseModule { + id: ParseModuleId::default(), + parent: None, span: span::Span::dummy(), module_kind_span, module_eval_order: vec![], @@ -224,7 +231,9 @@ fn parse_in_memory( submodules, attributes, hash, + name: None, }; + let root_id = engines.pme().insert(root); let lexed_program = lexed::LexedProgram::new( kind, lexed::LexedModule { @@ -233,7 +242,13 @@ fn parse_in_memory( }, ); - Ok((lexed_program, parsed::ParseProgram { kind, root })) + Ok(( + lexed_program, + parsed::ParseProgram { + kind, + root: root_id, + }, + )) } pub struct Submodule { @@ -258,6 +273,7 @@ fn parse_submodules( include_tests: bool, experimental: ExperimentalFlags, lsp_mode: Option<&LspConfig>, + parent: Option, ) -> Submodules { // Assume the happy path, so there'll be as many submodules as dependencies, but no more. let mut submods = Vec::with_capacity(module.submodules().count()); @@ -290,6 +306,7 @@ fn parse_submodules( include_tests, experimental, lsp_mode, + parent, ) { if !matches!(kind, parsed::TreeType::Library) { let source_id = engines.se().get_source_id(submod_path.as_ref()); @@ -327,7 +344,7 @@ pub type SourceHash = u64; pub struct ParsedModuleTree { pub tree_type: parsed::TreeType, pub lexed_module: lexed::LexedModule, - pub parse_module: parsed::ParseModule, + pub parse_module: ParseModuleId, } /// Given the source of the module along with its path, @@ -343,6 +360,7 @@ fn parse_module_tree( include_tests: bool, experimental: ExperimentalFlags, lsp_mode: Option<&LspConfig>, + parent: Option, ) -> Result { let query_engine = engines.qe(); @@ -351,6 +369,35 @@ fn parse_module_tree( let source_id = engines.se().get_source_id(&path.clone()); let module = sway_parse::parse_file(handler, src.clone(), Some(source_id))?; + // Convert from the raw parsed module to the `ParseTree` ready for type-check. + let (kind, tree) = to_parsed_lang::convert_parse_tree( + &mut to_parsed_lang::Context::new(build_target, experimental), + handler, + engines, + module.value.clone(), + )?; + let module_kind_span = module.value.kind.span(); + let attributes = module_attrs_to_map(handler, &module.attribute_list)?; + + let mut hasher = DefaultHasher::new(); + src.hash(&mut hasher); + let hash = hasher.finish(); + + let parse_module = parsed::ParseModule { + id: ParseModuleId::default(), + parent, + span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(), + module_kind_span, + module_eval_order: vec![], + tree, + submodules: vec![], + attributes, + hash, + name: module_name.map(|n| n.to_string()), + }; + + let parse_module_id = engines.pme().insert(parse_module); + // Parse all submodules before converting to the `ParseTree`. // This always recovers on parse errors for the file itself by skipping that file. let submodules = parse_submodules( @@ -363,44 +410,25 @@ fn parse_module_tree( include_tests, experimental, lsp_mode, + Some(parse_module_id), ); - // Convert from the raw parsed module to the `ParseTree` ready for type-check. - let (kind, tree) = to_parsed_lang::convert_parse_tree( - &mut to_parsed_lang::Context::new(build_target, experimental), - handler, - engines, - module.value.clone(), - )?; - let module_kind_span = module.value.kind.span(); - let attributes = module_attrs_to_map(handler, &module.attribute_list)?; - let lexed_submodules = submodules .iter() .map(|s| (s.name.clone(), s.lexed.clone())) .collect::>(); - let lexed = lexed::LexedModule { + let lexed_module = lexed::LexedModule { tree: module.value, submodules: lexed_submodules, }; - let mut hasher = DefaultHasher::new(); - src.hash(&mut hasher); - let hash = hasher.finish(); - - let parsed_submodules = submodules - .iter() - .map(|s| (s.name.clone(), s.parsed.clone())) - .collect::>(); - let parsed = parsed::ParseModule { - span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(), - module_kind_span, - module_eval_order: vec![], - tree, - submodules: parsed_submodules, - attributes, - hash, - }; + parse_module_id.write(engines, |m| { + let parsed_submodules = submodules + .iter() + .map(|s| (s.name.clone(), s.parsed.clone())) + .collect::>(); + m.submodules = parsed_submodules; + }); // Let's prime the cache with the module dependency and hash data. let modified_time = std::fs::metadata(path.as_path()) @@ -426,8 +454,8 @@ fn parse_module_tree( Ok(ParsedModuleTree { tree_type: kind, - lexed_module: lexed, - parse_module: parsed, + lexed_module, + parse_module: parse_module_id, }) } @@ -536,14 +564,62 @@ fn module_path( pub fn build_module_dep_graph( handler: &Handler, - parse_module: &mut parsed::ParseModule, + engines: &Engines, + root_module_id: ParseModuleId, ) -> Result<(), ErrorEmitted> { - let module_dep_graph = ty::TyModule::build_dep_graph(handler, parse_module)?; - parse_module.module_eval_order = module_dep_graph.compute_order(handler)?; + let mut dep_graph = ModuleDepGraph::new(); + + { + let root_module_arc = root_module_id.get(engines); + let root_module = root_module_arc.read().unwrap(); + let module_name = root_module.name.clone(); + + ty::TyModule::build_dep_graph( + handler, + engines, + &mut dep_graph, + &root_module, + &root_module_id, + )?; - for (_, submodule) in &mut parse_module.submodules { - build_module_dep_graph(handler, &mut submodule.module)?; + dep_graph.visualize( + engines, + Some(format!( + "module_dep_graph_{}.dot", + module_name.clone().unwrap_or_default() + )), + ); } + + let ordered_modules = dep_graph.compute_order(handler, engines)?; + + //println!("global order {:?}", engines.help_out(global_order.clone())); + + // Set the modules with their computed submodules evaluation order + let mut modules = VecDeque::new(); + modules.push_back(root_module_id); + + while let Some(module_id) = modules.pop_front() { + module_id.write(engines, |m| { + let submodules = m.submodules.iter().map(|(_, m)| m.module); + + // Queue up the submodules for further processing + modules.extend(submodules.clone()); + + // Sort submodules based on their position in the computed order + let mut sorted = submodules.collect::>(); + + let position_in_order = + |module_id: &ParseModuleId| ordered_modules.iter().position(|id| id == module_id); + + sorted.sort_by_key(|module| position_in_order(module)); + + //println!("position_in_order {:?} {:?}", m.name, engines.help_out(sorted.clone())); + + m.module_eval_order = sorted.clone(); + }); + } + Ok(()) } @@ -565,10 +641,11 @@ pub fn parsed_to_ast( }); let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default(); - // Build the dependency graph for the submodules. - build_module_dep_graph(handler, &mut parse_program.root)?; + // Build the dependency graph starting from the root module. + build_module_dep_graph(handler, engines, parse_program.root)?; let namespace = Namespace::init_root(initial_namespace); + // Collect the program symbols. let mut collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; @@ -1254,32 +1331,34 @@ fn test_unary_ordering() { let (.., prog) = prog.unwrap(); // this should parse as `(!a) && b`, not `!(a && b)`. So, the top level // expression should be `&&` - if let parsed::AstNode { - content: - parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)), - .. - } = &prog.root.tree.root_nodes[0] - { - let fn_decl = engines.pe().get_function(decl_id); + prog.root.read(&engines, |root| { if let parsed::AstNode { content: - parsed::AstNodeContent::Expression(parsed::Expression { - kind: - parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression { - op, .. - }), - .. - }), + parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)), .. - } = &fn_decl.body.contents[2] + } = &root.tree.root_nodes[0] { - assert_eq!(op, &language::LazyOp::And) + let fn_decl = engines.pe().get_function(decl_id); + if let parsed::AstNode { + content: + parsed::AstNodeContent::Expression(parsed::Expression { + kind: + parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression { + op, .. + }), + .. + }), + .. + } = &fn_decl.body.contents[2] + { + assert_eq!(op, &language::LazyOp::And) + } else { + panic!("Was not lazy operator.") + } } else { - panic!("Was not lazy operator.") - } - } else { - panic!("Was not ast node") - }; + panic!("Was not ast node") + }; + }) } #[test] diff --git a/sway-core/src/semantic_analysis.rs b/sway-core/src/semantic_analysis.rs index 2d3bcdcc6c3..e82317da4a9 100644 --- a/sway-core/src/semantic_analysis.rs +++ b/sway-core/src/semantic_analysis.rs @@ -2,7 +2,7 @@ pub mod ast_node; pub(crate) mod cei_pattern_analysis; pub(crate) mod coins_analysis; -mod module; +pub mod module; pub mod namespace; mod node_dependencies; mod program; diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 8acdf1cac09..8266538ed5c 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -44,15 +44,18 @@ pub type ModuleDepGraphNodeId = petgraph::graph::NodeIndex; #[derive(Clone, Debug)] pub enum ModuleDepGraphNode { - Module {}, + Module { id: ParseModuleId }, Submodule { name: ModName }, } impl DebugWithEngines for ModuleDepGraphNode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _engines: &Engines) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>, engines: &Engines) -> std::fmt::Result { let text = match self { - ModuleDepGraphNode::Module { .. } => { - format!("{:?}", "Root module") + ModuleDepGraphNode::Module { id } => { + let module_arc = engines.pme().get(id); + let module = module_arc.read().unwrap(); + let module_name = module.name.clone().unwrap_or_default(); + format!("{:?}", module_name.as_str()) } ModuleDepGraphNode::Submodule { name: mod_name } => { format!("{:?}", mod_name.as_str()) @@ -68,7 +71,7 @@ pub type ModuleDepNodeGraph = petgraph::graph::DiGraph, + node_id_map: HashMap, } impl ModuleDepGraph { @@ -76,31 +79,34 @@ impl ModuleDepGraph { Self { dep_graph: Default::default(), root: Default::default(), - node_name_map: Default::default(), + node_id_map: Default::default(), + } + } + + pub fn get_or_add_node(&mut self, id: ParseModuleId) -> ModuleDepGraphNodeId { + match self.get_node_id_for_module(id) { + Some(node) => node, + None => self.add_node(ModuleDepGraphNode::Module { id }), } } pub fn add_node(&mut self, node: ModuleDepGraphNode) -> ModuleDepGraphNodeId { let node_id = self.dep_graph.add_node(node.clone()); match node { - ModuleDepGraphNode::Module {} => {} - ModuleDepGraphNode::Submodule { name: mod_name } => { - self.node_name_map.insert(mod_name.to_string(), node_id); + ModuleDepGraphNode::Module { id } => { + self.node_id_map.insert(id, node_id); } + ModuleDepGraphNode::Submodule { .. } => unreachable!(), }; node_id } - pub fn add_root_node(&mut self) -> ModuleDepGraphNodeId { - self.root = self.add_node(super::module::ModuleDepGraphNode::Module {}); - self.root + pub fn add_module_node(&mut self, id: ParseModuleId) -> ModuleDepGraphNodeId { + self.add_node(ModuleDepGraphNode::Module { id }) } - fn get_node_id_for_module( - &self, - mod_name: &sway_types::BaseIdent, - ) -> Option { - self.node_name_map.get(&mod_name.to_string()).copied() + fn get_node_id_for_module(&self, id: ParseModuleId) -> Option { + self.node_id_map.get(&id).copied() } /// Prints out GraphViz DOT format for the dependency graph. @@ -147,16 +153,23 @@ impl ModuleDepGraph { pub(crate) fn compute_order( &self, handler: &Handler, + engines: &Engines, ) -> Result { // Check for dependency cycles in the graph by running the Johnson's algorithm. let cycles = self.dep_graph.cycles(); if !cycles.is_empty() { let mut modules = Vec::new(); for cycle in cycles.first().unwrap() { + if *cycle == self.root { + continue; + } let node = self.dep_graph.node_weight(*cycle).unwrap(); match node { - ModuleDepGraphNode::Module {} => unreachable!(), - ModuleDepGraphNode::Submodule { name } => modules.push(name.clone()), + ModuleDepGraphNode::Module { id } => { + let name = id.read(engines, |m| m.name.clone()).unwrap_or_default(); + modules.push(name) + } + ModuleDepGraphNode::Submodule { .. } => unreachable!(), }; } return Err(handler.emit_err(CompileError::ModuleDepGraphCyclicReference { modules })); @@ -177,8 +190,8 @@ impl ModuleDepGraph { let node = self.dep_graph.node_weight(node_index); match node { Some(node) => match node { - ModuleDepGraphNode::Module {} => None, // root module - ModuleDepGraphNode::Submodule { name: mod_name } => Some(mod_name.clone()), + ModuleDepGraphNode::Module { id } => Some(*id), + ModuleDepGraphNode::Submodule { .. } => unreachable!(), }, None => None, } @@ -194,29 +207,45 @@ impl ty::TyModule { /// Analyzes the given parsed module to produce a dependency graph. pub fn build_dep_graph( handler: &Handler, - parsed: &ParseModule, - ) -> Result { - let mut dep_graph = ModuleDepGraph::new(); - dep_graph.add_root_node(); + engines: &Engines, + dep_graph: &mut ModuleDepGraph, + root_module: &ParseModule, + module_id: &ParseModuleId, + ) -> Result<(), ErrorEmitted> { + let module_arc = module_id.get(engines); + let module = module_arc.read().unwrap(); - let ParseModule { submodules, .. } = parsed; + let node = dep_graph.get_or_add_node(*module_id); + if module.parent.is_none() { + dep_graph.root = node; + } // Create graph nodes for each submodule. - submodules.iter().for_each(|(name, _submodule)| { - let sub_mod_node = - dep_graph.add_node(ModuleDepGraphNode::Submodule { name: name.clone() }); + module.submodules.iter().for_each(|(_name, submodule)| { + let sub_mod_node = dep_graph.get_or_add_node(submodule.module); dep_graph .dep_graph - .add_edge(dep_graph.root, sub_mod_node, ModuleDepGraphEdge {}); + .add_edge(node, sub_mod_node, ModuleDepGraphEdge {}); }); // Analyze submodules first in order of declaration. - submodules.iter().for_each(|(name, submodule)| { - let _ = - ty::TySubmodule::build_dep_graph(handler, &mut dep_graph, name.clone(), submodule); - }); + module + .submodules + .iter() + .map(|(_name, submodule)| { + let _ = ty::TySubmodule::build_dep_graph( + handler, + engines, + dep_graph, + root_module, + submodule, + ); + + Self::build_dep_graph(handler, engines, dep_graph, root_module, &submodule.module) + }) + .collect::, ErrorEmitted>>()?; - Ok(dep_graph) + Ok(()) } /// Collects the given parsed module to produce a module symbol map. @@ -242,7 +271,7 @@ impl ty::TyModule { module_eval_order.iter().for_each(|eval_mod_name| { let (name, submodule) = submodules .iter() - .find(|(submod_name, _submodule)| eval_mod_name == submod_name) + .find(|(_name, submodule)| *eval_mod_name == submodule.module) .unwrap(); let _ = ty::TySubmodule::collect(handler, engines, ctx, name.clone(), submodule); }); @@ -325,15 +354,19 @@ impl ty::TyModule { // Type-check submodules first in order of evaluation previously computed by the dependency graph. let submodules_res = module_eval_order .iter() - .map(|eval_mod_name| { + .map(|eval_mod_id| { let (name, submodule) = submodules .iter() - .find(|(submod_name, _)| eval_mod_name == submod_name) + .find(|(_name, submodule)| *eval_mod_id == submodule.module) .unwrap(); + let source_id = submodule + .module + .read(engines, |m| m.span.source_id().cloned()); + // Try to get the cached submodule if let Some(cached_module) = ty::TyModule::get_cached_ty_module_if_up_to_date( - submodule.module.span.source_id(), + source_id.as_ref(), engines, build_config, ) { @@ -639,30 +672,35 @@ fn collect_fallback_fn( impl ty::TySubmodule { pub fn build_dep_graph( - _handler: &Handler, + handler: &Handler, + engines: &Engines, module_dep_graph: &mut ModuleDepGraph, - mod_name: ModName, + root_module: &ParseModule, submodule: &ParseSubmodule, ) -> Result<(), ErrorEmitted> { let ParseSubmodule { module, .. } = submodule; - let sub_mod_node = module_dep_graph.get_node_id_for_module(&mod_name).unwrap(); + let submod_node = module_dep_graph.get_node_id_for_module(*module).unwrap(); + let module_arc = module.get(engines); + let module = module_arc.read().unwrap(); for node in module.tree.root_nodes.iter() { match &node.content { AstNodeContent::UseStatement(use_stmt) => { - if let Some(use_mod_ident) = use_stmt.call_path.first() { - if let Some(mod_name_node) = - module_dep_graph.get_node_id_for_module(use_mod_ident) - { - // Prevent adding edge loops between the same node as that will throw off - // the cyclic dependency analysis. - if sub_mod_node != mod_name_node { - module_dep_graph.dep_graph.add_edge( - sub_mod_node, - mod_name_node, - ModuleDepGraphEdge {}, - ); - } - } + let used_submod_module_id = root_module.lookup_submodule( + handler, + engines, + &vec![use_stmt.call_path.first().unwrap().clone()], + )?; + + let used_submod_node = module_dep_graph.get_or_add_node(used_submod_module_id); + + // Prevent adding edge loops between the same node as that will throw off + // the cyclic dependency analysis. + if submod_node != used_submod_node { + module_dep_graph.dep_graph.add_edge( + submod_node, + used_submod_node, + ModuleDepGraphEdge {}, + ); } } AstNodeContent::Declaration(_) => {} @@ -686,12 +724,14 @@ impl ty::TySubmodule { mod_name_span: _, visibility, } = submodule; + let module_arc = module.get(engines); + let module = module_arc.read().unwrap(); parent_ctx.enter_submodule( engines, mod_name, *visibility, module.span.clone(), - |submod_ctx| ty::TyModule::collect(handler, engines, submod_ctx, module), + |submod_ctx| ty::TyModule::collect(handler, engines, submod_ctx, &module), ) } @@ -709,9 +749,11 @@ impl ty::TySubmodule { mod_name_span, visibility, } = submodule; + let module_arc = module.get(engines); + let module = module_arc.read().unwrap(); parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| { let module_res = - ty::TyModule::type_check(handler, submod_ctx, engines, kind, module, build_config); + ty::TyModule::type_check(handler, submod_ctx, engines, kind, &module, build_config); module_res.map(|module| ty::TySubmodule { module, mod_name_span: mod_name_span.clone(), diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 36f14f2050f..d7edfc7b376 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -18,7 +18,7 @@ use sway_types::{span::Span, Spanned}; /// script/predicate/contract file or some library dependency whether introduced via `mod` or the /// `[dependencies]` table of a `forc` manifest. /// -/// A `Module` contains a set of all items that exist within the lexical scope via declaration or +/// A `Module` contains a set of all items that exist within its lexical scopes via declaration or /// importing, along with a map of each of its submodules. #[derive(Clone, Debug)] pub struct Module { diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index 581a630d9b6..f49e6de2952 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -31,8 +31,9 @@ impl TyProgram { ) -> Result { let mut ctx = SymbolCollectionContext::new(namespace); let ParseProgram { root, kind: _ } = parsed; - - ty::TyModule::collect(handler, engines, &mut ctx, root)?; + root.write(engines, |root| { + ty::TyModule::collect(handler, engines, &mut ctx, root) + })?; Ok(ctx) } @@ -62,12 +63,15 @@ impl TyProgram { let ParseProgram { root, kind } = parsed; + let root_arc = root.get(engines); + let root = root_arc.read().unwrap(); + let root = ty::TyModule::type_check( handler, ctx.by_ref(), engines, parsed.kind, - root, + &root, build_config, )?; diff --git a/sway-core/src/semantic_analysis/symbol_resolve.rs b/sway-core/src/semantic_analysis/symbol_resolve.rs index 60ac3da6a53..9e9443f439e 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -27,7 +27,9 @@ pub trait ResolveSymbols { impl ResolveSymbols for ParseProgram { fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { let ParseProgram { root, .. } = self; - root.resolve_symbols(handler, ctx.by_ref()); + root.write(ctx.engines(), |root| { + root.resolve_symbols(handler, ctx.by_ref()); + }); } } @@ -44,12 +46,12 @@ impl ResolveSymbols for ParseModule { } = self; // Analyze submodules first in order of evaluation previously computed by the dependency graph. - module_eval_order.iter().for_each(|eval_mod_name| { + module_eval_order.iter().for_each(|eval_mod_id| { let (_name, submodule) = submodules .iter_mut() - .find(|(submod_name, _submodule)| eval_mod_name == submod_name) + .find(|(_name, submodule)| *eval_mod_id == submodule.module) .unwrap(); - submodule.module.resolve_symbols(handler, ctx.by_ref()); + submodule.module.write(ctx.engines(), |m| m.resolve_symbols(handler, ctx.by_ref())); }); tree.root_nodes diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index ec85cf3298b..2e00484e567 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -58,7 +58,7 @@ pub enum CompileError { modules.iter().map(|ident| ident.as_str().to_string()) .collect::>() .join(", "))] - ModuleDepGraphCyclicReference { modules: Vec }, + ModuleDepGraphCyclicReference { modules: Vec }, #[error("Variable \"{var_name}\" does not exist in this scope.")] UnknownVariable { var_name: Ident, span: Span }, diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 7f4ed2a9153..ec928fa1814 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -535,21 +535,19 @@ fn parse_ast_to_tokens( .unwrap_or(true) }; - parse_program - .root - .tree - .root_nodes - .iter() - .chain( - parse_program - .root - .submodules_recursive() - .flat_map(|(_, submodule)| &submodule.module.tree.root_nodes), - ) - .filter(should_process) - .collect::>() - .par_iter() - .for_each(|n| f(n, ctx)); + parse_program.root.read(ctx.engines, |root| { + root.tree + .root_nodes + .iter() + .chain(parse_program.root.read(ctx.engines, |root| { + root.submodules_recursive() + .flat_map(|(_, submodule)| &submodule.module.tree.root_nodes) + })) + .filter(should_process) + .collect::>() + .par_iter() + .for_each(|n| f(n, ctx)); + }); } /// Parse the [ty::TyProgram] AST to populate the [TokenMap] with typed AST nodes. diff --git a/sway-module-order/Forc.lock b/sway-module-order/Forc.lock new file mode 100644 index 00000000000..ff3c1438a03 --- /dev/null +++ b/sway-module-order/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = "sway-module-order" +source = "member" diff --git a/sway-module-order/Forc.toml b/sway-module-order/Forc.toml new file mode 100644 index 00000000000..4baf46dd8ab --- /dev/null +++ b/sway-module-order/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Harsh Bajpai"] +entry = "lib.sw" +license = "Apache-2.0" +name = "sway-module-order" +implicit-std=false + +[dependencies] diff --git a/sway-module-order/src/a.sw b/sway-module-order/src/a.sw new file mode 100644 index 00000000000..2e4eb22fb20 --- /dev/null +++ b/sway-module-order/src/a.sw @@ -0,0 +1,3 @@ +library; + +pub mod inner_a; diff --git a/sway-module-order/src/a/inner_a.sw b/sway-module-order/src/a/inner_a.sw new file mode 100644 index 00000000000..a04af80a19a --- /dev/null +++ b/sway-module-order/src/a/inner_a.sw @@ -0,0 +1,3 @@ +library; + +use ::b::inner_b::foo; diff --git a/sway-module-order/src/b.sw b/sway-module-order/src/b.sw new file mode 100644 index 00000000000..3d4de365869 --- /dev/null +++ b/sway-module-order/src/b.sw @@ -0,0 +1,3 @@ +library; + +pub mod inner_b; diff --git a/sway-module-order/src/b/inner_b.sw b/sway-module-order/src/b/inner_b.sw new file mode 100644 index 00000000000..47f8176ee24 --- /dev/null +++ b/sway-module-order/src/b/inner_b.sw @@ -0,0 +1,3 @@ +library; + +pub fn foo() {} diff --git a/sway-module-order/src/lib.sw b/sway-module-order/src/lib.sw new file mode 100644 index 00000000000..d8009c7b5a3 --- /dev/null +++ b/sway-module-order/src/lib.sw @@ -0,0 +1,4 @@ +library; + +pub mod a; +pub mod b;