From e9356cc429ccce54d2dc0c443498170778fc0685 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Thu, 25 Jul 2024 11:32:40 -0300 Subject: [PATCH] Add symbol resolve context. --- sway-core/src/decl_engine/parsed_engine.rs | 24 + sway-core/src/language/call_path.rs | 6 + sway-core/src/language/parsed/declaration.rs | 33 + .../language/parsed/declaration/function.rs | 1 + .../language/parsed/declaration/impl_trait.rs | 3 +- .../src/language/parsed/expression/mod.rs | 7 + sway-core/src/lib.rs | 8 +- sway-core/src/semantic_analysis.rs | 4 +- .../ast_node/declaration/declaration.rs | 9 +- .../ast_node/declaration/impl_trait.rs | 1 + .../ast_node/expression/typed_expression.rs | 1 + .../typed_expression/method_application.rs | 1 + sway-core/src/semantic_analysis/module.rs | 2 +- .../semantic_analysis/namespace/namespace.rs | 2 +- .../src/semantic_analysis/namespace/root.rs | 11 +- .../semantic_analysis/node_dependencies.rs | 2 + sway-core/src/semantic_analysis/program.rs | 2 +- .../symbol_collection_context.rs | 27 +- .../src/semantic_analysis/symbol_resolve.rs | 646 ++++++++++++++++++ .../symbol_resolve_context.rs | 283 ++++++++ .../src/transform/to_parsed_lang/context.rs | 10 +- .../to_parsed_lang/convert_parse_tree.rs | 49 +- .../src/type_system/ast_elements/binding.rs | 68 +- sway-core/src/type_system/mod.rs | 2 +- 24 files changed, 1170 insertions(+), 32 deletions(-) create mode 100644 sway-core/src/semantic_analysis/symbol_resolve.rs create mode 100644 sway-core/src/semantic_analysis/symbol_resolve_context.rs diff --git a/sway-core/src/decl_engine/parsed_engine.rs b/sway-core/src/decl_engine/parsed_engine.rs index 8b8f84107eb..6977a86e7f6 100644 --- a/sway-core/src/decl_engine/parsed_engine.rs +++ b/sway-core/src/decl_engine/parsed_engine.rs @@ -100,6 +100,30 @@ decl_engine_insert!(enum_slab, EnumDeclaration); decl_engine_insert!(enum_variant_slab, EnumVariant); decl_engine_insert!(type_alias_slab, TypeAliasDeclaration); +macro_rules! decl_engine_replace { + ($slab:ident, $decl:ty) => { + impl ParsedDeclEngineReplace<$decl> for ParsedDeclEngine { + fn replace(&self, index: ParsedDeclId<$decl>, decl: $decl) { + self.$slab.replace(index.inner(), decl); + } + } + }; +} + +decl_engine_replace!(variable_slab, VariableDeclaration); +decl_engine_replace!(function_slab, FunctionDeclaration); +decl_engine_replace!(trait_slab, TraitDeclaration); +decl_engine_replace!(trait_fn_slab, TraitFn); +decl_engine_replace!(trait_type_slab, TraitTypeDeclaration); +decl_engine_replace!(impl_self_or_trait_slab, ImplSelfOrTrait); +decl_engine_replace!(struct_slab, StructDeclaration); +decl_engine_replace!(storage_slab, StorageDeclaration); +decl_engine_replace!(abi_slab, AbiDeclaration); +decl_engine_replace!(configurable_slab, ConfigurableDeclaration); +decl_engine_replace!(constant_slab, ConstantDeclaration); +decl_engine_replace!(enum_slab, EnumDeclaration); +decl_engine_replace!(type_alias_slab, TypeAliasDeclaration); + macro_rules! decl_engine_clear { ($($slab:ident, $decl:ty);* $(;)?) => { impl ParsedDeclEngine { diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index 7c6ba2502f7..8036d3ecab8 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -215,6 +215,12 @@ impl OrdWithEngines for CallPath { } } +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct ResolvedCallPath { + pub decl: T, + pub unresolved_call_path: CallPath, +} + impl std::convert::From for CallPath { fn from(other: Ident) -> Self { CallPath { diff --git a/sway-core/src/language/parsed/declaration.rs b/sway-core/src/language/parsed/declaration.rs index d33ec02e4d4..628fd3078ac 100644 --- a/sway-core/src/language/parsed/declaration.rs +++ b/sway-core/src/language/parsed/declaration.rs @@ -21,6 +21,10 @@ pub use r#enum::*; pub use r#struct::*; pub use r#trait::*; pub use storage::*; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; pub use type_alias::*; pub use variable::*; @@ -117,6 +121,35 @@ impl Declaration { } } + pub(crate) fn to_fn_ref( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result, ErrorEmitted> { + match self { + Declaration::FunctionDeclaration(decl_id) => Ok(*decl_id), + decl => Err(handler.emit_err(CompileError::DeclIsNotAFunction { + actually: decl.friendly_type_name().to_string(), + span: decl.span(engines), + })), + } + } + + pub(crate) fn to_struct_decl( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result, ErrorEmitted> { + match self { + Declaration::StructDeclaration(decl_id) => Ok(*decl_id), + decl => Err(handler.emit_err(CompileError::DeclIsNotAStruct { + actually: decl.friendly_type_name().to_string(), + span: decl.span(engines), + })), + } + } + + #[allow(unused)] pub(crate) fn visibility(&self, decl_engine: &ParsedDeclEngine) -> Visibility { match self { Declaration::TraitDeclaration(decl_id) => decl_engine.get_trait(decl_id).visibility, diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index 6232810f8f3..716f545ef0e 100644 --- a/sway-core/src/language/parsed/declaration/function.rs +++ b/sway-core/src/language/parsed/declaration/function.rs @@ -27,6 +27,7 @@ pub struct FunctionDeclaration { pub type_parameters: Vec, pub where_clause: Vec<(Ident, Vec)>, pub kind: FunctionDeclarationKind, + pub implementing_type: Option, } impl EqWithEngines for FunctionDeclaration {} diff --git a/sway-core/src/language/parsed/declaration/impl_trait.rs b/sway-core/src/language/parsed/declaration/impl_trait.rs index d6ba0a05535..48ba779155e 100644 --- a/sway-core/src/language/parsed/declaration/impl_trait.rs +++ b/sway-core/src/language/parsed/declaration/impl_trait.rs @@ -1,6 +1,6 @@ use super::{ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration}; use crate::{ - decl_engine::parsed_id::ParsedDeclId, + decl_engine::{parsed_id::ParsedDeclId, ParsedInterfaceDeclId}, engine_threading::{ DebugWithEngines, EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, }, @@ -69,6 +69,7 @@ pub struct ImplSelfOrTrait { pub impl_type_parameters: Vec, pub trait_name: CallPath, pub trait_type_arguments: Vec, + pub trait_decl_ref: Option, pub implementing_for: TypeArgument, pub items: Vec, // the span of the whole impl trait and block diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 73ab3a33cbb..90d41fbf19b 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -1,6 +1,7 @@ use std::{cmp::Ordering, fmt, hash::Hasher}; use crate::{ + decl_engine::parsed_id::ParsedDeclId, engine_threading::{ DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines, OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext, @@ -22,6 +23,8 @@ pub use method_name::MethodName; pub use scrutinee::*; use sway_ast::intrinsics::Intrinsic; +use super::{FunctionDeclaration, StructDeclaration}; + /// Represents a parsed, but not yet type checked, [Expression](https://en.wikipedia.org/wiki/Expression_(computer_science)). #[derive(Debug, Clone)] pub struct Expression { @@ -32,6 +35,8 @@ pub struct Expression { #[derive(Debug, Clone)] pub struct FunctionApplicationExpression { pub call_path_binding: TypeBinding, + pub resolved_call_path_binding: + Option>>>, pub arguments: Vec, } @@ -88,6 +93,8 @@ impl PartialEqWithEngines for ArrayExpression { #[derive(Debug, Clone)] pub struct StructExpression { + pub resolved_call_path_binding: + Option>>>, pub call_path_binding: TypeBinding, pub fields: Vec, } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index bdc7e683ceb..51bac2d6a24 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -34,6 +34,8 @@ pub use debug_generation::write_dwarf; use indexmap::IndexMap; use metadata::MetadataManager; use query_engine::{ModuleCacheKey, ModulePath, ProgramsCacheEntry}; +use semantic_analysis::symbol_resolve::ResolveSymbols; +use semantic_analysis::symbol_resolve_context::SymbolResolveContext; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -537,9 +539,13 @@ pub fn parsed_to_ast( let namespace = Namespace::init_root(initial_namespace); // Collect the program symbols. - let _collection_ctx = + let mut symbol_collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; + // Resolve the program symbols. + let resolve_ctx = SymbolResolveContext::new(engines, &mut symbol_collection_ctx); + parse_program.resolve_symbols(handler, resolve_ctx); + // Type check the program. let typed_program_opt = ty::TyProgram::type_check( handler, diff --git a/sway-core/src/semantic_analysis.rs b/sway-core/src/semantic_analysis.rs index 2ace7bb474c..2d3bcdcc6c3 100644 --- a/sway-core/src/semantic_analysis.rs +++ b/sway-core/src/semantic_analysis.rs @@ -2,11 +2,13 @@ pub mod ast_node; pub(crate) mod cei_pattern_analysis; pub(crate) mod coins_analysis; -pub mod symbol_collection_context; mod module; pub mod namespace; mod node_dependencies; mod program; +pub mod symbol_collection_context; +pub mod symbol_resolve; +pub mod symbol_resolve_context; mod type_check_analysis; pub(crate) mod type_check_context; mod type_check_finalization; 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 9eeb3ac74c1..1945a8ba441 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -10,9 +10,10 @@ use crate::{ }, namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ - symbol_collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments, - ConstShadowingMode, GenericShadowingMode, TypeCheckAnalysis, TypeCheckAnalysisContext, - TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, + symbol_collection_context::SymbolCollectionContext, + type_check_context::EnforceTypeArguments, ConstShadowingMode, GenericShadowingMode, + TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, + TypeCheckFinalizationContext, }, type_system::*, Engines, @@ -52,7 +53,7 @@ impl TyDecl { } parsed::Declaration::EnumVariantDeclaration(_decl) => {} parsed::Declaration::FunctionDeclaration(decl_id) => { - let fn_decl = engines.pe().get_function(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); } parsed::Declaration::TraitDeclaration(decl_id) => { 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 e65406772fa..5eca8e967d3 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 @@ -37,6 +37,7 @@ impl TyImplSelfOrTrait { impl_type_parameters, trait_name, mut trait_type_arguments, + trait_decl_ref: _, mut implementing_for, items, block_span, 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 e5f5ca57586..92d768136cc 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 @@ -193,6 +193,7 @@ impl ty::TyExpression { ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { call_path_binding, + resolved_call_path_binding: _, ref arguments, } = *function_application_expression.clone(); Self::type_check_function_application( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index c281e67da0e..99c4dea63bf 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -504,6 +504,7 @@ pub(crate) fn type_check_method_application( ]), span: Span::dummy(), }, + resolved_call_path_binding: None, arguments: vec![ Expression { kind: ExpressionKind::Literal(Literal::B256([0u8; 32])), diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 3247e95833e..f8910773695 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -24,8 +24,8 @@ use crate::{ }; use super::{ - symbol_collection_context::SymbolCollectionContext, declaration::auto_impl::{self, EncodingAutoImplContext}, + symbol_collection_context::SymbolCollectionContext, }; #[derive(Clone, Debug)] diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 7a8b00e4304..a3aed9205c9 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -310,7 +310,7 @@ impl Namespace { } /// Pushes a new submodule to the namespace's module hierarchy. - pub fn push_new_submodule( + pub fn push_submodule( &mut self, engines: &Engines, mod_name: Ident, diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index c84b004e7c8..7c238054506 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -4,7 +4,7 @@ use super::{ module::Module, namespace::Namespace, trait_map::TraitMap, Ident, ResolvedTraitImplItem, }; use crate::{ - decl_engine::DeclRef, + decl_engine::{DeclEngine, DeclRef}, engine_threading::*, language::{ parsed::*, @@ -69,6 +69,15 @@ impl ResolvedDeclaration { } } + pub fn resolve_parsed(self, decl_engine: &DeclEngine) -> Declaration { + match self { + ResolvedDeclaration::Parsed(decl) => decl, + ResolvedDeclaration::Typed(ty_decl) => ty_decl + .get_parsed_decl(decl_engine) + .expect("expecting valid parsed declaration"), + } + } + pub fn expect_parsed(self) -> Declaration { match self { ResolvedDeclaration::Parsed(decl) => decl, diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 01b299c0792..1b8b7cc1930 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -550,6 +550,7 @@ impl Dependencies { ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { call_path_binding, + resolved_call_path_binding: _, arguments, } = &**function_application_expression; self.gather_from_call_path(&call_path_binding.inner, false, true) @@ -591,6 +592,7 @@ impl Dependencies { ExpressionKind::Struct(struct_expression) => { let StructExpression { call_path_binding, + resolved_call_path_binding: _, fields, } = &**struct_expression; self.gather_from_call_path(&call_path_binding.inner, false, false) diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index 07058ac46a9..ab83749d2f5 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -19,7 +19,7 @@ use super::{ }; impl TyProgram { - /// Collects the given parsed program to produce a symbol map and module evaluation order. + /// Collects the given parsed program to produce a symbol maps. /// /// The given `initial_namespace` acts as an initial state for each module within this program. /// It should contain a submodule for each library package dependency. diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index 8fb8937fc47..c072dce9cec 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -37,14 +37,33 @@ impl SymbolCollectionContext { /// Scope the `CollectionContext` with a new lexical scope. pub fn scoped( - mut self, + &mut self, engines: &Engines, - with_scoped_ctx: impl FnOnce(SymbolCollectionContext) -> Result, + with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> Result { self.namespace .module_mut(engines) .write(engines, |m| m.push_new_lexical_scope()); - let ret = with_scoped_ctx(self.clone()); + let ret = with_scoped_ctx(self); + self.namespace + .module_mut(engines) + .write(engines, |m| m.pop_lexical_scope()); + ret + } + + /// Enter the lexical scope 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 { + self.namespace + .module_mut(engines) + .write(engines, |m| m.push_new_lexical_scope()); + let ret = with_ctx(self); self.namespace .module_mut(engines) .write(engines, |m| m.pop_lexical_scope()); @@ -64,7 +83,7 @@ impl SymbolCollectionContext { with_submod_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T, ) -> T { self.namespace - .push_new_submodule(engines, mod_name, visibility, module_span); + .push_submodule(engines, mod_name, visibility, module_span); //let Self { namespace, .. } = self; //let mut submod_ns = namespace.enter_submodule(mod_name, visibility, module_span); let ret = with_submod_ctx(self); diff --git a/sway-core/src/semantic_analysis/symbol_resolve.rs b/sway-core/src/semantic_analysis/symbol_resolve.rs new file mode 100644 index 00000000000..f20b251cf8e --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -0,0 +1,646 @@ +use sway_error::handler::Handler; + +use crate::{ + ast_elements::binding::SymbolResolveTypeBinding, + decl_engine::{parsed_engine::ParsedDeclEngineReplace, parsed_id::ParsedDeclId}, + language::{ + parsed::{ + AbiDeclaration, AstNode, AstNodeContent, CodeBlock, ConfigurableDeclaration, + ConstantDeclaration, Declaration, EnumDeclaration, EnumVariant, Expression, + ExpressionKind, FunctionDeclaration, FunctionParameter, ImplItem, ImplSelfOrTrait, + ParseModule, ParseProgram, ReassignmentTarget, Scrutinee, StorageDeclaration, + StorageEntry, StructDeclaration, StructExpressionField, StructField, + StructScrutineeField, Supertrait, TraitDeclaration, TraitFn, TraitItem, + TraitTypeDeclaration, TypeAliasDeclaration, VariableDeclaration, + }, + CallPath, CallPathTree, ResolvedCallPath, + }, + TraitConstraint, TypeArgument, TypeBinding, TypeParameter, +}; + +use super::symbol_resolve_context::SymbolResolveContext; + +pub trait ResolveSymbols { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext); +} + +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()); + } +} + +impl ResolveSymbols for ParseModule { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + let ParseModule { + submodules, + tree, + module_eval_order, + attributes: _, + span: _, + hash: _, + .. + } = self; + + // Analyze submodules first in order of evaluation previously computed by the dependency graph. + module_eval_order.iter().for_each(|eval_mod_name| { + let (_name, submodule) = submodules + .iter_mut() + .find(|(submod_name, _submodule)| eval_mod_name == submod_name) + .unwrap(); + submodule.module.resolve_symbols(handler, ctx.by_ref()); + }); + + tree.root_nodes + .iter_mut() + .for_each(|node| node.resolve_symbols(handler, ctx.by_ref())) + } +} + +impl ResolveSymbols for AstNode { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match &mut self.content { + AstNodeContent::UseStatement(_) => {} + AstNodeContent::Declaration(decl) => decl.resolve_symbols(handler, ctx), + AstNodeContent::Expression(expr) => expr.resolve_symbols(handler, ctx), + AstNodeContent::IncludeStatement(_) => {} + AstNodeContent::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for Declaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match self { + Declaration::VariableDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::FunctionDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::StructDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::EnumDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::EnumVariantDeclaration(_decl) => unreachable!(), + Declaration::ImplSelfOrTrait(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::AbiDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::ConstantDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::StorageDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TypeAliasDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitTypeDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitFnDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::ConfigurableDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + } + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut var_decl = pe.get_variable(self).as_ref().clone(); + var_decl.body.resolve_symbols(handler, ctx); + pe.replace(*self, var_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut fn_decl = pe.get_function(self).as_ref().clone(); + fn_decl.body.resolve_symbols(handler, ctx); + pe.replace(*self, fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_decl = ctx.engines().pe().get_trait(self).as_ref().clone(); + trait_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut struct_decl = ctx.engines().pe().get_struct(self).as_ref().clone(); + struct_decl.resolve_symbols(handler, ctx); + pe.replace(*self, struct_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut enum_decl = ctx.engines().pe().get_enum(self).as_ref().clone(); + enum_decl.resolve_symbols(handler, ctx); + pe.replace(*self, enum_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut configurable_decl = ctx.engines().pe().get_configurable(self).as_ref().clone(); + configurable_decl.resolve_symbols(handler, ctx); + pe.replace(*self, configurable_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut constant_decl = ctx.engines().pe().get_constant(self).as_ref().clone(); + constant_decl.resolve_symbols(handler, ctx); + pe.replace(*self, constant_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_type_decl = ctx.engines().pe().get_trait_type(self).as_ref().clone(); + trait_type_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_type_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_fn_decl = ctx.engines().pe().get_trait_fn(self).as_ref().clone(); + trait_fn_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut impl_self_or_trait = ctx + .engines() + .pe() + .get_impl_self_or_trait(self) + .as_ref() + .clone(); + impl_self_or_trait.resolve_symbols(handler, ctx); + pe.replace(*self, impl_self_or_trait); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut abi_decl = ctx.engines().pe().get_abi(self).as_ref().clone(); + abi_decl.resolve_symbols(handler, ctx); + pe.replace(*self, abi_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut storage_decl = ctx.engines().pe().get_storage(self).as_ref().clone(); + storage_decl.resolve_symbols(handler, ctx); + pe.replace(*self, storage_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut type_alias = ctx.engines().pe().get_type_alias(self).as_ref().clone(); + type_alias.resolve_symbols(handler, ctx); + pe.replace(*self, type_alias); + } +} + +impl ResolveSymbols for ConfigurableDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_ascription.resolve_symbols(handler, ctx.by_ref()); + if let Some(value) = self.value.as_mut() { + value.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for ConstantDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_ascription.resolve_symbols(handler, ctx.by_ref()); + if let Some(value) = self.value.as_mut() { + value.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.fields + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + self.type_parameters + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for StructField { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for EnumDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_parameters + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + self.variants + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for EnumVariant { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for TraitDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.interface_surface + .iter_mut() + .for_each(|item| item.resolve_symbols(handler, ctx.by_ref())); + self.methods + .iter_mut() + .for_each(|m| m.resolve_symbols(handler, ctx.by_ref())); + self.supertraits + .iter_mut() + .for_each(|st| st.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for AbiDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.interface_surface + .iter_mut() + .for_each(|item| item.resolve_symbols(handler, ctx.by_ref())); + self.methods + .iter_mut() + .for_each(|m| m.resolve_symbols(handler, ctx.by_ref())); + self.supertraits + .iter_mut() + .for_each(|st| st.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for TraitItem { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + TraitItem::TraitFn(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Constant(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Type(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for TraitFn { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + self.return_type.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for Supertrait { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.name.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for FunctionParameter { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for ImplSelfOrTrait { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.impl_type_parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + self.trait_name.resolve_symbols(handler, ctx.by_ref()); + self.trait_type_arguments + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + self.implementing_for.resolve_symbols(handler, ctx.by_ref()); + self.items + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for ImplItem { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match self { + ImplItem::Fn(decl_id) => decl_id.resolve_symbols(handler, ctx), + ImplItem::Constant(decl_id) => decl_id.resolve_symbols(handler, ctx), + ImplItem::Type(decl_id) => decl_id.resolve_symbols(handler, ctx), + } + } +} + +impl ResolveSymbols for TraitTypeDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + if let Some(ty) = self.ty_opt.as_mut() { + ty.resolve_symbols(handler, ctx) + } + } +} + +impl ResolveSymbols for StorageDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.entries + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for StorageEntry { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + StorageEntry::Namespace(ref mut ns) => { + ns.entries + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())); + } + StorageEntry::Field(ref mut f) => { + f.type_argument.resolve_symbols(handler, ctx.by_ref()); + f.initializer.resolve_symbols(handler, ctx.by_ref()); + } + } + } +} + +impl ResolveSymbols for TypeAliasDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.ty.resolve_symbols(handler, ctx) + } +} + +impl ResolveSymbols for TypeArgument { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + if let Some(call_path) = self.call_path_tree.as_mut() { + call_path.resolve_symbols(handler, ctx); + } + } +} + +impl ResolveSymbols for TypeParameter { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.trait_constraints + .iter_mut() + .for_each(|tc| tc.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for TraitConstraint { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.trait_name.resolve_symbols(handler, ctx.by_ref()); + self.type_arguments + .iter_mut() + .for_each(|tc| tc.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for CallPath { + fn resolve_symbols(&mut self, _handler: &Handler, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CallPathTree { + fn resolve_symbols(&mut self, _handler: &Handler, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CodeBlock { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + for expr in self.contents.iter_mut() { + expr.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructExpressionField { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.value.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for Scrutinee { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + Scrutinee::Or { + ref mut elems, + span: _, + } => elems + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())), + Scrutinee::CatchAll { .. } => {} + Scrutinee::Literal { .. } => {} + Scrutinee::Variable { .. } => {} + Scrutinee::AmbiguousSingleIdent(_) => {} + Scrutinee::StructScrutinee { + struct_name, + fields, + span: _, + } => { + struct_name.resolve_symbols(handler, ctx.by_ref()); + fields + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())) + } + Scrutinee::EnumScrutinee { + call_path, + value, + span: _, + } => { + call_path.resolve_symbols(handler, ctx.by_ref()); + value.resolve_symbols(handler, ctx.by_ref()); + } + Scrutinee::Tuple { elems, span: _ } => { + elems + .iter_mut() + .for_each(|s| s.resolve_symbols(handler, ctx.by_ref())); + } + Scrutinee::Error { .. } => {} + } + } +} + +impl ResolveSymbols for StructScrutineeField { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + StructScrutineeField::Rest { .. } => {} + StructScrutineeField::Field { + field: _, + scrutinee, + span: _, + } => { + if let Some(scrutinee) = scrutinee.as_mut() { + scrutinee.resolve_symbols(handler, ctx.by_ref()); + } + } + } + } +} + +impl ResolveSymbols for Expression { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.kind.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for ExpressionKind { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + ExpressionKind::Error(_, _) => {} + ExpressionKind::Literal(_) => {} + ExpressionKind::AmbiguousPathExpression(_) => {} + ExpressionKind::FunctionApplication(expr) => { + let result = SymbolResolveTypeBinding::resolve_symbol( + &mut expr.call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + if let Ok(result) = result { + expr.resolved_call_path_binding = Some(TypeBinding::< + ResolvedCallPath>, + > { + inner: ResolvedCallPath { + decl: result, + unresolved_call_path: expr.call_path_binding.inner.clone(), + }, + span: expr.call_path_binding.span.clone(), + type_arguments: expr.call_path_binding.type_arguments.clone(), + }); + } + expr.arguments + .iter_mut() + .for_each(|a| a.resolve_symbols(handler, ctx.by_ref())) + } + ExpressionKind::LazyOperator(expr) => { + expr.lhs.resolve_symbols(handler, ctx.by_ref()); + expr.rhs.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::AmbiguousVariableExpression(_) => {} + ExpressionKind::Variable(_) => {} + ExpressionKind::Tuple(exprs) => { + exprs + .iter_mut() + .for_each(|expr| expr.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::TupleIndex(expr) => { + expr.prefix.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::Array(expr) => expr + .contents + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())), + ExpressionKind::Struct(expr) => { + expr.call_path_binding + .resolve_symbols(handler, ctx.by_ref()); + let result = SymbolResolveTypeBinding::resolve_symbol( + &mut expr.call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + if let Ok(result) = result { + expr.resolved_call_path_binding = Some(TypeBinding::< + ResolvedCallPath>, + > { + inner: ResolvedCallPath { + decl: result, + unresolved_call_path: expr.call_path_binding.inner.clone(), + }, + span: expr.call_path_binding.span.clone(), + type_arguments: expr.call_path_binding.type_arguments.clone(), + }); + } + } + ExpressionKind::CodeBlock(block) => { + block + .contents + .iter_mut() + .for_each(|node| node.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::If(expr) => { + expr.condition.resolve_symbols(handler, ctx.by_ref()); + expr.then.resolve_symbols(handler, ctx.by_ref()); + if let Some(r#else) = expr.r#else.as_mut() { + r#else.resolve_symbols(handler, ctx.by_ref()); + } + } + ExpressionKind::Match(expr) => { + expr.value.resolve_symbols(handler, ctx.by_ref()); + expr.branches.iter_mut().for_each(|branch| { + branch.scrutinee.resolve_symbols(handler, ctx.by_ref()); + branch.result.resolve_symbols(handler, ctx.by_ref()); + }); + } + ExpressionKind::Asm(asm_expr) => asm_expr.registers.iter_mut().for_each(|reg| { + if let Some(initializer) = reg.initializer.as_mut() { + initializer.resolve_symbols(handler, ctx.by_ref()); + } + }), + ExpressionKind::MethodApplication(expr) => { + expr.method_name_binding + .resolve_symbols(handler, ctx.by_ref()); + expr.contract_call_params + .iter_mut() + .for_each(|field| field.resolve_symbols(handler, ctx.by_ref())); + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::Subfield(expr) => expr.prefix.resolve_symbols(handler, ctx), + ExpressionKind::DelineatedPath(expr) => { + expr.call_path_binding.resolve_symbols(handler, ctx) + } + ExpressionKind::AbiCast(expr) => { + expr.abi_name.resolve_symbols(handler, ctx.by_ref()); + expr.address.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ArrayIndex(expr) => { + expr.index.resolve_symbols(handler, ctx.by_ref()); + expr.prefix.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::StorageAccess(_expr) => {} + ExpressionKind::IntrinsicFunction(expr) => { + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())); + expr.kind_binding.resolve_symbols(handler, ctx); + } + ExpressionKind::WhileLoop(expr) => { + expr.condition.resolve_symbols(handler, ctx.by_ref()); + expr.body.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ForLoop(expr) => expr.desugared.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Break => {} + ExpressionKind::Continue => {} + ExpressionKind::Reassignment(expr) => { + match &mut expr.lhs { + ReassignmentTarget::ElementAccess(expr) => { + expr.resolve_symbols(handler, ctx.by_ref()) + } + ReassignmentTarget::Deref(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + }; + expr.rhs.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ImplicitReturn(expr) => expr.resolve_symbols(handler, ctx), + ExpressionKind::Return(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Ref(expr) => expr.value.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Deref(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + } + } +} diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs new file mode 100644 index 00000000000..c2558697fe8 --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -0,0 +1,283 @@ +use crate::{ + engine_threading::*, + language::{CallPath, Visibility}, + namespace::{ModulePath, ResolvedDeclaration}, + semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, + type_system::TypeId, +}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{span::Span, Ident, Spanned}; +use sway_utils::iter_prefixes; + +use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; + +/// Contextual state tracked and accumulated throughout symbol resolving. +pub struct SymbolResolveContext<'a> { + /// The namespace context accumulated throughout symbol resolving. + /// + /// Internally, this includes: + /// + /// - The `root` module from which all other modules maybe be accessed using absolute paths. + /// - The `init` module used to initialize submodule namespaces. + /// - A `mod_path` that represents the current module being type-checked. This is automatically + /// updated upon entering/exiting submodules via the `enter_submodule` method. + pub(crate) engines: &'a Engines, + pub(crate) symbol_collection_ctx: &'a mut SymbolCollectionContext, + + // The following set of fields are intentionally private. When a `SymbolResolveContext` is passed + // into a new node during symbol resolving, these fields should be updated using the `with_*` + // methods which provides a new `SymbolResolveContext`, ensuring we don't leak our changes into + // the parent nodes. + /// While symbol resolving an `impl` (whether inherent or for a `trait`/`abi`) this represents the + /// type for which we are implementing. For example in `impl Foo {}` or `impl Trait for Foo + /// {}`, this represents the type ID of `Foo`. + self_type: Option, + /// Whether or not a const declaration shadows previous const declarations sequentially. + /// + /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`. + const_shadowing_mode: ConstShadowingMode, + /// Whether or not a generic type parameters shadows previous generic type parameters. + /// + /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation. + generic_shadowing_mode: GenericShadowingMode, +} + +impl<'a> SymbolResolveContext<'a> { + /// Initialize a symbol resolving context with a namespace. + pub fn new( + engines: &'a Engines, + symbol_collection_ctx: &'a mut SymbolCollectionContext, + ) -> Self { + Self { + engines, + symbol_collection_ctx, + self_type: None, + const_shadowing_mode: ConstShadowingMode::ItemStyle, + generic_shadowing_mode: GenericShadowingMode::Disallow, + } + } + + /// Create a new context that mutably borrows the inner `namespace` with a lifetime bound by + /// `self`. + /// + /// This is particularly useful when symbol resolving a node that has more than one child node + /// (very often the case). By taking the context with the namespace lifetime bound to `self` + /// rather than the original namespace reference, we instead restrict the returned context to + /// the local scope and avoid consuming the original context when providing context to the + /// first visited child node. + pub fn by_ref(&mut self) -> SymbolResolveContext<'_> { + SymbolResolveContext { + engines: self.engines, + symbol_collection_ctx: self.symbol_collection_ctx, + self_type: self.self_type, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + } + } + + /// Scope the `SymbolResolveContext` with a new namespace lexical scope. + pub fn scoped( + self, + with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result, + ) -> Result { + let engines = self.engines; + self.symbol_collection_ctx + .enter_lexical_scope(engines, |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 + /// symbol resolving its content. + /// + /// Returns the result of the given `with_submod_ctx` function. + pub fn enter_submodule( + self, + mod_name: Ident, + visibility: Visibility, + module_span: Span, + with_submod_ctx: impl FnOnce(SymbolResolveContext) -> T, + ) -> T { + let engines = self.engines; + self.symbol_collection_ctx.enter_submodule( + engines, + mod_name, + visibility, + module_span, + |submod_collect_ctx| { + let submod_ctx = SymbolResolveContext::new(engines, submod_collect_ctx); + with_submod_ctx(submod_ctx) + }, + ) + } + + /// Returns a mutable reference to the current namespace. + pub fn namespace_mut(&mut self) -> &mut Namespace { + &mut self.symbol_collection_ctx.namespace + } + + /// Returns a reference to the current namespace. + pub fn namespace(&self) -> &Namespace { + &self.symbol_collection_ctx.namespace + } + + /// Map this `SymbolResolveContext` instance to a new one with the given const shadowing `mode`. + #[allow(unused)] + pub(crate) fn with_const_shadowing_mode( + self, + const_shadowing_mode: ConstShadowingMode, + ) -> Self { + Self { + const_shadowing_mode, + ..self + } + } + + /// Map this `SymbolResolveContext` instance to a new one with the given generic shadowing `mode`. + #[allow(unused)] + pub(crate) fn with_generic_shadowing_mode( + self, + generic_shadowing_mode: GenericShadowingMode, + ) -> Self { + Self { + generic_shadowing_mode, + ..self + } + } + + // A set of accessor methods. We do this rather than making the fields `pub` in order to ensure + // that these are only updated via the `with_*` methods that produce a new `SymbolResolveContext`. + #[allow(unused)] + pub(crate) fn self_type(&self) -> Option { + self.self_type + } + + #[allow(unused)] + pub(crate) fn const_shadowing_mode(&self) -> ConstShadowingMode { + self.const_shadowing_mode + } + + #[allow(unused)] + pub(crate) fn generic_shadowing_mode(&self) -> GenericShadowingMode { + self.generic_shadowing_mode + } + + /// Get the engines needed for engine threading. + pub(crate) fn engines(&self) -> &'a Engines { + self.engines + } + + /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`. + pub(crate) fn resolve_call_path_with_visibility_check( + &self, + handler: &Handler, + call_path: &CallPath, + ) -> Result { + self.resolve_call_path_with_visibility_check_and_modpath( + handler, + &self.namespace().mod_path, + call_path, + ) + } + + /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. + /// + /// This will concatenate the `mod_path` with the `call_path`'s prefixes and + /// then calling `resolve_symbol` with the resulting path and call_path's suffix. + /// + /// The `mod_path` is significant here as we assume the resolution is done within the + /// context of the module pointed to by `mod_path` and will only check the call path prefixes + /// and the symbol's own visibility. + pub(crate) fn resolve_call_path_with_visibility_check_and_modpath( + &self, + handler: &Handler, + mod_path: &ModulePath, + call_path: &CallPath, + ) -> Result { + let (decl, mod_path) = self.namespace().root.resolve_call_path_and_mod_path( + handler, + self.engines, + mod_path, + call_path, + self.self_type, + )?; + + // In case there is no mod path we don't need to check visibility + if mod_path.is_empty() { + return Ok(decl); + } + + // In case there are no prefixes we don't need to check visibility + if call_path.prefixes.is_empty() { + return Ok(decl); + } + + // check the visibility of the call path elements + // we don't check the first prefix because direct children are always accessible + for prefix in iter_prefixes(&call_path.prefixes).skip(1) { + let module = self.namespace().lookup_submodule_from_absolute_path( + handler, + self.engines(), + prefix, + )?; + if module.visibility().is_private() { + let prefix_last = prefix[prefix.len() - 1].clone(); + handler.emit_err(CompileError::ImportPrivateModule { + span: prefix_last.span(), + name: prefix_last, + }); + } + } + + // check the visibility of the symbol itself + if !decl.visibility(self.engines).is_public() { + handler.emit_err(CompileError::ImportPrivateSymbol { + name: call_path.suffix.clone(), + span: call_path.suffix.span(), + }); + } + + Ok(decl) + } +} + +/// This type is used to denote if, during monomorphization, the compiler +/// should enforce that type arguments be provided. An example of that +/// might be this: +/// +/// ```ignore +/// struct Point { +/// x: u64, +/// y: u64 +/// } +/// +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +/// +/// `EnforceTypeArguments` would require that the type annotations +/// for `p1` and `p2` contain `<...>`. This is to avoid ambiguous definitions: +/// +/// ```ignore +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +#[allow(dead_code)] +#[derive(Clone, Copy)] +pub(crate) enum EnforceTypeArguments { + Yes, + No, +} diff --git a/sway-core/src/transform/to_parsed_lang/context.rs b/sway-core/src/transform/to_parsed_lang/context.rs index 4358abec4f0..dcd661a685b 100644 --- a/sway-core/src/transform/to_parsed_lang/context.rs +++ b/sway-core/src/transform/to_parsed_lang/context.rs @@ -1,4 +1,8 @@ -use crate::{build_config::ExperimentalFlags, language::parsed::TreeType, BuildTarget}; +use crate::{ + build_config::ExperimentalFlags, + language::parsed::{Declaration, TreeType}, + BuildTarget, +}; pub struct Context { pub experimental: ExperimentalFlags, @@ -21,6 +25,9 @@ pub struct Context { /// The program type. program_type: Option, + + /// Keeps track of the implementing type as we convert the tree. + pub(crate) implementing_type: Option, } impl Context { @@ -34,6 +41,7 @@ impl Context { destructured_tuple_unique_suffix: std::default::Default::default(), match_expression_matched_value_unique_suffix: std::default::Default::default(), program_type: std::default::Default::default(), + implementing_type: None, } } 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 4e70c070b5e..f15e204b846 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 @@ -174,9 +174,17 @@ pub fn item_to_ast_nodes( .into_iter() .map(AstNodeContent::UseStatement) .collect(), - ItemKind::Struct(item_struct) => decl(Declaration::StructDeclaration( - item_struct_to_struct_declaration(context, handler, engines, item_struct, attributes)?, - )), + ItemKind::Struct(item_struct) => { + let struct_decl = Declaration::StructDeclaration(item_struct_to_struct_declaration( + context, + handler, + engines, + item_struct, + attributes, + )?); + context.implementing_type = Some(struct_decl.clone()); + decl(struct_decl) + } ItemKind::Enum(item_enum) => decl(Declaration::EnumDeclaration( item_enum_to_enum_declaration(context, handler, engines, item_enum, attributes)?, )), @@ -203,15 +211,25 @@ pub fn item_to_ast_nodes( function_declaration_decl_id, )) } - ItemKind::Trait(item_trait) => decl(Declaration::TraitDeclaration( - item_trait_to_trait_declaration(context, handler, engines, item_trait, attributes)?, - )), - ItemKind::Impl(item_impl) => decl(item_impl_to_declaration( - context, handler, engines, item_impl, - )?), - ItemKind::Abi(item_abi) => decl(Declaration::AbiDeclaration(item_abi_to_abi_declaration( - context, handler, engines, item_abi, attributes, - )?)), + ItemKind::Trait(item_trait) => { + let trait_decl = Declaration::TraitDeclaration(item_trait_to_trait_declaration( + context, handler, engines, item_trait, attributes, + )?); + context.implementing_type = Some(trait_decl.clone()); + decl(trait_decl) + } + ItemKind::Impl(item_impl) => { + let impl_decl = item_impl_to_declaration(context, handler, engines, item_impl)?; + context.implementing_type = Some(impl_decl.clone()); + decl(impl_decl) + } + ItemKind::Abi(item_abi) => { + let abi_decl = Declaration::AbiDeclaration(item_abi_to_abi_declaration( + context, handler, engines, item_abi, attributes, + )?); + context.implementing_type = Some(abi_decl.clone()); + decl(abi_decl) + } ItemKind::Const(item_const) => decl(Declaration::ConstantDeclaration({ item_const_to_constant_declaration( context, handler, engines, item_const, attributes, true, @@ -545,6 +563,7 @@ pub fn item_fn_to_function_declaration( }; let kind = override_kind.unwrap_or(kind); + let implementing_type = context.implementing_type.clone(); let fn_decl = FunctionDeclaration { purity: get_attributed_purity(context, handler, &attributes)?, @@ -578,6 +597,7 @@ pub fn item_fn_to_function_declaration( .transpose()? .unwrap_or(vec![]), kind, + implementing_type, }; let decl_id = engines.pe().insert(fn_decl); Ok(decl_id) @@ -778,6 +798,7 @@ pub fn item_impl_to_declaration( impl_type_parameters, trait_name: trait_name.to_call_path(handler)?, trait_type_arguments, + trait_decl_ref: None, implementing_for, items, block_span, @@ -796,6 +817,7 @@ pub fn item_impl_to_declaration( prefixes: vec![], suffix: BaseIdent::dummy(), }, + trait_decl_ref: None, trait_type_arguments: vec![], implementing_for, impl_type_parameters, @@ -1761,6 +1783,7 @@ fn struct_path_and_fields_to_struct_expression( }; Ok(Box::new(StructExpression { call_path_binding, + resolved_call_path_binding: None, fields, })) } @@ -1909,6 +1932,7 @@ fn expr_func_app_to_expression_kind( type_arguments: TypeArgs::Regular(type_arguments), span: span.clone(), }, + resolved_call_path_binding: None, arguments, }, )), @@ -2605,6 +2629,7 @@ fn configurable_field_to_configurable_declaration( type_arguments: TypeArgs::Regular(vec![type_ascription.clone()]), span: span.clone(), }, + resolved_call_path_binding: None, arguments: vec![value], })); Expression { diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 699a99470ba..a391a9e1c67 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -3,10 +3,18 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ - decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef}, + decl_engine::{ + parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef, + }, engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}, - language::{ty, CallPath, QualifiedCallPath}, - semantic_analysis::{type_check_context::EnforceTypeArguments, TypeCheckContext}, + language::{ + parsed::{FunctionDeclaration, StructDeclaration}, + ty, CallPath, QualifiedCallPath, + }, + semantic_analysis::{ + symbol_resolve::ResolveSymbols, symbol_resolve_context::SymbolResolveContext, + type_check_context::EnforceTypeArguments, TypeCheckContext, + }, type_system::priv_prelude::*, Ident, }; @@ -184,6 +192,17 @@ impl TypeBinding { span: self.span, } } + + pub(crate) fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext<'_>) { + match self.type_arguments { + TypeArgs::Regular(ref mut args) => args + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())), + TypeArgs::Prefix(ref mut args) => args + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())), + } + } } impl TypeBinding> { @@ -249,6 +268,32 @@ pub(crate) trait TypeCheckTypeBinding { ) -> Result<(DeclRef>, Option, Option), ErrorEmitted>; } +#[allow(clippy::type_complexity)] +pub trait SymbolResolveTypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted>; +} + +impl SymbolResolveTypeBinding for TypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted> { + let engines = ctx.engines(); + // Grab the declaration. + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; + // Check to see if this is a function declaration. + let fn_decl = unknown_decl + .resolve_parsed(engines.de()) + .to_fn_ref(handler, engines)?; + Ok(fn_decl) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -309,6 +354,23 @@ impl TypeCheckTypeBinding for TypeBinding { } } +impl SymbolResolveTypeBinding for TypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted> { + let engines = ctx.engines(); + // Grab the declaration. + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; + // Check to see if this is a struct declaration. + let struct_decl_id = unknown_decl + .resolve_parsed(engines.de()) + .to_struct_decl(handler, engines)?; + Ok(struct_decl_id) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index 85f21f9e132..7a3a50d35fe 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -1,4 +1,4 @@ -mod ast_elements; +pub(crate) mod ast_elements; mod engine; mod id; mod info;