diff --git a/sway-core/src/decl_engine/interface_decl_id.rs b/sway-core/src/decl_engine/interface_decl_id.rs index 642017fc07b..b6253b482eb 100644 --- a/sway-core/src/decl_engine/interface_decl_id.rs +++ b/sway-core/src/decl_engine/interface_decl_id.rs @@ -1,4 +1,30 @@ -use crate::{decl_engine::*, language::ty}; +use crate::{ + decl_engine::*, + language::{ + parsed::{AbiDeclaration, TraitDeclaration}, + ty, + }, +}; + +use super::parsed_id::ParsedDeclId; + +#[derive(Debug, Eq, PartialEq, Hash, Clone)] +pub enum ParsedInterfaceDeclId { + Abi(ParsedDeclId), + Trait(ParsedDeclId), +} + +impl From> for ParsedInterfaceDeclId { + fn from(id: ParsedDeclId) -> Self { + Self::Abi(id) + } +} + +impl From> for ParsedInterfaceDeclId { + fn from(id: ParsedDeclId) -> Self { + Self::Trait(id) + } +} #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub enum InterfaceDeclId { diff --git a/sway-core/src/decl_engine/parsed_engine.rs b/sway-core/src/decl_engine/parsed_engine.rs index 463117735fd..853407001f3 100644 --- a/sway-core/src/decl_engine/parsed_engine.rs +++ b/sway-core/src/decl_engine/parsed_engine.rs @@ -104,6 +104,30 @@ decl_engine_insert!(constant_slab, ConstantDeclaration); decl_engine_insert!(enum_slab, EnumDeclaration); 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_trait_slab, ImplTrait); +decl_engine_replace!(impl_self_slab, ImplSelf); +decl_engine_replace!(struct_slab, StructDeclaration); +decl_engine_replace!(storage_slab, StorageDeclaration); +decl_engine_replace!(abi_slab, AbiDeclaration); +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 85e2b610f11..db3dbc666b3 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -187,6 +187,12 @@ pub struct CallPath { pub is_absolute: bool, } +#[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 3eb784956ab..d0cc2342787 100644 --- a/sway-core/src/language/parsed/declaration.rs +++ b/sway-core/src/language/parsed/declaration.rs @@ -19,14 +19,18 @@ 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::Spanned; pub use type_alias::*; pub use variable::*; use crate::{ - decl_engine::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId}, + decl_engine::{parsed_engine::{ParsedDeclEngineGet, ParsedDeclEngine}, parsed_id::ParsedDeclId}, engine_threading::{DebugWithEngines, DisplayWithEngines}, - Engines, + Engines, language::Visibility, }; #[derive(Debug, Clone)] @@ -95,6 +99,58 @@ impl Declaration { TraitTypeDeclaration(decl_id) => pe.get_trait_type(decl_id).span(), } } + + 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, + Declaration::ConstantDeclaration(decl_id) => { + decl_engine.get_constant(decl_id).visibility + } + Declaration::StructDeclaration(decl_id) => decl_engine.get_struct(decl_id).visibility, + Declaration::EnumDeclaration(decl_id) => decl_engine.get_enum(decl_id).visibility, + Declaration::FunctionDeclaration(decl_id) => { + decl_engine.get_function(decl_id).visibility + } + Declaration::TypeAliasDeclaration(decl_id) => { + decl_engine.get_type_alias(decl_id).visibility + } + Declaration::VariableDeclaration(_decl_id) => Visibility::Private, + Declaration::ImplTrait(_) + | Declaration::ImplSelf(_) + | Declaration::StorageDeclaration(_) + | Declaration::AbiDeclaration(_) + | Declaration::TraitTypeDeclaration(_) => Visibility::Public, + } + } } impl DisplayWithEngines for Declaration { diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index ab7c69c5817..b4d99b4f44d 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 DebugWithEngines 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 98be0491077..bec44a95ca8 100644 --- a/sway-core/src/language/parsed/declaration/impl_trait.rs +++ b/sway-core/src/language/parsed/declaration/impl_trait.rs @@ -1,7 +1,10 @@ use super::{ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration}; use crate::{ - decl_engine::parsed_id::ParsedDeclId, engine_threading::DebugWithEngines, language::CallPath, - type_system::TypeArgument, Engines, TypeParameter, + decl_engine::{parsed_id::ParsedDeclId, ParsedInterfaceDeclId}, + engine_threading::DebugWithEngines, + language::CallPath, + type_system::TypeArgument, + Engines, TypeParameter, }; use sway_types::{span::Span, Named, Spanned}; @@ -47,6 +50,7 @@ pub struct ImplTrait { 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 7b55a838cda..8af283773d0 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, } @@ -57,6 +62,8 @@ pub struct 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 48ba813803a..2945a144068 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}; @@ -536,8 +538,13 @@ pub fn parsed_to_ast( build_module_dep_graph(handler, &mut parse_program.root)?; // Collect the program symbols. - let _collection_ctx = + let mut symbol_collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, initial_namespace.clone())?; + println!("{:#?}", symbol_collection_ctx.namespace); + + // 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( 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 06e9c3f9d14..325a84f7240 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, 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 23072debd37..818af7207bb 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 TyImplTrait { 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 cc0f2cce114..f8d18cf808e 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 @@ -194,6 +194,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 d5618f44d89..675df061972 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 @@ -479,6 +479,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 77fc12ae350..45c3d177f9d 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/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index d44d859df39..94bd416beba 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -12,7 +12,7 @@ pub use lexical_scope::{Items, LexicalScope, LexicalScopeId, LexicalScopePath}; pub use module::Module; pub use namespace::Namespace; pub use namespace::TryInsertingTraitImplOnFailure; -pub use root::Root; +pub use root::{ResolvedDeclaration, Root}; pub(super) use trait_map::IsExtendingExistingImpl; pub(super) use trait_map::IsImplSelf; pub(super) use trait_map::ResolvedTraitImplItem; diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index fdb6b910ad7..3bde3eab3fa 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -293,7 +293,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 9081d0b3282..9f2284257b9 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -46,6 +46,13 @@ impl DebugWithEngines for ResolvedDeclaration { } impl ResolvedDeclaration { + pub fn expect_parsed(self) -> Declaration { + match self { + ResolvedDeclaration::Parsed(decl) => decl, + ResolvedDeclaration::Typed(_) => panic!(), + } + } + pub fn expect_typed(self) -> ty::TyDecl { match self { ResolvedDeclaration::Parsed(_) => panic!(), @@ -54,6 +61,21 @@ impl ResolvedDeclaration { } } +#[derive(Clone, Debug)] +pub struct ResolveOptions { + pub resolve_parsed: bool, + pub resolve_typed: bool, +} + +impl Default for ResolveOptions { + fn default() -> Self { + Self { + resolve_parsed: true, + resolve_typed: true, + } + } +} + /// The root module, from which all other modules can be accessed. /// /// This is equivalent to the "crate root" of a Rust crate. @@ -65,6 +87,7 @@ impl ResolvedDeclaration { #[derive(Clone, Debug)] pub struct Root { pub(crate) module: Module, + pub(crate) resolve_options: ResolveOptions, } impl Root { @@ -837,43 +860,53 @@ impl Root { symbol: &Ident, module: &Module, ) -> Result { - // Check locally declared items. Any name clash with imports will have already been reported as an error. - if let Some(decl) = module.current_items().symbols.get(symbol) { - return Ok(ResolvedDeclaration::Typed(decl.clone())); - } - // Check item imports - if let Some((_, _, decl)) = module.current_items().use_item_synonyms.get(symbol) { - return Ok(ResolvedDeclaration::Typed(decl.clone())); + if self.resolve_options.resolve_parsed { + // Check locally declared parsed items. Any name clash with imports will have already been reported as an error. + if let Some(decl) = module.current_items().parsed_symbols.get(symbol) { + return Ok(ResolvedDeclaration::Parsed(decl.clone())); + } } - // Check glob imports - if let Some(decls) = module.current_items().use_glob_synonyms.get(symbol) { - if decls.len() == 1 { - return Ok(ResolvedDeclaration::Typed(decls[0].1.clone())); - } else if decls.is_empty() { - return Err(handler.emit_err(CompileError::Internal( + if self.resolve_options.resolve_typed { + // Check locally declared items. Any name clash with imports will have already been reported as an error. + if let Some(decl) = module.current_items().symbols.get(symbol) { + return Ok(ResolvedDeclaration::Typed(decl.clone())); + } + // Check item imports + if let Some((_, _, decl)) = module.current_items().use_item_synonyms.get(symbol) { + return Ok(ResolvedDeclaration::Typed(decl.clone())); + } + // Check glob imports + if let Some(decls) = module.current_items().use_glob_synonyms.get(symbol) { + if decls.len() == 1 { + return Ok(ResolvedDeclaration::Typed(decls[0].1.clone())); + } else if decls.is_empty() { + return Err(handler.emit_err(CompileError::Internal( "The name {symbol} was bound in a star import, but no corresponding module paths were found", symbol.span(), ))); - } else { - // Symbol not found - return Err(handler.emit_err(CompileError::SymbolWithMultipleBindings { - name: symbol.clone(), - paths: decls - .iter() - .map(|(path, decl)| { - let mut path_strs = path.iter().map(|x| x.as_str()).collect::>(); - // Add the enum name to the path if the decl is an enum variant. - if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { - enum_ref, .. - }) = decl - { - path_strs.push(enum_ref.name().as_str()) - }; - path_strs.join("::") - }) - .collect(), - span: symbol.span(), - })); + } else { + // Symbol not found + return Err(handler.emit_err(CompileError::SymbolWithMultipleBindings { + name: symbol.clone(), + paths: decls + .iter() + .map(|(path, decl)| { + let mut path_strs = + path.iter().map(|x| x.as_str()).collect::>(); + // Add the enum name to the path if the decl is an enum variant. + if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { + enum_ref, + .. + }) = decl + { + path_strs.push(enum_ref.name().as_str()) + }; + path_strs.join("::") + }) + .collect(), + span: symbol.span(), + })); + } } } // Symbol not found @@ -886,7 +919,10 @@ impl Root { impl From for Root { fn from(module: Module) -> Self { - Root { module } + Root { + module, + resolve_options: Default::default(), + } } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 2112b57c1a9..b7ff0909205 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -527,6 +527,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) @@ -568,6 +569,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 cf26a6a0013..d0423b91f5c 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 48a42e38d77..08f4de89caf 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -21,14 +21,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()); @@ -48,7 +67,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..c13fef27f6b --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -0,0 +1,632 @@ +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, ConstantDeclaration, Declaration, + EnumDeclaration, EnumVariant, Expression, ExpressionKind, FunctionDeclaration, + FunctionParameter, ImplItem, ImplSelf, ImplTrait, ParseModule, ParseProgram, + ReassignmentTarget, Scrutinee, StorageDeclaration, 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; + ctx.namespace_mut().root.resolve_options.resolve_typed = false; + root.resolve_symbols(handler, ctx.by_ref()); + ctx.namespace_mut().root.resolve_options.resolve_typed = true; + } +} + +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::ImplTrait(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::ImplSelf(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), + } + } +} + +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 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_trait = ctx.engines().pe().get_impl_trait(self).as_ref().clone(); + impl_trait.resolve_symbols(handler, ctx); + pe.replace(*self, impl_trait); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut impl_decl = ctx.engines().pe().get_impl_self(self).as_ref().clone(); + impl_decl.resolve_symbols(handler, ctx); + pe.replace(*self, impl_decl); + } +} + +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 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 ImplTrait { + 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 ImplSelf { + 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.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.fields.iter_mut().for_each(|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) { + // if let ExpressionKind::FunctionApplication(_) = self.kind { + // println!("fn_app: {}", ctx.engines.help_out(self.span.clone())); + // } + 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) => { + //expr.call_path_binding.resolve_symbol(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(), + }); + } + 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..b22df64c26d --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -0,0 +1,1106 @@ +use std::collections::{HashMap, VecDeque}; + +use crate::{ + decl_engine::parsed_id::ParsedDeclId, + engine_threading::*, + language::{ + parsed::{self, Declaration, FunctionDeclaration}, + CallPath, QualifiedCallPath, Visibility, + }, + namespace::{ + ModulePath, ResolvedDeclaration, ResolvedTraitImplItem, TryInsertingTraitImplOnFailure, + }, + semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, + type_system::{TypeArgument, TypeId, TypeInfo}, + TraitConstraint, UnifyCheck, +}; +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 + } + + /// Resolve the type of the given [TypeId], replacing any instances of + /// [TypeInfo::Custom] with a reference to the declaration. + #[allow(clippy::too_many_arguments)] + #[allow(unused)] + pub(crate) fn resolve( + &mut self, + handler: &Handler, + type_id: TypeId, + span: &Span, + enforce_type_arguments: EnforceTypeArguments, + type_info_prefix: Option<&ModulePath>, + mod_path: &ModulePath, + ) -> Result { + let engines = self.engines; + let type_engine = engines.te(); + let module_path = type_info_prefix.unwrap_or(mod_path); + let type_id = match (*type_engine.get(type_id)).clone() { + TypeInfo::Custom { + qualified_call_path, + type_arguments, + root_type_id, + } => { + let type_decl_opt = if let Some(root_type_id) = root_type_id { + self.namespace() + .root() + .resolve_call_path_and_root_type_id( + handler, + self.engines, + self.namespace().module(engines), + root_type_id, + None, + &qualified_call_path.clone().to_call_path(handler)?, + self.self_type(), + ) + .ok() + } else { + self.resolve_qualified_call_path_with_visibility_check_and_modpath( + handler, + module_path, + &qualified_call_path, + ) + .ok() + }; + self.type_decl_opt_to_type_id( + handler, + type_decl_opt, + qualified_call_path.clone(), + span, + enforce_type_arguments, + mod_path, + type_arguments.clone(), + )? + } + TypeInfo::Array(mut elem_ty, n) => { + elem_ty.type_id = self + .resolve( + handler, + elem_ty.type_id, + span, + enforce_type_arguments, + None, + mod_path, + ) + .unwrap_or_else(|err| { + self.engines + .te() + .insert(self.engines, TypeInfo::ErrorRecovery(err), None) + }); + + self.engines.te().insert( + self.engines, + TypeInfo::Array(elem_ty.clone(), n.clone()), + elem_ty.span.source_id(), + ) + } + TypeInfo::Tuple(mut type_arguments) => { + for type_argument in type_arguments.iter_mut() { + type_argument.type_id = self + .resolve( + handler, + type_argument.type_id, + span, + enforce_type_arguments, + None, + mod_path, + ) + .unwrap_or_else(|err| { + self.engines.te().insert( + self.engines, + TypeInfo::ErrorRecovery(err), + None, + ) + }); + } + + self.engines.te().insert( + self.engines, + TypeInfo::Tuple(type_arguments), + span.source_id(), + ) + } + TypeInfo::TraitType { + name, + trait_type_id, + } => { + let item_ref = self.namespace().get_root_trait_item_for_type( + handler, + self.engines, + &name, + trait_type_id, + None, + )?; + if let ResolvedTraitImplItem::Parsed(parsed::ImplItem::Type(type_ref)) = item_ref { + let type_decl = self.engines.pe().get_trait_type(&type_ref); + // if let Some(ty) = &type_decl.ty { + // ty.type_id + // } else { + type_id + // } + } else { + return Err(handler.emit_err(CompileError::Internal( + "Expecting associated type", + item_ref.span(self.engines), + ))); + } + } + TypeInfo::Ref { + referenced_type: mut ty, + to_mutable_value, + } => { + ty.type_id = self + .resolve( + handler, + ty.type_id, + span, + enforce_type_arguments, + None, + mod_path, + ) + .unwrap_or_else(|err| { + self.engines + .te() + .insert(self.engines, TypeInfo::ErrorRecovery(err), None) + }); + + self.engines.te().insert( + self.engines, + TypeInfo::Ref { + to_mutable_value, + referenced_type: ty.clone(), + }, + None, + ) + } + _ => type_id, + }; + + // TODO/tritao + //let mut type_id = type_id; + //type_id.subst(&self.type_subst(), self.engines()); + + Ok(type_id) + } + + /// Short-hand for calling [Root::resolve_type_with_self] on `root` with the `mod_path`. + #[allow(clippy::too_many_arguments)] // TODO: remove lint bypass once private modules are no longer experimental + #[allow(unused)] + pub(crate) fn resolve_type( + &mut self, + handler: &Handler, + type_id: TypeId, + span: &Span, + enforce_type_arguments: EnforceTypeArguments, + type_info_prefix: Option<&ModulePath>, + ) -> Result { + let mod_path = self.namespace().mod_path.clone(); + self.resolve( + handler, + type_id, + span, + enforce_type_arguments, + type_info_prefix, + &mod_path, + ) + } + + /// Short-hand for calling [Root::resolve_type_without_self] on `root` and with the `mod_path`. + pub(crate) fn resolve_type_without_self( + &mut self, + handler: &Handler, + type_id: TypeId, + span: &Span, + type_info_prefix: Option<&ModulePath>, + ) -> Result { + let mod_path = self.namespace().mod_path.clone(); + self.resolve( + handler, + type_id, + span, + EnforceTypeArguments::Yes, + type_info_prefix, + &mod_path, + ) + } + + /// 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, + }); + } + } + + // TODO/tritao + // check the visibility of the symbol itself + // if !decl.visibility(self.engines.de()).is_public() { + // handler.emit_err(CompileError::ImportPrivateSymbol { + // name: call_path.suffix.clone(), + // span: call_path.suffix.span(), + // }); + // } + + Ok(decl) + } + + #[allow(unused)] + pub(crate) fn resolve_qualified_call_path_with_visibility_check( + &mut self, + handler: &Handler, + qualified_call_path: &QualifiedCallPath, + ) -> Result { + self.resolve_qualified_call_path_with_visibility_check_and_modpath( + handler, + &self.namespace().mod_path.clone(), + qualified_call_path, + ) + } + + #[allow(unused)] + pub(crate) fn resolve_qualified_call_path_with_visibility_check_and_modpath( + &mut self, + handler: &Handler, + mod_path: &ModulePath, + qualified_call_path: &QualifiedCallPath, + ) -> Result { + let engines = self.engines(); + let type_engine = self.engines().te(); + if let Some(qualified_path_root) = qualified_call_path.clone().qualified_path_root { + let root_type_id = match &&*type_engine.get(qualified_path_root.ty.type_id) { + TypeInfo::Custom { + qualified_call_path: call_path, + type_arguments, + .. + } => { + let type_decl = self.resolve_call_path_with_visibility_check_and_modpath( + handler, + mod_path, + &call_path.clone().to_call_path(handler)?, + )?; + self.type_decl_opt_to_type_id( + handler, + Some(type_decl), + call_path.clone(), + &qualified_path_root.ty.span(), + EnforceTypeArguments::No, + mod_path, + type_arguments.clone(), + )? + } + _ => qualified_path_root.ty.type_id, + }; + + let as_trait_opt = match &&*type_engine.get(qualified_path_root.as_trait) { + TypeInfo::Custom { + qualified_call_path: call_path, + .. + } => Some( + call_path + .clone() + .to_call_path(handler)? + .to_fullpath(engines, self.namespace()), + ), + _ => None, + }; + + self.namespace().root.resolve_call_path_and_root_type_id( + handler, + engines, + self.namespace().module(engines), + root_type_id, + as_trait_opt, + &qualified_call_path.call_path, + self.self_type(), + ) + } else { + self.resolve_call_path_with_visibility_check_and_modpath( + handler, + mod_path, + &qualified_call_path.call_path, + ) + } + } + + #[allow(clippy::too_many_arguments)] + #[allow(unused)] + fn type_decl_opt_to_type_id( + &mut self, + handler: &Handler, + type_decl_opt: Option, + call_path: QualifiedCallPath, + span: &Span, + enforce_type_arguments: EnforceTypeArguments, + mod_path: &ModulePath, + type_arguments: Option>, + ) -> Result { + todo!(); + // TODO/tritao + // let decl_engine = self.engines.de(); + // let type_engine = self.engines.te(); + // Ok(match type_decl_opt { + // Some(ty::TyDecl::StructDecl(ty::StructDecl { + // decl_id: original_id, + // .. + // })) => { + // // get the copy from the declaration engine + // let mut new_copy = (*decl_engine.get_struct(&original_id)).clone(); + + // // monomorphize the copy, in place + // self.monomorphize_with_modpath( + // handler, + // &mut new_copy, + // &mut type_arguments.unwrap_or_default(), + // enforce_type_arguments, + // span, + // mod_path, + // )?; + + // // insert the new copy in the decl engine + // let new_decl_ref = decl_engine.insert(new_copy); + + // // create the type id from the copy + // type_engine.insert( + // self.engines, + // TypeInfo::Struct(new_decl_ref.clone()), + // new_decl_ref.span().source_id(), + // ) + // } + // Some(ty::TyDecl::EnumDecl(ty::EnumDecl { + // decl_id: original_id, + // .. + // })) => { + // // get the copy from the declaration engine + // let mut new_copy = (*decl_engine.get_enum(&original_id)).clone(); + + // // monomorphize the copy, in place + // self.monomorphize_with_modpath( + // handler, + // &mut new_copy, + // &mut type_arguments.unwrap_or_default(), + // enforce_type_arguments, + // span, + // mod_path, + // )?; + + // // insert the new copy in the decl engine + // let new_decl_ref = decl_engine.insert(new_copy); + + // // create the type id from the copy + // type_engine.insert( + // self.engines, + // TypeInfo::Enum(new_decl_ref.clone()), + // new_decl_ref.span().source_id(), + // ) + // } + // Some(ty::TyDecl::TypeAliasDecl(ty::TypeAliasDecl { + // decl_id: original_id, + // .. + // })) => { + // let new_copy = decl_engine.get_type_alias(&original_id); + + // // TODO: monomorphize the copy, in place, when generic type aliases are + // // supported + + // new_copy.create_type_id(self.engines) + // } + // Some(ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { + // type_id, + // .. + // })) => type_id, + // Some(ty::TyDecl::TraitTypeDecl(ty::TraitTypeDecl { + // decl_id, + // name, + // decl_span: _, + // })) => { + // let decl_type = decl_engine.get_type(&decl_id); + + // if let Some(ty) = &decl_type.ty { + // ty.type_id + // } else if let Some(implementing_type) = self.self_type() { + // type_engine.insert( + // self.engines, + // TypeInfo::TraitType { + // name: name.clone(), + // trait_type_id: implementing_type, + // }, + // name.span().source_id(), + // ) + // } else { + // return Err(handler.emit_err(CompileError::Internal( + // "Self type not provided.", + // span.clone(), + // ))); + // } + // } + // _ => { + // let err = handler.emit_err(CompileError::UnknownTypeName { + // name: call_path.call_path.to_string(), + // span: call_path.call_path.span(), + // }); + // type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None) + // } + // }) + } + + /// Given a name and a type (plus a `self_type` to potentially + /// resolve it), find items matching in the namespace. + #[allow(unused)] + pub(crate) fn find_items_for_type( + &mut self, + handler: &Handler, + type_id: TypeId, + item_prefix: &ModulePath, + item_name: &Ident, + ) -> Result, ErrorEmitted> { + let type_engine = self.engines.te(); + let _decl_engine = self.engines.de(); + + // If the type that we are looking for is the error recovery type, then + // we want to return the error case without creating a new error + // message. + if let TypeInfo::ErrorRecovery(err) = &*type_engine.get(type_id) { + return Err(*err); + } + + // grab the local module + let local_module = self.namespace().lookup_submodule_from_absolute_path( + handler, + self.engines(), + &self.namespace().mod_path, + )?; + + // grab the local items from the local module + let local_items = local_module + .current_items() + .get_items_for_type(self.engines, type_id); + + // resolve the type + let type_id = self + .resolve( + handler, + type_id, + &item_name.span(), + EnforceTypeArguments::No, + None, + item_prefix, + ) + .unwrap_or_else(|err| { + type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None) + }); + + // grab the module where the type itself is declared + let type_module = self.namespace().lookup_submodule_from_absolute_path( + handler, + self.engines(), + item_prefix, + )?; + + // grab the items from where the type is declared + let mut type_items = type_module + .current_items() + .get_items_for_type(self.engines, type_id); + + let mut items = local_items; + items.append(&mut type_items); + + let mut matching_item_decl_refs: Vec = vec![]; + + let pe = self.engines.pe(); + for item in items.into_iter() { + match &item { + ResolvedTraitImplItem::Parsed(item) => match item { + parsed::ImplItem::Fn(decl_id) => { + if pe.get_function(decl_id).name == *item_name { + matching_item_decl_refs.push(item.clone()); + } + } + parsed::ImplItem::Constant(decl_id) => { + if pe.get_constant(decl_id).name == *item_name { + matching_item_decl_refs.push(item.clone()); + } + } + parsed::ImplItem::Type(decl_id) => { + if pe.get_trait_type(decl_id).name == *item_name { + matching_item_decl_refs.push(item.clone()); + } + } + }, + ResolvedTraitImplItem::Typed(_) => unreachable!(), + } + } + + Ok(matching_item_decl_refs) + } + + /// Given a name and a type (plus a `self_type` to potentially + /// resolve it), find that method in the namespace. Requires `args_buf` + /// because of some special casing for the standard library where we pull + /// the type from the arguments buffer. + /// + /// This function will generate a missing method error if the method is not + /// found. + #[allow(clippy::too_many_arguments)] // TODO: remove lint bypass once private modules are no longer experimental + #[allow(unused)] + pub(crate) fn find_method_for_type( + &mut self, + handler: &Handler, + type_id: TypeId, + method_prefix: &ModulePath, + method_name: &Ident, + annotation_type: TypeId, + arguments_types: &VecDeque, + as_trait: Option, + try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, + ) -> Result, ErrorEmitted> { + let decl_engine = self.engines.de(); + let type_engine = self.engines.te(); + let parsed_decl_engine = self.engines.pe(); + + let eq_check = UnifyCheck::non_dynamic_equality(self.engines); + let coercion_check = UnifyCheck::coercion(self.engines); + + // default numeric types to u64 + if type_engine.contains_numeric(decl_engine, type_id) { + type_engine.decay_numeric(handler, self.engines, type_id, &method_name.span())?; + } + + let matching_item_decl_refs = + self.find_items_for_type(handler, type_id, method_prefix, method_name)?; + + let matching_method_decl_refs = matching_item_decl_refs + .into_iter() + .flat_map(|item| match item { + parsed::ImplItem::Fn(decl_id) => Some(decl_id), + parsed::ImplItem::Constant(_) => None, + parsed::ImplItem::Type(_) => None, + }) + .collect::>(); + + let mut qualified_call_path = None; + let matching_method_decl_ref = { + // Case where multiple methods exist with the same name + // This is the case of https://github.com/FuelLabs/sway/issues/3633 + // where multiple generic trait impls use the same method name but with different parameter types + let mut maybe_method_decl_refs: Vec> = vec![]; + for decl_ref in matching_method_decl_refs.clone().into_iter() { + let method = parsed_decl_engine.get_function(&decl_ref); + if method.parameters.len() == arguments_types.len() + && method + .parameters + .iter() + .zip(arguments_types.iter()) + .all(|(p, a)| coercion_check.check(p.type_argument.type_id, *a)) + && (matches!(&*type_engine.get(annotation_type), TypeInfo::Unknown) + || coercion_check.check(annotation_type, method.return_type.type_id)) + { + maybe_method_decl_refs.push(decl_ref); + } + } + + if !maybe_method_decl_refs.is_empty() { + let mut trait_methods = HashMap::< + (CallPath, Vec>), + ParsedDeclId, + >::new(); + let mut impl_self_method = None; + for method_ref in maybe_method_decl_refs.clone() { + let method = parsed_decl_engine.get_function(&method_ref); + if let Some(Declaration::ImplTrait(impl_trait)) = + method.implementing_type.clone() + { + let trait_decl = parsed_decl_engine.get_impl_trait(&impl_trait); + let mut skip_insert = false; + if let Some(as_trait) = as_trait { + if let TypeInfo::Custom { + qualified_call_path: call_path, + type_arguments, + root_type_id: _, + } = &*type_engine.get(as_trait) + { + qualified_call_path = Some(call_path.clone()); + // When `>::method()` is used we only add methods to `trait_methods` that + // originate from the qualified trait. + if trait_decl.trait_name + == call_path.clone().to_call_path(handler)? + { + let mut params_equal = true; + if let Some(params) = type_arguments { + if params.len() != trait_decl.trait_type_arguments.len() { + params_equal = false; + } else { + for (p1, p2) in params + .iter() + .zip(trait_decl.trait_type_arguments.clone()) + { + let p1_type_id = self.resolve_type_without_self( + handler, p1.type_id, &p1.span, None, + )?; + let p2_type_id = self.resolve_type_without_self( + handler, p2.type_id, &p2.span, None, + )?; + if !eq_check.check(p1_type_id, p2_type_id) { + params_equal = false; + break; + } + } + } + } + if params_equal { + trait_methods.insert( + ( + trait_decl.trait_name.clone(), + trait_decl + .trait_type_arguments + .iter() + .cloned() + .map(|a| self.engines.help_out(a)) + .collect::>(), + ), + method_ref, + ); + } + } + skip_insert = true; + } + } + + if !skip_insert { + trait_methods.insert( + ( + trait_decl.trait_name.clone(), + trait_decl + .trait_type_arguments + .iter() + .cloned() + .map(|a| self.engines.help_out(a)) + .collect::>(), + ), + method_ref, + ); + } + if trait_decl.trait_decl_ref.is_none() { + impl_self_method = Some(method_ref); + } + } + } + + if trait_methods.len() == 1 { + trait_methods.values().next().cloned() + } else if trait_methods.len() > 1 { + if impl_self_method.is_some() { + // In case we have trait methods and a impl self method we use the impl self method. + impl_self_method + } else { + fn to_string( + trait_name: CallPath, + trait_type_args: Vec>, + ) -> String { + format!( + "{}{}", + trait_name.suffix, + if trait_type_args.is_empty() { + String::new() + } else { + format!( + "<{}>", + trait_type_args + .iter() + .map(|type_arg| type_arg.to_string()) + .collect::>() + .join(", ") + ) + } + ) + } + let mut trait_strings = trait_methods + .keys() + .map(|t| to_string(t.0.clone(), t.1.clone())) + .collect::>(); + // Sort so the output of the error is always the same. + trait_strings.sort(); + return Err(handler.emit_err( + CompileError::MultipleApplicableItemsInScope { + item_name: method_name.as_str().to_string(), + item_kind: "function".to_string(), + type_name: self.engines.help_out(type_id).to_string(), + as_traits: trait_strings, + span: method_name.span(), + }, + )); + } + } else if qualified_call_path.is_some() { + // When we use a qualified path the expected method should be in trait_methods. + None + } else { + maybe_method_decl_refs.first().cloned() + } + } else { + // When we can't match any method with parameter types we still return the first method found + // This was the behavior before introducing the parameter type matching + matching_method_decl_refs.first().cloned() + } + }; + + if let Some(method_decl_ref) = matching_method_decl_ref { + return Ok(method_decl_ref); + } + + if let Some(TypeInfo::ErrorRecovery(err)) = arguments_types + .front() + .map(|x| (*type_engine.get(*x)).clone()) + { + Err(err) + } else { + if matches!( + try_inserting_trait_impl_on_failure, + TryInsertingTraitImplOnFailure::Yes + ) { + // Retrieve the implemented traits for the type and insert them in the namespace. + // insert_trait_implementation_for_type is done lazily only when required because of a failure. + self.insert_trait_implementation_for_type(type_id); + + return self.find_method_for_type( + handler, + type_id, + method_prefix, + method_name, + annotation_type, + arguments_types, + as_trait, + TryInsertingTraitImplOnFailure::No, + ); + } + + let type_name = if let Some(call_path) = qualified_call_path { + format!( + "{} as {}", + self.engines.help_out(type_id), + call_path.call_path + ) + } else { + self.engines.help_out(type_id).to_string() + }; + Err(handler.emit_err(CompileError::MethodNotFound { + method_name: method_name.clone(), + type_name, + span: method_name.span(), + })) + } + } + + #[allow(unused)] + pub(crate) fn get_items_for_type_and_trait_name( + &self, + type_id: TypeId, + trait_name: &CallPath, + ) -> Vec { + self.get_items_for_type_and_trait_name_and_trait_type_arguments(type_id, trait_name, &[]) + } + + #[allow(unused)] + pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments( + &self, + type_id: TypeId, + trait_name: &CallPath, + trait_type_args: &[TypeArgument], + ) -> Vec { + // Use trait name with full path, improves consistency between + // this get and inserting in `insert_trait_implementation`. + let trait_name = trait_name.to_fullpath(self.engines(), self.namespace()); + + self.namespace() + .module(self.engines) + .current_items() + .implemented_traits + .get_items_for_type_and_trait_name_and_trait_type_arguments( + self.engines, + type_id, + &trait_name, + trait_type_args, + ) + } + + pub(crate) fn insert_trait_implementation_for_type(&mut self, type_id: TypeId) { + let engines = self.engines; + self.namespace_mut() + .module_mut(engines) + .current_items_mut() + .implemented_traits + .insert_for_type(engines, type_id); + } + + pub fn check_type_impls_traits( + &mut self, + type_id: TypeId, + constraints: &[TraitConstraint], + ) -> bool { + let handler = Handler::default(); + let engines = self.engines; + + self.namespace_mut() + .module_mut(engines) + .current_items_mut() + .implemented_traits + .check_if_trait_constraints_are_satisfied_for_type( + &handler, + type_id, + constraints, + &Span::dummy(), + engines, + crate::namespace::TryInsertingTraitImplOnFailure::Yes, + ) + .is_ok() + } +} + +/// 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 +/// } +/// } +/// ``` +/// +/// `EnforeTypeArguments` 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 +/// } +/// } +/// ``` +#[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 86e9869a2d6..5a025dd2388 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 @@ -173,9 +173,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)?, )), @@ -202,15 +210,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, @@ -537,6 +555,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)?, @@ -570,6 +589,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) @@ -769,12 +789,14 @@ 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, }; let impl_trait = engines.pe().insert(impl_trait); - Ok(Declaration::ImplTrait(impl_trait)) + let decl = Declaration::ImplTrait(impl_trait); + Ok(decl) } None => match &*engines.te().get(implementing_for.type_id) { TypeInfo::Contract => Err(handler @@ -1724,6 +1746,7 @@ fn struct_path_and_fields_to_struct_expression( }; Ok(Box::new(StructExpression { call_path_binding, + resolved_call_path_binding: None, fields, })) } @@ -1872,6 +1895,7 @@ fn expr_func_app_to_expression_kind( type_arguments: TypeArgs::Regular(type_arguments), span: span.clone(), }, + resolved_call_path_binding: None, arguments, }, )), @@ -2512,6 +2536,7 @@ fn configurable_field_to_constant_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 80b1dcb261b..c141c975dac 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -2,10 +2,16 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ - decl_engine::{DeclEngineInsert, DeclId, DeclRef}, - engine_threading::{PartialEqWithEngines, PartialEqWithEnginesContext}, - language::{ty, CallPath, QualifiedCallPath}, - semantic_analysis::{type_check_context::EnforceTypeArguments, TypeCheckContext}, + decl_engine::{parsed_id::ParsedDeclId, *}, + engine_threading::*, + 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, }; @@ -161,6 +167,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> { @@ -219,6 +236,30 @@ 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.expect_parsed().to_fn_ref(handler, engines)?; + Ok(fn_decl) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -278,6 +319,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 + .expect_parsed() + .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 7e789a792ba..1f0b5b387eb 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;