From c9679b259fca58737550ebf09d5d1703c17e5836 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 6 May 2024 11:59:18 +0100 Subject: [PATCH] Add symbol resolve context. --- .../src/decl_engine/interface_decl_id.rs | 28 +- sway-core/src/decl_engine/parsed_engine.rs | 24 + sway-core/src/language/call_path.rs | 6 + sway-core/src/language/parsed/declaration.rs | 68 +- .../language/parsed/declaration/function.rs | 1 + .../language/parsed/declaration/impl_trait.rs | 8 +- .../src/language/parsed/expression/mod.rs | 5 +- sway-core/src/lib.rs | 9 +- sway-core/src/semantic_analysis.rs | 4 +- .../ast_node/declaration/impl_trait.rs | 1 + .../src/semantic_analysis/namespace/mod.rs | 2 +- .../src/semantic_analysis/namespace/root.rs | 7 + .../semantic_analysis/node_dependencies.rs | 1 + .../src/semantic_analysis/symbol_resolve.rs | 524 +++++++ .../symbol_resolve_context.rs | 1249 +++++++++++++++++ .../src/transform/to_parsed_lang/context.rs | 6 +- .../to_parsed_lang/convert_parse_tree.rs | 49 +- .../src/type_system/ast_elements/binding.rs | 48 +- sway-core/src/type_system/mod.rs | 2 +- 19 files changed, 2014 insertions(+), 28 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/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 4b7d3d2b13b..1ea07cf4303 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -177,6 +177,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 ad6a1a6c5ec..9461ee77b84 100644 --- a/sway-core/src/language/parsed/declaration.rs +++ b/sway-core/src/language/parsed/declaration.rs @@ -17,11 +17,19 @@ 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_id::ParsedDeclId, Engines}; +use crate::{ + decl_engine::{parsed_engine::ParsedDeclEngine, parsed_id::ParsedDeclId}, + language::Visibility, + Engines, +}; #[derive(Debug, Clone)] pub enum Declaration { @@ -50,7 +58,26 @@ impl Declaration { } } - #[allow(dead_code)] + /// Friendly type name string used for error reporting, + /// which consists of the type name of the declaration AST node. + pub fn friendly_type_name(&self) -> &'static str { + use Declaration::*; + match self { + VariableDeclaration(_) => "variable", + ConstantDeclaration(_) => "constant", + TraitTypeDeclaration(_) => "type", + FunctionDeclaration(_) => "function", + TraitDeclaration(_) => "trait", + StructDeclaration(_) => "struct", + EnumDeclaration(_) => "enum", + ImplSelf(_) => "impl self", + ImplTrait(_) => "impl trait", + AbiDeclaration(_) => "abi", + StorageDeclaration(_) => "contract storage", + TypeAliasDeclaration(_) => "type alias", + } + } + fn span(&self, engines: &Engines) -> sway_types::Span { use Declaration::*; let pe = engines.pe(); @@ -69,4 +96,41 @@ impl Declaration { TraitTypeDeclaration(decl_id) => pe.get_trait_type(decl_id).span(), } } + + 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), + })), + } + } + + 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, + } + } } 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..2f76ca7e726 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -7,7 +7,7 @@ use crate::{ }, language::{parsed::CodeBlock, *}, type_system::TypeBinding, - Engines, TypeArgument, TypeId, + Engines, TypeArgument, TypeId, decl_engine::parsed_id::ParsedDeclId, }; use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, Span, Spanned}; @@ -22,6 +22,8 @@ pub use method_name::MethodName; pub use scrutinee::*; use sway_ast::intrinsics::Intrinsic; +use super::StructDeclaration; + /// Represents a parsed, but not yet type checked, [Expression](https://en.wikipedia.org/wiki/Expression_(computer_science)). #[derive(Debug, Clone)] pub struct Expression { @@ -57,6 +59,7 @@ 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 529d9e1ce51..222c5a690e6 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,9 +538,14 @@ pub fn parsed_to_ast( build_module_dep_graph(handler, &mut parse_program.root)?; // Collect the program symbols. - let _collection_ctx = + let symbol_collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, initial_namespace.clone())?; + // Resolve the program symbols. + let mut namespace = Namespace::init_root(initial_namespace.clone()); + let resolve_ctx = SymbolResolveContext::new(&mut namespace, engines, &symbol_collection_ctx); + let new_parse_program = parse_program.clone().resolve_symbols(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/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index a734a030d30..7e4cdf485e6 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/namespace/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index 299b79bbdda..3e149f3b3b3 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -10,7 +10,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::{Root, ResolvedDeclaration}; 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/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 977ca36ef84..a51e61e7202 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -25,6 +25,13 @@ pub enum 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!(), diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index ff6acedf195..94d8220adb6 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -568,6 +568,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/symbol_resolve.rs b/sway-core/src/semantic_analysis/symbol_resolve.rs new file mode 100644 index 00000000000..5cd72ee23c9 --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -0,0 +1,524 @@ +use sway_error::handler::Handler; + +use crate::{ + ast_elements::binding::SymbolResolveTypeBinding, + decl_engine::{parsed_engine::ParsedDeclEngineReplace, parsed_id::ParsedDeclId}, + language::{ + parsed::{ + AstNode, AstNodeContent, CodeBlock, ConstantDeclaration, Declaration, EnumDeclaration, + EnumVariant, Expression, ExpressionKind, FunctionDeclaration, FunctionParameter, + ImplItem, ImplSelf, ImplTrait, ParseModule, ParseProgram, Scrutinee, StructDeclaration, + StructExpressionField, StructField, StructScrutineeField, Supertrait, TraitDeclaration, + TraitFn, TraitItem, TraitTypeDeclaration, VariableDeclaration, + }, + CallPath, CallPathTree, ResolvedCallPath, + }, + TraitConstraint, TypeArgument, TypeBinding, TypeParameter, +}; + +use super::symbol_resolve_context::SymbolResolveContext; + +pub trait ResolveSymbols { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext); +} + +impl ResolveSymbols for ParseProgram { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let ParseProgram { root, .. } = self; + root.resolve_symbols(ctx); + } +} + +impl ResolveSymbols for ParseModule { + fn resolve_symbols(&mut self, 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(ctx.by_ref()); + }); + + tree.root_nodes + .iter_mut() + .for_each(|node| node.resolve_symbols(ctx.by_ref())) + } +} + +impl ResolveSymbols for AstNode { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + match self.content { + AstNodeContent::UseStatement(_) => {} + AstNodeContent::Declaration(ref mut decl) => decl.resolve_symbols(ctx), + AstNodeContent::Expression(ref mut expr) => expr.resolve_symbols(ctx), + AstNodeContent::IncludeStatement(_) => {} + AstNodeContent::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for Declaration { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + match self { + Declaration::VariableDeclaration(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::FunctionDeclaration(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::TraitDeclaration(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::StructDeclaration(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::EnumDeclaration(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::ImplTrait(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::ImplSelf(decl_id) => decl_id.resolve_symbols(ctx), + Declaration::AbiDeclaration(_) => todo!(), + Declaration::ConstantDeclaration(_) => todo!(), + Declaration::StorageDeclaration(_) => todo!(), + Declaration::TypeAliasDeclaration(_) => todo!(), + Declaration::TraitTypeDeclaration(_) => todo!(), + } + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut var_decl = pe.get_variable(self).as_ref().clone(); + var_decl.body.resolve_symbols(ctx); + pe.replace(*self, var_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut fn_decl = pe.get_function(self).as_ref().clone(); + fn_decl.body.resolve_symbols(ctx); + pe.replace(*self, fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_decl = ctx.engines().pe().get_trait(self).as_ref().clone(); + trait_decl.resolve_symbols(ctx); + pe.replace(*self, trait_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut struct_decl = ctx.engines().pe().get_struct(self).as_ref().clone(); + struct_decl.resolve_symbols(ctx); + pe.replace(*self, struct_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut enum_decl = ctx.engines().pe().get_enum(self).as_ref().clone(); + enum_decl.resolve_symbols(ctx); + pe.replace(*self, enum_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut constant_decl = ctx.engines().pe().get_constant(self).as_ref().clone(); + constant_decl.resolve_symbols(ctx); + pe.replace(*self, constant_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, 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(ctx); + pe.replace(*self, trait_type_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, 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(ctx); + pe.replace(*self, trait_fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, 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(ctx); + pe.replace(*self, impl_trait); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, 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(ctx); + pe.replace(*self, impl_decl); + } +} + +impl ResolveSymbols for ConstantDeclaration { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.type_ascription.resolve_symbols(ctx.by_ref()); + if let Some(value) = self.value.as_mut() { + value.resolve_symbols(ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructDeclaration { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.fields + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())); + self.type_parameters + .iter_mut() + .for_each(|tp| tp.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for StructField { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(ctx); + } +} + +impl ResolveSymbols for EnumDeclaration { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.type_parameters + .iter_mut() + .for_each(|tp| tp.resolve_symbols(ctx.by_ref())); + self.variants + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for EnumVariant { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(ctx); + } +} + +impl ResolveSymbols for TraitDeclaration { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.interface_surface + .iter_mut() + .for_each(|item| item.resolve_symbols(ctx.by_ref())); + self.methods + .iter_mut() + .for_each(|m| m.resolve_symbols(ctx.by_ref())); + self.supertraits + .iter_mut() + .for_each(|st| st.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for TraitItem { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + match self { + TraitItem::TraitFn(ref mut id) => id.resolve_symbols(ctx.by_ref()), + TraitItem::Constant(ref mut id) => id.resolve_symbols(ctx.by_ref()), + TraitItem::Type(ref mut id) => id.resolve_symbols(ctx.by_ref()), + TraitItem::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for TraitFn { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())); + self.return_type.resolve_symbols(ctx.by_ref()); + } +} + +impl ResolveSymbols for Supertrait { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.name.resolve_symbols(ctx.by_ref()); + } +} + +impl ResolveSymbols for FunctionParameter { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(ctx.by_ref()); + } +} + +impl ResolveSymbols for ImplTrait { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.impl_type_parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())); + self.trait_name.resolve_symbols(ctx.by_ref()); + self.trait_type_arguments + .iter_mut() + .for_each(|tp| tp.resolve_symbols(ctx.by_ref())); + self.implementing_for.resolve_symbols(ctx.by_ref()); + self.items + .iter_mut() + .for_each(|tp| tp.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for ImplSelf { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.impl_type_parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())); + self.implementing_for.resolve_symbols(ctx.by_ref()); + self.items + .iter_mut() + .for_each(|tp| tp.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for ImplItem { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + match self { + ImplItem::Fn(decl_id) => decl_id.resolve_symbols(ctx), + ImplItem::Constant(decl_id) => decl_id.resolve_symbols(ctx), + ImplItem::Type(decl_id) => decl_id.resolve_symbols(ctx), + } + } +} + +impl ResolveSymbols for TraitTypeDeclaration { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + if let Some(ty) = self.ty_opt.as_mut() { + ty.resolve_symbols(ctx) + } + } +} + +impl ResolveSymbols for TypeArgument { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + if let Some(call_path) = self.call_path_tree.as_mut() { + call_path.resolve_symbols(ctx); + } + } +} + +impl ResolveSymbols for TypeParameter { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.trait_constraints + .iter_mut() + .for_each(|tc| tc.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for TraitConstraint { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + self.trait_name.resolve_symbols(ctx.by_ref()); + self.type_arguments + .iter_mut() + .for_each(|tc| tc.resolve_symbols(ctx.by_ref())); + } +} + +impl ResolveSymbols for CallPath { + fn resolve_symbols(&mut self, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CallPathTree { + fn resolve_symbols(&mut self, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CodeBlock { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + for expr in self.contents.iter_mut() { + expr.resolve_symbols(ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructExpressionField { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + self.value.resolve_symbols(ctx); + } +} + +impl ResolveSymbols for Scrutinee { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + match self { + Scrutinee::Or { + ref mut elems, + span: _, + } => elems + .iter_mut() + .for_each(|e| e.resolve_symbols(ctx.by_ref())), + Scrutinee::CatchAll { .. } => {} + Scrutinee::Literal { .. } => {} + Scrutinee::Variable { .. } => {} + Scrutinee::AmbiguousSingleIdent(_) => {} + Scrutinee::StructScrutinee { + struct_name, + fields, + span: _, + } => { + struct_name.resolve_symbols(ctx.by_ref()); + fields + .iter_mut() + .for_each(|f| f.resolve_symbols(ctx.by_ref())) + } + Scrutinee::EnumScrutinee { + call_path, + value, + span: _, + } => { + call_path.resolve_symbols(ctx.by_ref()); + value.resolve_symbols(ctx.by_ref()); + } + Scrutinee::Tuple { elems, span: _ } => { + elems + .iter_mut() + .for_each(|s| s.resolve_symbols(ctx.by_ref())); + } + Scrutinee::Error { .. } => {} + } + } +} + +impl ResolveSymbols for StructScrutineeField { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + match self { + StructScrutineeField::Rest { .. } => {} + StructScrutineeField::Field { + field: _, + scrutinee, + span: _, + } => { + if let Some(scrutinee) = scrutinee.as_mut() { + scrutinee.resolve_symbols(ctx.by_ref()); + } + } + } + } +} + +impl ResolveSymbols for Expression { + fn resolve_symbols(&mut self, ctx: SymbolResolveContext) { + self.kind.resolve_symbols(ctx); + } +} + +impl ResolveSymbols for ExpressionKind { + fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext) { + match self { + ExpressionKind::Error(_, _) => todo!(), + ExpressionKind::Literal(_) => {} + ExpressionKind::AmbiguousPathExpression(_) => {} + ExpressionKind::FunctionApplication(_) => todo!(), + ExpressionKind::LazyOperator(expr) => { + expr.lhs.resolve_symbols(ctx.by_ref()); + expr.rhs.resolve_symbols(ctx.by_ref()); + } + ExpressionKind::AmbiguousVariableExpression(_) => {} + ExpressionKind::Variable(_) => {} + ExpressionKind::Tuple(ref mut exprs) => { + exprs + .iter_mut() + .for_each(|expr| expr.resolve_symbols(ctx.by_ref())); + } + ExpressionKind::TupleIndex(expr) => { + expr.prefix.resolve_symbols(ctx.by_ref()); + } + ExpressionKind::Array(_) => todo!(), + ExpressionKind::Struct(ref mut expr) => { + expr.call_path_binding.resolve_symbols(ctx.by_ref()); + let result = SymbolResolveTypeBinding::resolve_symbol( + &mut expr.call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + expr.resolved_call_path_binding = Some(TypeBinding::< + ResolvedCallPath>, + > { + inner: ResolvedCallPath { + decl: result.unwrap(), + 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(ref mut block) => { + block + .contents + .iter_mut() + .for_each(|node| node.resolve_symbols(ctx.by_ref())); + } + ExpressionKind::If(expr) => { + expr.condition.resolve_symbols(ctx.by_ref()); + expr.then.resolve_symbols(ctx.by_ref()); + if let Some(r#else) = expr.r#else.as_mut() { + r#else.resolve_symbols(ctx.by_ref()); + } + } + ExpressionKind::Match(expr) => { + expr.value.resolve_symbols(ctx.by_ref()); + expr.branches.iter_mut().for_each(|branch| { + branch.scrutinee.resolve_symbols(ctx.by_ref()); + branch.result.resolve_symbols(ctx.by_ref()); + }); + } + ExpressionKind::Asm(ref mut asm_expr) => { + asm_expr.registers.iter_mut().for_each(|reg| { + if let Some(initializer) = reg.initializer.as_mut() { + initializer.resolve_symbols(ctx.by_ref()); + } + }) + } + ExpressionKind::MethodApplication(ref mut expr) => { + expr.method_name_binding.resolve_symbols(ctx.by_ref()); + expr.contract_call_params + .iter_mut() + .for_each(|field| field.resolve_symbols(ctx.by_ref())); + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(ctx.by_ref())); + } + ExpressionKind::Subfield(expr) => expr.prefix.resolve_symbols(ctx), + ExpressionKind::DelineatedPath(expr) => expr.call_path_binding.resolve_symbols(ctx), + ExpressionKind::AbiCast(_) => todo!(), + ExpressionKind::ArrayIndex(_) => todo!(), + ExpressionKind::StorageAccess(_) => todo!(), + ExpressionKind::IntrinsicFunction(expr) => { + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(ctx.by_ref())); + expr.kind_binding.resolve_symbols(ctx); + } + ExpressionKind::WhileLoop(_) => todo!(), + ExpressionKind::ForLoop(_) => todo!(), + ExpressionKind::Break => todo!(), + ExpressionKind::Continue => todo!(), + ExpressionKind::Reassignment(_) => todo!(), + ExpressionKind::ImplicitReturn(ref mut expr) => expr.resolve_symbols(ctx), + ExpressionKind::Return(_) => todo!(), + ExpressionKind::Ref(_) => todo!(), + ExpressionKind::Deref(_) => todo!(), + } + } +} 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..714220c30fe --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -0,0 +1,1249 @@ +use std::collections::{HashMap, VecDeque}; + +use crate::{ + decl_engine::parsed_id::ParsedDeclId, + engine_threading::*, + language::{ + parsed::{self, Declaration, FunctionDeclaration}, + ty::TyDecl, + CallPath, QualifiedCallPath, Visibility, + }, + namespace::{ + IsExtendingExistingImpl, IsImplSelf, ModulePath, ResolvedDeclaration, + ResolvedTraitImplItem, TryInsertingTraitImplOnFailure, + }, + semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, + type_system::{TypeArgument, TypeId, TypeInfo}, + TraitConstraint, TypeParameter, 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) namespace: &'a mut Namespace, + + pub(crate) engines: &'a Engines, + pub(crate) symbol_collection_ctx: &'a SymbolCollectionContext, + + // The following set of fields are intentionally private. When a `SymbolResolveContext` is passed + // into a new node during type checking, 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( + namespace: &'a mut Namespace, + engines: &'a Engines, + symbol_collection_ctx: &'a SymbolCollectionContext, + ) -> Self { + Self { + namespace, + 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 { + namespace: self.namespace, + 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. + pub fn scoped( + self, + with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result, + ) -> Result { + todo!(); + // let mut namespace = self.namespace.clone(); + // let ctx = SymbolResolveContext { + // namespace: &mut namespace, + // self_type: self.self_type, + // const_shadowing_mode: self.const_shadowing_mode, + // generic_shadowing_mode: self.generic_shadowing_mode, + // engines: self.engines, + // }; + // with_scoped_ctx(ctx) + } + + /// Enter the submodule with the given name and produce a type-check context ready for + /// symbol resolving its content. + /// + /// Returns the result of the given `with_submod_ctx` function. + pub fn enter_submodule( + mut self, + mod_name: Ident, + visibility: Visibility, + module_span: Span, + with_submod_ctx: impl FnOnce(SymbolResolveContext) -> T, + ) -> T { + // We're checking a submodule, so no need to pass through anything other than the + // namespace and the engines. + let engines = self.engines; + let symbol_collection_ctx = self.symbol_collection_ctx; + + let mut submod_ns = + self.namespace_mut() + .enter_submodule(engines, mod_name, visibility, module_span); + let submod_ctx = SymbolResolveContext::new(&mut submod_ns, engines, symbol_collection_ctx); + with_submod_ctx(submod_ctx) + } + + /// Returns a mutable reference to the current namespace. + pub fn namespace_mut(&mut self) -> &mut Namespace { + self.namespace + } + + /// Returns a reference to the current namespace. + pub fn namespace(&self) -> &Namespace { + self.namespace + } + + /// Map this `SymbolResolveContext` instance to a new one with the given const shadowing `mode`. + 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`. + 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`. + + pub(crate) fn self_type(&self) -> Option { + self.self_type + } + + pub(crate) fn const_shadowing_mode(&self) -> ConstShadowingMode { + self.const_shadowing_mode + } + + pub(crate) fn generic_shadowing_mode(&self) -> GenericShadowingMode { + self.generic_shadowing_mode + } + + // Provide some convenience functions around the inner context. + + /// Short-hand for calling [Namespace::insert_symbol] with the `const_shadowing_mode` provided by + /// the `SymbolResolveContext`. + pub(crate) fn insert_symbol( + &mut self, + handler: &Handler, + name: Ident, + item: TyDecl, + ) -> Result<(), ErrorEmitted> { + let const_shadowing_mode = self.const_shadowing_mode; + let generic_shadowing_mode = self.generic_shadowing_mode; + let engines = self.engines(); + self.namespace_mut() + .module_mut(engines) + .current_items_mut() + .insert_symbol( + handler, + engines, + name, + item, + const_shadowing_mode, + 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)] + 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 + 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) + } + + 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, + ) + } + + 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)] + 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. + 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 + 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(), + })) + } + } + + /// Short-hand for performing a [Module::star_import] with `mod_path` as the destination. + pub(crate) fn star_import( + &mut self, + handler: &Handler, + src: &ModulePath, + ) -> Result<(), ErrorEmitted> { + let engines = self.engines; + let mod_path = self.namespace().mod_path.clone(); + self.namespace_mut() + .root + .star_import(handler, engines, src, &mod_path) + } + + /// Short-hand for performing a [Module::variant_star_import] with `mod_path` as the destination. + pub(crate) fn variant_star_import( + &mut self, + handler: &Handler, + src: &ModulePath, + enum_name: &Ident, + ) -> Result<(), ErrorEmitted> { + let engines = self.engines; + let mod_path = self.namespace().mod_path.clone(); + self.namespace_mut() + .root + .variant_star_import(handler, engines, src, &mod_path, enum_name) + } + + /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination. + pub(crate) fn self_import( + &mut self, + handler: &Handler, + src: &ModulePath, + alias: Option, + ) -> Result<(), ErrorEmitted> { + let engines = self.engines; + let mod_path = self.namespace().mod_path.clone(); + self.namespace_mut() + .root + .self_import(handler, engines, src, &mod_path, alias) + } + + /// Short-hand for performing a [Module::item_import] with `mod_path` as the destination. + pub(crate) fn item_import( + &mut self, + handler: &Handler, + src: &ModulePath, + item: &Ident, + alias: Option, + ) -> Result<(), ErrorEmitted> { + let engines = self.engines; + let mod_path = self.namespace().mod_path.clone(); + self.namespace_mut() + .root + .item_import(handler, engines, src, item, &mod_path, alias) + } + + /// Short-hand for performing a [Module::variant_import] with `mod_path` as the destination. + #[allow(clippy::too_many_arguments)] + pub(crate) fn variant_import( + &mut self, + handler: &Handler, + src: &ModulePath, + enum_name: &Ident, + variant_name: &Ident, + alias: Option, + ) -> Result<(), ErrorEmitted> { + let engines = self.engines; + let mod_path = self.namespace().mod_path.clone(); + self.namespace_mut().root.variant_import( + handler, + engines, + src, + enum_name, + variant_name, + &mod_path, + alias, + ) + } + + #[allow(clippy::too_many_arguments)] + pub(crate) fn insert_trait_implementation( + &mut self, + handler: &Handler, + trait_name: CallPath, + trait_type_args: Vec, + type_id: TypeId, + items: &[ResolvedTraitImplItem], + impl_span: &Span, + trait_decl_span: Option, + is_impl_self: IsImplSelf, + is_extending_existing_impl: IsExtendingExistingImpl, + ) -> Result<(), ErrorEmitted> { + // Use trait name with full path, improves consistency between + // this inserting and getting in `get_methods_for_type_and_trait_name`. + let full_trait_name = trait_name.to_fullpath(self.engines(), self.namespace()); + let engines = self.engines; + + self.namespace_mut() + .module_mut(engines) + .current_items_mut() + .implemented_traits + .insert( + handler, + full_trait_name, + trait_type_args, + type_id, + items, + impl_span, + trait_decl_span, + is_impl_self, + is_extending_existing_impl, + engines, + ) + } + + 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, &[]) + } + + 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() + } +} + +pub(crate) trait MonomorphizeHelper { + fn name(&self) -> &Ident; + fn type_parameters(&self) -> &[TypeParameter]; + fn has_self_type_param(&self) -> bool; +} + +/// 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..3815db19874 100644 --- a/sway-core/src/transform/to_parsed_lang/context.rs +++ b/sway-core/src/transform/to_parsed_lang/context.rs @@ -1,4 +1,4 @@ -use crate::{build_config::ExperimentalFlags, language::parsed::TreeType, BuildTarget}; +use crate::{build_config::ExperimentalFlags, language::parsed::{TreeType, Declaration}, BuildTarget}; pub struct Context { pub experimental: ExperimentalFlags, @@ -21,6 +21,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 +37,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 1f2ab37ce26..78a7998e7e5 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, })) } diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 80b1dcb261b..9f6c867f538 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -2,10 +2,13 @@ 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::StructDeclaration, ty, CallPath, QualifiedCallPath}, + semantic_analysis::{ + symbol_resolve_context::SymbolResolveContext, type_check_context::EnforceTypeArguments, + TypeCheckContext, symbol_resolve::ResolveSymbols, + }, type_system::priv_prelude::*, Ident, }; @@ -161,6 +164,17 @@ impl TypeBinding { span: self.span, } } + + pub(crate) fn resolve_symbols(&mut self, mut ctx: SymbolResolveContext<'_>) { + match self.type_arguments { + TypeArgs::Regular(ref mut args) => { + args.iter_mut().for_each(|arg| arg.resolve_symbols(ctx.by_ref())) + } + TypeArgs::Prefix(ref mut args) => { + args.iter_mut().for_each(|arg| arg.resolve_symbols(ctx.by_ref())) + } + } + } } impl TypeBinding> { @@ -219,6 +233,15 @@ 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 TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -278,6 +301,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;