diff --git a/sway-core/src/decl_engine/engine.rs b/sway-core/src/decl_engine/engine.rs index 8f992f119bd..6dca672b734 100644 --- a/sway-core/src/decl_engine/engine.rs +++ b/sway-core/src/decl_engine/engine.rs @@ -13,9 +13,10 @@ use crate::{ engine_threading::*, language::{ parsed::{ - AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, EnumDeclaration, - FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, StructDeclaration, - TraitDeclaration, TraitFn, TraitTypeDeclaration, TypeAliasDeclaration, + AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, Declaration, + EnumDeclaration, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, + StructDeclaration, TraitDeclaration, TraitFn, TraitTypeDeclaration, + TypeAliasDeclaration, }, ty::{ self, TyAbiDecl, TyConfigurableDecl, TyConstantDecl, TyDeclParsedType, TyEnumDecl, @@ -122,6 +123,13 @@ where fn get_parsed_decl_id(&self, decl_id: &DeclId) -> Option>; } +pub trait DeclEngineGetParsedDecl +where + T: TyDeclParsedType, +{ + fn get_parsed_decl(&self, decl_id: &DeclId) -> Option; +} + pub trait DeclEngineInsert where T: Named + Spanned + TyDeclParsedType, @@ -288,6 +296,82 @@ decl_engine_parsed_decl_id!(configurable_parsed_decl_id_map, ty::TyConfigurableD decl_engine_parsed_decl_id!(enum_parsed_decl_id_map, ty::TyEnumDecl); decl_engine_parsed_decl_id!(type_alias_parsed_decl_id_map, ty::TyTypeAliasDecl); +macro_rules! decl_engine_parsed_decl { + ($slab:ident, $decl:ty, $ctor:expr) => { + impl DeclEngineGetParsedDecl<$decl> for DeclEngine { + fn get_parsed_decl(&self, decl_id: &DeclId<$decl>) -> Option { + let parsed_decl_id_map = self.$slab.read(); + if let Some(parsed_decl_id) = parsed_decl_id_map.get(&decl_id) { + return Some($ctor(parsed_decl_id.clone())); + } else { + None + } + } + } + }; +} + +decl_engine_parsed_decl!( + function_parsed_decl_id_map, + ty::TyFunctionDecl, + Declaration::FunctionDeclaration +); +decl_engine_parsed_decl!( + trait_parsed_decl_id_map, + ty::TyTraitDecl, + Declaration::TraitDeclaration +); +decl_engine_parsed_decl!( + trait_fn_parsed_decl_id_map, + ty::TyTraitFn, + Declaration::TraitFnDeclaration +); +decl_engine_parsed_decl!( + trait_type_parsed_decl_id_map, + ty::TyTraitType, + Declaration::TraitTypeDeclaration +); +decl_engine_parsed_decl!( + impl_self_or_trait_parsed_decl_id_map, + ty::TyImplSelfOrTrait, + Declaration::ImplSelfOrTrait +); +decl_engine_parsed_decl!( + struct_parsed_decl_id_map, + ty::TyStructDecl, + Declaration::StructDeclaration +); +decl_engine_parsed_decl!( + storage_parsed_decl_id_map, + ty::TyStorageDecl, + Declaration::StorageDeclaration +); +decl_engine_parsed_decl!( + abi_parsed_decl_id_map, + ty::TyAbiDecl, + Declaration::AbiDeclaration +); +decl_engine_parsed_decl!( + constant_parsed_decl_id_map, + ty::TyConstantDecl, + Declaration::ConstantDeclaration +); +decl_engine_parsed_decl!( + configurable_parsed_decl_id_map, + ty::TyConfigurableDecl, + Declaration::ConfigurableDeclaration +); +decl_engine_parsed_decl!( + enum_parsed_decl_id_map, + ty::TyEnumDecl, + Declaration::EnumDeclaration +); +decl_engine_parsed_decl!( + type_alias_parsed_decl_id_map, + ty::TyTypeAliasDecl, + Declaration::TypeAliasDeclaration +); + macro_rules! decl_engine_replace { ($slab:ident, $decl:ty) => { impl DeclEngineReplace<$decl> for DeclEngine { diff --git a/sway-core/src/decl_engine/parsed_engine.rs b/sway-core/src/decl_engine/parsed_engine.rs index 8b8f84107eb..6977a86e7f6 100644 --- a/sway-core/src/decl_engine/parsed_engine.rs +++ b/sway-core/src/decl_engine/parsed_engine.rs @@ -100,6 +100,30 @@ decl_engine_insert!(enum_slab, EnumDeclaration); decl_engine_insert!(enum_variant_slab, EnumVariant); decl_engine_insert!(type_alias_slab, TypeAliasDeclaration); +macro_rules! decl_engine_replace { + ($slab:ident, $decl:ty) => { + impl ParsedDeclEngineReplace<$decl> for ParsedDeclEngine { + fn replace(&self, index: ParsedDeclId<$decl>, decl: $decl) { + self.$slab.replace(index.inner(), decl); + } + } + }; +} + +decl_engine_replace!(variable_slab, VariableDeclaration); +decl_engine_replace!(function_slab, FunctionDeclaration); +decl_engine_replace!(trait_slab, TraitDeclaration); +decl_engine_replace!(trait_fn_slab, TraitFn); +decl_engine_replace!(trait_type_slab, TraitTypeDeclaration); +decl_engine_replace!(impl_self_or_trait_slab, ImplSelfOrTrait); +decl_engine_replace!(struct_slab, StructDeclaration); +decl_engine_replace!(storage_slab, StorageDeclaration); +decl_engine_replace!(abi_slab, AbiDeclaration); +decl_engine_replace!(configurable_slab, ConfigurableDeclaration); +decl_engine_replace!(constant_slab, ConstantDeclaration); +decl_engine_replace!(enum_slab, EnumDeclaration); +decl_engine_replace!(type_alias_slab, TypeAliasDeclaration); + macro_rules! decl_engine_clear { ($($slab:ident, $decl:ty);* $(;)?) => { impl ParsedDeclEngine { diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index 7c6ba2502f7..8036d3ecab8 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -215,6 +215,12 @@ impl OrdWithEngines for CallPath { } } +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct ResolvedCallPath { + pub decl: T, + pub unresolved_call_path: CallPath, +} + impl std::convert::From for CallPath { fn from(other: Ident) -> Self { CallPath { diff --git a/sway-core/src/language/parsed/declaration.rs b/sway-core/src/language/parsed/declaration.rs index c6a04c93789..a47c4895c1b 100644 --- a/sway-core/src/language/parsed/declaration.rs +++ b/sway-core/src/language/parsed/declaration.rs @@ -21,6 +21,10 @@ pub use r#enum::*; pub use r#struct::*; pub use r#trait::*; pub use storage::*; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; pub use type_alias::*; pub use variable::*; @@ -29,6 +33,7 @@ use crate::{ decl_engine::{ parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet}, parsed_id::ParsedDeclId, + DeclEngineGetParsedDeclId, }, engine_threading::{ DebugWithEngines, DisplayWithEngines, EqWithEngines, PartialEqWithEngines, @@ -53,6 +58,7 @@ pub enum Declaration { StorageDeclaration(ParsedDeclId), TypeAliasDeclaration(ParsedDeclId), TraitTypeDeclaration(ParsedDeclId), + TraitFnDeclaration(ParsedDeclId), } #[derive(Debug, Clone)] @@ -84,6 +90,7 @@ impl Declaration { TraitTypeDeclaration(_) => "type", FunctionDeclaration(_) => "function", TraitDeclaration(_) => "trait", + TraitFnDeclaration(_) => "trait fn", StructDeclaration(_) => "struct", EnumDeclaration(_) => "enum", EnumVariantDeclaration(_) => "enum variant", @@ -111,9 +118,55 @@ impl Declaration { StorageDeclaration(decl_id) => pe.get_storage(decl_id).span(), TypeAliasDeclaration(decl_id) => pe.get_type_alias(decl_id).span(), TraitTypeDeclaration(decl_id) => pe.get_trait_type(decl_id).span(), + TraitFnDeclaration(decl_id) => pe.get_trait_fn(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), + Declaration::TypeAliasDeclaration(decl_id) => { + let alias = engines.pe().get_type_alias(decl_id); + let struct_decl_id = engines.te().get(alias.ty.type_id).expect_struct( + handler, + engines, + &self.span(engines), + )?; + + let parsed_decl_id = engines.de().get_parsed_decl_id(&struct_decl_id); + parsed_decl_id.ok_or_else(|| { + handler.emit_err(CompileError::InternalOwned( + "Cannot get parsed decl id from decl id".to_string(), + self.span(engines), + )) + }) + } + 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, @@ -138,7 +191,8 @@ impl Declaration { Declaration::ImplSelfOrTrait(_) | Declaration::StorageDeclaration(_) | Declaration::AbiDeclaration(_) - | Declaration::TraitTypeDeclaration(_) => Visibility::Public, + | Declaration::TraitTypeDeclaration(_) + | Declaration::TraitFnDeclaration(_) => Visibility::Public, } } } diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index 6232810f8f3..afd61ef54d3 100644 --- a/sway-core/src/language/parsed/declaration/function.rs +++ b/sway-core/src/language/parsed/declaration/function.rs @@ -1,6 +1,7 @@ use crate::{ engine_threading::*, language::{parsed::*, *}, + namespace::LexicalScopeId, transform::{self, AttributeKind}, type_system::*, }; @@ -27,6 +28,8 @@ pub struct FunctionDeclaration { pub type_parameters: Vec, pub where_clause: Vec<(Ident, Vec)>, pub kind: FunctionDeclarationKind, + pub implementing_type: Option, + pub lexical_scope: LexicalScopeId, } impl EqWithEngines for FunctionDeclaration {} diff --git a/sway-core/src/language/parsed/declaration/impl_trait.rs b/sway-core/src/language/parsed/declaration/impl_trait.rs index d6ba0a05535..48ba779155e 100644 --- a/sway-core/src/language/parsed/declaration/impl_trait.rs +++ b/sway-core/src/language/parsed/declaration/impl_trait.rs @@ -1,6 +1,6 @@ use super::{ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration}; use crate::{ - decl_engine::parsed_id::ParsedDeclId, + decl_engine::{parsed_id::ParsedDeclId, ParsedInterfaceDeclId}, engine_threading::{ DebugWithEngines, EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, }, @@ -69,6 +69,7 @@ pub struct ImplSelfOrTrait { pub impl_type_parameters: Vec, pub trait_name: CallPath, pub trait_type_arguments: Vec, + pub trait_decl_ref: Option, pub implementing_for: TypeArgument, pub items: Vec, // the span of the whole impl trait and block diff --git a/sway-core/src/language/parsed/declaration/trait.rs b/sway-core/src/language/parsed/declaration/trait.rs index 35625083453..12e76e554c6 100644 --- a/sway-core/src/language/parsed/declaration/trait.rs +++ b/sway-core/src/language/parsed/declaration/trait.rs @@ -120,6 +120,12 @@ pub struct TraitFn { pub return_type: TypeArgument, } +impl Spanned for TraitFn { + fn span(&self) -> sway_types::Span { + self.span.clone() + } +} + #[derive(Debug, Clone)] pub struct TraitTypeDeclaration { pub name: Ident, diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 73ab3a33cbb..90d41fbf19b 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -1,6 +1,7 @@ use std::{cmp::Ordering, fmt, hash::Hasher}; use crate::{ + decl_engine::parsed_id::ParsedDeclId, engine_threading::{ DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines, OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext, @@ -22,6 +23,8 @@ pub use method_name::MethodName; pub use scrutinee::*; use sway_ast::intrinsics::Intrinsic; +use super::{FunctionDeclaration, StructDeclaration}; + /// Represents a parsed, but not yet type checked, [Expression](https://en.wikipedia.org/wiki/Expression_(computer_science)). #[derive(Debug, Clone)] pub struct Expression { @@ -32,6 +35,8 @@ pub struct Expression { #[derive(Debug, Clone)] pub struct FunctionApplicationExpression { pub call_path_binding: TypeBinding, + pub resolved_call_path_binding: + Option>>>, pub arguments: Vec, } @@ -88,6 +93,8 @@ impl PartialEqWithEngines for ArrayExpression { #[derive(Debug, Clone)] pub struct StructExpression { + pub resolved_call_path_binding: + Option>>>, pub call_path_binding: TypeBinding, pub fields: Vec, } diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index e3adb11ce4e..61363124c11 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -12,7 +12,7 @@ use sway_types::{Ident, Named, Span, Spanned}; use crate::{ decl_engine::*, engine_threading::*, - language::{ty::*, Visibility}, + language::{parsed::Declaration, ty::*, Visibility}, type_system::*, types::*, }; @@ -496,6 +496,26 @@ impl GetDeclIdent for TyDecl { } impl TyDecl { + pub(crate) fn get_parsed_decl(&self, decl_engine: &DeclEngine) -> Option { + match self { + TyDecl::VariableDecl(_decl) => None, + TyDecl::ConstantDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::ConfigurableDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::TraitTypeDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::FunctionDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::TraitDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::StructDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::EnumDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::EnumVariantDecl(decl) => decl_engine.get_parsed_decl(decl.enum_ref.id()), + TyDecl::ImplSelfOrTrait(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::AbiDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::GenericTypeForFunctionScope(_data) => None, + TyDecl::ErrorRecovery(_, _) => None, + TyDecl::StorageDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + TyDecl::TypeAliasDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id), + } + } + /// Retrieves the declaration as a `DeclId`. /// /// Returns an error if `self` is not the [TyDecl][EnumDecl] variant. @@ -535,7 +555,7 @@ impl TyDecl { /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][StructDecl] variant. - pub(crate) fn to_struct_id( + pub(crate) fn to_struct_decl( &self, handler: &Handler, engines: &Engines, diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index bdc7e683ceb..51bac2d6a24 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -34,6 +34,8 @@ pub use debug_generation::write_dwarf; use indexmap::IndexMap; use metadata::MetadataManager; use query_engine::{ModuleCacheKey, ModulePath, ProgramsCacheEntry}; +use semantic_analysis::symbol_resolve::ResolveSymbols; +use semantic_analysis::symbol_resolve_context::SymbolResolveContext; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -537,9 +539,13 @@ pub fn parsed_to_ast( let namespace = Namespace::init_root(initial_namespace); // Collect the program symbols. - let _collection_ctx = + let mut symbol_collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; + // Resolve the program symbols. + let resolve_ctx = SymbolResolveContext::new(engines, &mut symbol_collection_ctx); + parse_program.resolve_symbols(handler, resolve_ctx); + // Type check the program. let typed_program_opt = ty::TyProgram::type_check( handler, diff --git a/sway-core/src/semantic_analysis.rs b/sway-core/src/semantic_analysis.rs index 2988080309e..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 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/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index 485fe51fa4d..41fa19bb75a 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -5,6 +5,22 @@ use crate::language::{ }; impl ty::TyCodeBlock { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + code_block: &CodeBlock, + ) -> Result<(), ErrorEmitted> { + let _ = code_block + .contents + .iter() + .map(|node| ty::TyAstNode::collect(handler, engines, ctx, node)) + .filter_map(|res| res.ok()) + .collect::>(); + + Ok(()) + } + pub(crate) fn type_check( handler: &Handler, ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 2731811f6a7..d495c142fe1 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -405,7 +405,7 @@ where return Some((None, None)); } - let implementing_for_decl_id = decl.to_struct_id(&Handler::default(), engines).unwrap(); + let implementing_for_decl_id = decl.to_struct_decl(&Handler::default(), engines).unwrap(); let struct_decl = self.ctx.engines().de().get(&implementing_for_decl_id); let program_id = struct_decl.span().source_id().map(|sid| sid.program_id()); 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 1c4b1d977b6..3f37865215a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -2,17 +2,21 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Named, Spanned}; use crate::{ - decl_engine::{DeclEngineGet, DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, + decl_engine::{ + parsed_engine::ParsedDeclEngineReplace, DeclEngineGet, DeclEngineInsert, DeclRef, + ReplaceFunctionImplementingType, + }, language::{ parsed::{self, StorageEntry}, - ty::{self, FunctionDecl, TyDecl, TyStorageField}, + ty::{self, FunctionDecl, TyCodeBlock, TyDecl, TyStorageField}, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ - 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, @@ -42,14 +46,24 @@ impl TyDecl { let trait_type_decl = engines.pe().get_trait_type(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, trait_type_decl.name.clone(), decl)?; } + parsed::Declaration::TraitFnDeclaration(decl_id) => { + let trait_fn_decl = engines.pe().get_trait_fn(decl_id).as_ref().clone(); + ctx.insert_parsed_symbol(handler, engines, trait_fn_decl.name.clone(), decl)?; + } parsed::Declaration::EnumDeclaration(decl_id) => { let enum_decl = engines.pe().get_enum(decl_id).as_ref().clone(); ctx.insert_parsed_symbol(handler, engines, enum_decl.name.clone(), decl)?; } parsed::Declaration::EnumVariantDeclaration(_decl) => {} parsed::Declaration::FunctionDeclaration(decl_id) => { - let fn_decl = engines.pe().get_function(decl_id); + let decl_id = *decl_id; + let mut fn_decl = engines.pe().get_function(&decl_id).as_ref().clone(); let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl); + let (_ret, lexical_scope_id) = ctx.scoped(engines, |scoped_ctx| { + TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) + }); + fn_decl.lexical_scope = lexical_scope_id; + engines.pe().replace(decl_id, fn_decl); } parsed::Declaration::TraitDeclaration(decl_id) => { let trait_decl = engines.pe().get_trait(decl_id).as_ref().clone(); @@ -609,6 +623,9 @@ impl TyDecl { ctx.insert_symbol(handler, name, decl.clone())?; decl } + parsed::Declaration::TraitFnDeclaration(_decl_id) => { + unreachable!(); + } }; Ok(decl) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index e65406772fa..5eca8e967d3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -37,6 +37,7 @@ impl TyImplSelfOrTrait { impl_type_parameters, trait_name, mut trait_type_arguments, + trait_decl_ref: _, mut implementing_for, items, block_span, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index 4f726c3b711..12ac36c44a6 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -233,7 +233,7 @@ fn type_check_struct( let unknown_decl = ctx.namespace() .resolve_symbol_typed(handler, engines, &struct_name, ctx.self_type())?; - let struct_id = unknown_decl.to_struct_id(handler, ctx.engines())?; + let struct_id = unknown_decl.to_struct_decl(handler, ctx.engines())?; let mut struct_decl = (*decl_engine.get_struct(&struct_id)).clone(); // monomorphize the struct definition diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index e5f5ca57586..c0d50699189 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -193,6 +193,7 @@ impl ty::TyExpression { ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { call_path_binding, + resolved_call_path_binding: _, ref arguments, } = *function_application_expression.clone(); Self::type_check_function_application( @@ -1107,7 +1108,7 @@ impl ty::TyExpression { None, )? .expect_typed(); - let storage_key_struct_decl_ref = storage_key_decl_opt.to_struct_id(handler, engines)?; + let storage_key_struct_decl_ref = storage_key_decl_opt.to_struct_decl(handler, engines)?; let mut storage_key_struct_decl = (*decl_engine.get_struct(&storage_key_struct_decl_ref)).clone(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index c281e67da0e..99c4dea63bf 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -504,6 +504,7 @@ pub(crate) fn type_check_method_application( ]), span: Span::dummy(), }, + resolved_call_path_binding: None, arguments: vec![ Expression { kind: ExpressionKind::Literal(Literal::B256([0u8; 32])), diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index aab6354cfc0..04aab70d407 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -19,7 +19,7 @@ use sway_error::{ }; use sway_types::{span::Span, Spanned}; -use super::collection_context::SymbolCollectionContext; +use super::symbol_collection_context::SymbolCollectionContext; impl ty::TyAstNode { pub(crate) fn collect( diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 2edc16ae3b7..f8910773695 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -24,8 +24,8 @@ use crate::{ }; use super::{ - collection_context::SymbolCollectionContext, declaration::auto_impl::{self, EncodingAutoImplContext}, + symbol_collection_context::SymbolCollectionContext, }; #[derive(Clone, Debug)] diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index bfa1f683945..e98c7f07f6d 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -229,7 +229,7 @@ impl Module { parent: Some(previous_scope_id), ..Default::default() }); - self.current_lexical_scope_id() + self.lexical_scopes.len() - 1 }; let previous_scope = self.lexical_scopes.get_mut(previous_scope_id).unwrap(); previous_scope.children.push(new_scoped_id); diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 7a8b00e4304..a3aed9205c9 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -310,7 +310,7 @@ impl Namespace { } /// Pushes a new submodule to the namespace's module hierarchy. - pub fn push_new_submodule( + pub fn push_submodule( &mut self, engines: &Engines, mod_name: Ident, diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 31480d5567a..19c50487499 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -4,11 +4,11 @@ use super::{ module::Module, namespace::Namespace, trait_map::TraitMap, Ident, ResolvedTraitImplItem, }; use crate::{ - decl_engine::DeclRef, + decl_engine::{DeclEngine, DeclRef}, engine_threading::*, language::{ parsed::*, - ty::{self, TyDecl, TyTraitItem}, + ty::{self, StructDecl, TyDecl, TyTraitItem}, CallPath, Visibility, }, namespace::{ModulePath, ModulePathBuf}, @@ -69,6 +69,15 @@ impl ResolvedDeclaration { } } + pub fn resolve_parsed(self, decl_engine: &DeclEngine) -> Declaration { + match self { + ResolvedDeclaration::Parsed(decl) => decl, + ResolvedDeclaration::Typed(ty_decl) => ty_decl + .get_parsed_decl(decl_engine) + .expect("expecting valid parsed declaration"), + } + } + pub fn expect_parsed(self) -> Declaration { match self { ResolvedDeclaration::Parsed(decl) => decl, @@ -90,6 +99,21 @@ impl ResolvedDeclaration { } } + pub(crate) fn to_struct_decl( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result { + match self { + ResolvedDeclaration::Parsed(decl) => decl + .to_struct_decl(handler, engines) + .map(|id| ResolvedDeclaration::Parsed(Declaration::StructDeclaration(id))), + ResolvedDeclaration::Typed(decl) => decl.to_struct_decl(handler, engines).map(|id| { + ResolvedDeclaration::Typed(TyDecl::StructDecl(StructDecl { decl_id: id })) + }), + } + } + pub(crate) fn visibility(&self, engines: &Engines) -> Visibility { match self { ResolvedDeclaration::Parsed(decl) => decl.visibility(engines.pe()), @@ -982,10 +1006,6 @@ 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(decl.clone()); - } // 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(decl.clone()); diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 45d2858a1b8..1b8b7cc1930 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -315,6 +315,10 @@ impl Dependencies { let decl = engines.pe().get_trait_type(decl_id); self.gather_from_type_decl(engines, &decl) } + Declaration::TraitFnDeclaration(decl_id) => { + let decl = engines.pe().get_trait_fn(decl_id); + self.gather_from_trait_fn_decl(engines, &decl) + } Declaration::FunctionDeclaration(decl_id) => { let fn_decl = engines.pe().get_function(decl_id); self.gather_from_fn_decl(engines, &fn_decl) @@ -505,6 +509,18 @@ impl Dependencies { } } + fn gather_from_trait_fn_decl(self, engines: &Engines, fn_decl: &TraitFn) -> Self { + let TraitFn { + parameters, + return_type, + .. + } = fn_decl; + self.gather_from_iter(parameters.iter(), |deps, param| { + deps.gather_from_type_argument(engines, ¶m.type_argument) + }) + .gather_from_type_argument(engines, return_type) + } + fn gather_from_fn_decl(self, engines: &Engines, fn_decl: &FunctionDeclaration) -> Self { let FunctionDeclaration { parameters, @@ -534,6 +550,7 @@ impl Dependencies { ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { call_path_binding, + resolved_call_path_binding: _, arguments, } = &**function_application_expression; self.gather_from_call_path(&call_path_binding.inner, false, true) @@ -575,6 +592,7 @@ impl Dependencies { ExpressionKind::Struct(struct_expression) => { let StructExpression { call_path_binding, + resolved_call_path_binding: _, fields, } = &**struct_expression; self.gather_from_call_path(&call_path_binding.inner, false, false) @@ -894,6 +912,10 @@ fn decl_name(engines: &Engines, decl: &Declaration) -> Option { let decl = engines.pe().get_trait_type(decl_id); dep_sym(decl.name.clone()) } + Declaration::TraitFnDeclaration(decl_id) => { + let decl = engines.pe().get_trait_fn(decl_id); + dep_sym(decl.name.clone()) + } Declaration::StructDeclaration(decl_id) => { let decl = engines.pe().get_struct(decl_id); dep_sym(decl.name.clone()) diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index 71f73f359d7..ab83749d2f5 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -14,12 +14,12 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_ir::{Context, Module}; use super::{ - collection_context::SymbolCollectionContext, TypeCheckAnalysis, TypeCheckAnalysisContext, - TypeCheckFinalization, TypeCheckFinalizationContext, + symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis, + TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext, }; 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/collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs similarity index 85% rename from sway-core/src/semantic_analysis/collection_context.rs rename to sway-core/src/semantic_analysis/symbol_collection_context.rs index 8fb8937fc47..ca8d1c2b961 100644 --- a/sway-core/src/semantic_analysis/collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -1,5 +1,6 @@ use crate::{ language::{parsed::Declaration, Visibility}, + namespace::LexicalScopeId, namespace::ModulePath, semantic_analysis::Namespace, Engines, @@ -37,14 +38,34 @@ 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, - ) -> Result { + with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, + ) -> (Result, LexicalScopeId) { + let lexical_scope_id: LexicalScopeId = self + .namespace + .module_mut(engines) + .write(engines, |m| m.push_new_lexical_scope()); + let ret = with_scoped_ctx(self); + self.namespace + .module_mut(engines) + .write(engines, |m| m.pop_lexical_scope()); + (ret, lexical_scope_id) + } + + /// 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_scoped_ctx(self.clone()); + let ret = with_ctx(self); self.namespace .module_mut(engines) .write(engines, |m| m.pop_lexical_scope()); @@ -64,7 +85,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..60ac3da6a53 --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -0,0 +1,646 @@ +use sway_error::handler::Handler; + +use crate::{ + ast_elements::binding::SymbolResolveTypeBinding, + decl_engine::{parsed_engine::ParsedDeclEngineReplace, parsed_id::ParsedDeclId}, + language::{ + parsed::{ + AbiDeclaration, AstNode, AstNodeContent, CodeBlock, ConfigurableDeclaration, + ConstantDeclaration, Declaration, EnumDeclaration, EnumVariant, Expression, + ExpressionKind, FunctionDeclaration, FunctionParameter, ImplItem, ImplSelfOrTrait, + ParseModule, ParseProgram, ReassignmentTarget, Scrutinee, StorageDeclaration, + StorageEntry, StructDeclaration, StructExpressionField, StructField, + StructScrutineeField, Supertrait, TraitDeclaration, TraitFn, TraitItem, + TraitTypeDeclaration, TypeAliasDeclaration, VariableDeclaration, + }, + CallPath, CallPathTree, ResolvedCallPath, + }, + TraitConstraint, TypeArgument, TypeBinding, TypeParameter, +}; + +use super::symbol_resolve_context::SymbolResolveContext; + +pub trait ResolveSymbols { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext); +} + +impl ResolveSymbols for ParseProgram { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + let ParseProgram { root, .. } = self; + root.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for ParseModule { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + let ParseModule { + submodules, + tree, + module_eval_order, + attributes: _, + span: _, + hash: _, + .. + } = self; + + // Analyze submodules first in order of evaluation previously computed by the dependency graph. + module_eval_order.iter().for_each(|eval_mod_name| { + let (_name, submodule) = submodules + .iter_mut() + .find(|(submod_name, _submodule)| eval_mod_name == submod_name) + .unwrap(); + submodule.module.resolve_symbols(handler, ctx.by_ref()); + }); + + tree.root_nodes + .iter_mut() + .for_each(|node| node.resolve_symbols(handler, ctx.by_ref())) + } +} + +impl ResolveSymbols for AstNode { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match &mut self.content { + AstNodeContent::UseStatement(_) => {} + AstNodeContent::Declaration(decl) => decl.resolve_symbols(handler, ctx), + AstNodeContent::Expression(expr) => expr.resolve_symbols(handler, ctx), + AstNodeContent::IncludeStatement(_) => {} + AstNodeContent::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for Declaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match self { + Declaration::VariableDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::FunctionDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::StructDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::EnumDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::EnumVariantDeclaration(_decl) => unreachable!(), + Declaration::ImplSelfOrTrait(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::AbiDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::ConstantDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::StorageDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TypeAliasDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitTypeDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::TraitFnDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + Declaration::ConfigurableDeclaration(decl_id) => decl_id.resolve_symbols(handler, ctx), + } + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut var_decl = pe.get_variable(self).as_ref().clone(); + var_decl.body.resolve_symbols(handler, ctx); + pe.replace(*self, var_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut fn_decl = pe.get_function(self).as_ref().clone(); + fn_decl.body.resolve_symbols(handler, ctx); + pe.replace(*self, fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_decl = ctx.engines().pe().get_trait(self).as_ref().clone(); + trait_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut struct_decl = ctx.engines().pe().get_struct(self).as_ref().clone(); + struct_decl.resolve_symbols(handler, ctx); + pe.replace(*self, struct_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut enum_decl = ctx.engines().pe().get_enum(self).as_ref().clone(); + enum_decl.resolve_symbols(handler, ctx); + pe.replace(*self, enum_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut configurable_decl = ctx.engines().pe().get_configurable(self).as_ref().clone(); + configurable_decl.resolve_symbols(handler, ctx); + pe.replace(*self, configurable_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut constant_decl = ctx.engines().pe().get_constant(self).as_ref().clone(); + constant_decl.resolve_symbols(handler, ctx); + pe.replace(*self, constant_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_type_decl = ctx.engines().pe().get_trait_type(self).as_ref().clone(); + trait_type_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_type_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut trait_fn_decl = ctx.engines().pe().get_trait_fn(self).as_ref().clone(); + trait_fn_decl.resolve_symbols(handler, ctx); + pe.replace(*self, trait_fn_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut impl_self_or_trait = ctx + .engines() + .pe() + .get_impl_self_or_trait(self) + .as_ref() + .clone(); + impl_self_or_trait.resolve_symbols(handler, ctx); + pe.replace(*self, impl_self_or_trait); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut abi_decl = ctx.engines().pe().get_abi(self).as_ref().clone(); + abi_decl.resolve_symbols(handler, ctx); + pe.replace(*self, abi_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut storage_decl = ctx.engines().pe().get_storage(self).as_ref().clone(); + storage_decl.resolve_symbols(handler, ctx); + pe.replace(*self, storage_decl); + } +} + +impl ResolveSymbols for ParsedDeclId { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + let pe = ctx.engines().pe(); + let mut type_alias = ctx.engines().pe().get_type_alias(self).as_ref().clone(); + type_alias.resolve_symbols(handler, ctx); + pe.replace(*self, type_alias); + } +} + +impl ResolveSymbols for ConfigurableDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_ascription.resolve_symbols(handler, ctx.by_ref()); + if let Some(value) = self.value.as_mut() { + value.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for ConstantDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_ascription.resolve_symbols(handler, ctx.by_ref()); + if let Some(value) = self.value.as_mut() { + value.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_parameters + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + self.fields + .iter_mut() + .for_each(|f| f.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.supertraits + .iter_mut() + .for_each(|st| st.resolve_symbols(handler, ctx.by_ref())); + 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())); + } +} + +impl ResolveSymbols for AbiDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.supertraits + .iter_mut() + .for_each(|st| st.resolve_symbols(handler, ctx.by_ref())); + 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())); + } +} + +impl ResolveSymbols for TraitItem { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + TraitItem::TraitFn(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Constant(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Type(ref mut id) => id.resolve_symbols(handler, ctx.by_ref()), + TraitItem::Error(_, _) => {} + } + } +} + +impl ResolveSymbols for TraitFn { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + self.return_type.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for Supertrait { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.name.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for FunctionParameter { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.type_argument.resolve_symbols(handler, ctx.by_ref()); + } +} + +impl ResolveSymbols for ImplSelfOrTrait { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.impl_type_parameters + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())); + self.trait_name.resolve_symbols(handler, ctx.by_ref()); + self.trait_type_arguments + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + self.implementing_for.resolve_symbols(handler, ctx.by_ref()); + self.items + .iter_mut() + .for_each(|tp| tp.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for ImplItem { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + match self { + ImplItem::Fn(decl_id) => decl_id.resolve_symbols(handler, ctx), + ImplItem::Constant(decl_id) => decl_id.resolve_symbols(handler, ctx), + ImplItem::Type(decl_id) => decl_id.resolve_symbols(handler, ctx), + } + } +} + +impl ResolveSymbols for TraitTypeDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + if let Some(ty) = self.ty_opt.as_mut() { + ty.resolve_symbols(handler, ctx) + } + } +} + +impl ResolveSymbols for StorageDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.entries + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for StorageEntry { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + StorageEntry::Namespace(ref mut ns) => { + ns.entries + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())); + } + StorageEntry::Field(ref mut f) => { + f.type_argument.resolve_symbols(handler, ctx.by_ref()); + f.initializer.resolve_symbols(handler, ctx.by_ref()); + } + } + } +} + +impl ResolveSymbols for TypeAliasDeclaration { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.ty.resolve_symbols(handler, ctx) + } +} + +impl ResolveSymbols for TypeArgument { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + if let Some(call_path) = self.call_path_tree.as_mut() { + call_path.resolve_symbols(handler, ctx); + } + } +} + +impl ResolveSymbols for TypeParameter { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.trait_constraints + .iter_mut() + .for_each(|tc| tc.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for TraitConstraint { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + self.trait_name.resolve_symbols(handler, ctx.by_ref()); + self.type_arguments + .iter_mut() + .for_each(|tc| tc.resolve_symbols(handler, ctx.by_ref())); + } +} + +impl ResolveSymbols for CallPath { + fn resolve_symbols(&mut self, _handler: &Handler, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CallPathTree { + fn resolve_symbols(&mut self, _handler: &Handler, _ctx: SymbolResolveContext) {} +} + +impl ResolveSymbols for CodeBlock { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + for expr in self.contents.iter_mut() { + expr.resolve_symbols(handler, ctx.by_ref()) + } + } +} + +impl ResolveSymbols for StructExpressionField { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.value.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for Scrutinee { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + Scrutinee::Or { + ref mut elems, + span: _, + } => elems + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())), + Scrutinee::CatchAll { .. } => {} + Scrutinee::Literal { .. } => {} + Scrutinee::Variable { .. } => {} + Scrutinee::AmbiguousSingleIdent(_) => {} + Scrutinee::StructScrutinee { + struct_name, + fields, + span: _, + } => { + struct_name.resolve_symbols(handler, ctx.by_ref()); + fields + .iter_mut() + .for_each(|f| f.resolve_symbols(handler, ctx.by_ref())) + } + Scrutinee::EnumScrutinee { + call_path, + value, + span: _, + } => { + call_path.resolve_symbols(handler, ctx.by_ref()); + value.resolve_symbols(handler, ctx.by_ref()); + } + Scrutinee::Tuple { elems, span: _ } => { + elems + .iter_mut() + .for_each(|s| s.resolve_symbols(handler, ctx.by_ref())); + } + Scrutinee::Error { .. } => {} + } + } +} + +impl ResolveSymbols for StructScrutineeField { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + StructScrutineeField::Rest { .. } => {} + StructScrutineeField::Field { + field: _, + scrutinee, + span: _, + } => { + if let Some(scrutinee) = scrutinee.as_mut() { + scrutinee.resolve_symbols(handler, ctx.by_ref()); + } + } + } + } +} + +impl ResolveSymbols for Expression { + fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { + self.kind.resolve_symbols(handler, ctx); + } +} + +impl ResolveSymbols for ExpressionKind { + fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext) { + match self { + ExpressionKind::Error(_, _) => {} + ExpressionKind::Literal(_) => {} + ExpressionKind::AmbiguousPathExpression(_) => {} + ExpressionKind::FunctionApplication(expr) => { + let result = SymbolResolveTypeBinding::resolve_symbol( + &mut expr.call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + if let Ok(result) = result { + expr.resolved_call_path_binding = Some(TypeBinding::< + ResolvedCallPath>, + > { + inner: ResolvedCallPath { + decl: result, + unresolved_call_path: expr.call_path_binding.inner.clone(), + }, + span: expr.call_path_binding.span.clone(), + type_arguments: expr.call_path_binding.type_arguments.clone(), + }); + } + expr.arguments + .iter_mut() + .for_each(|a| a.resolve_symbols(handler, ctx.by_ref())) + } + ExpressionKind::LazyOperator(expr) => { + expr.lhs.resolve_symbols(handler, ctx.by_ref()); + expr.rhs.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::AmbiguousVariableExpression(_) => {} + ExpressionKind::Variable(_) => {} + ExpressionKind::Tuple(exprs) => { + exprs + .iter_mut() + .for_each(|expr| expr.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::TupleIndex(expr) => { + expr.prefix.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::Array(expr) => expr + .contents + .iter_mut() + .for_each(|e| e.resolve_symbols(handler, ctx.by_ref())), + ExpressionKind::Struct(expr) => { + expr.call_path_binding + .resolve_symbols(handler, ctx.by_ref()); + let result = SymbolResolveTypeBinding::resolve_symbol( + &mut expr.call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + if let Ok(result) = result { + expr.resolved_call_path_binding = Some(TypeBinding::< + ResolvedCallPath>, + > { + inner: ResolvedCallPath { + decl: result, + unresolved_call_path: expr.call_path_binding.inner.clone(), + }, + span: expr.call_path_binding.span.clone(), + type_arguments: expr.call_path_binding.type_arguments.clone(), + }); + } + } + ExpressionKind::CodeBlock(block) => { + block + .contents + .iter_mut() + .for_each(|node| node.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::If(expr) => { + expr.condition.resolve_symbols(handler, ctx.by_ref()); + expr.then.resolve_symbols(handler, ctx.by_ref()); + if let Some(r#else) = expr.r#else.as_mut() { + r#else.resolve_symbols(handler, ctx.by_ref()); + } + } + ExpressionKind::Match(expr) => { + expr.value.resolve_symbols(handler, ctx.by_ref()); + expr.branches.iter_mut().for_each(|branch| { + branch.scrutinee.resolve_symbols(handler, ctx.by_ref()); + branch.result.resolve_symbols(handler, ctx.by_ref()); + }); + } + ExpressionKind::Asm(asm_expr) => asm_expr.registers.iter_mut().for_each(|reg| { + if let Some(initializer) = reg.initializer.as_mut() { + initializer.resolve_symbols(handler, ctx.by_ref()); + } + }), + ExpressionKind::MethodApplication(expr) => { + expr.method_name_binding + .resolve_symbols(handler, ctx.by_ref()); + expr.contract_call_params + .iter_mut() + .for_each(|field| field.resolve_symbols(handler, ctx.by_ref())); + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())); + } + ExpressionKind::Subfield(expr) => expr.prefix.resolve_symbols(handler, ctx), + ExpressionKind::DelineatedPath(expr) => { + expr.call_path_binding.resolve_symbols(handler, ctx) + } + ExpressionKind::AbiCast(expr) => { + expr.abi_name.resolve_symbols(handler, ctx.by_ref()); + expr.address.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ArrayIndex(expr) => { + expr.index.resolve_symbols(handler, ctx.by_ref()); + expr.prefix.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::StorageAccess(_expr) => {} + ExpressionKind::IntrinsicFunction(expr) => { + expr.arguments + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())); + expr.kind_binding.resolve_symbols(handler, ctx); + } + ExpressionKind::WhileLoop(expr) => { + expr.condition.resolve_symbols(handler, ctx.by_ref()); + expr.body.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ForLoop(expr) => expr.desugared.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Break => {} + ExpressionKind::Continue => {} + ExpressionKind::Reassignment(expr) => { + match &mut expr.lhs { + ReassignmentTarget::ElementAccess(expr) => { + expr.resolve_symbols(handler, ctx.by_ref()) + } + ReassignmentTarget::Deref(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + }; + expr.rhs.resolve_symbols(handler, ctx.by_ref()); + } + ExpressionKind::ImplicitReturn(expr) => expr.resolve_symbols(handler, ctx), + ExpressionKind::Return(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Ref(expr) => expr.value.resolve_symbols(handler, ctx.by_ref()), + ExpressionKind::Deref(expr) => expr.resolve_symbols(handler, ctx.by_ref()), + } + } +} diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs new file mode 100644 index 00000000000..c2558697fe8 --- /dev/null +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -0,0 +1,283 @@ +use crate::{ + engine_threading::*, + language::{CallPath, Visibility}, + namespace::{ModulePath, ResolvedDeclaration}, + semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, + type_system::TypeId, +}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{span::Span, Ident, Spanned}; +use sway_utils::iter_prefixes; + +use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; + +/// Contextual state tracked and accumulated throughout symbol resolving. +pub struct SymbolResolveContext<'a> { + /// The namespace context accumulated throughout symbol resolving. + /// + /// Internally, this includes: + /// + /// - The `root` module from which all other modules maybe be accessed using absolute paths. + /// - The `init` module used to initialize submodule namespaces. + /// - A `mod_path` that represents the current module being type-checked. This is automatically + /// updated upon entering/exiting submodules via the `enter_submodule` method. + pub(crate) engines: &'a Engines, + pub(crate) symbol_collection_ctx: &'a mut SymbolCollectionContext, + + // The following set of fields are intentionally private. When a `SymbolResolveContext` is passed + // into a new node during symbol resolving, these fields should be updated using the `with_*` + // methods which provides a new `SymbolResolveContext`, ensuring we don't leak our changes into + // the parent nodes. + /// While symbol resolving an `impl` (whether inherent or for a `trait`/`abi`) this represents the + /// type for which we are implementing. For example in `impl Foo {}` or `impl Trait for Foo + /// {}`, this represents the type ID of `Foo`. + self_type: Option, + /// Whether or not a const declaration shadows previous const declarations sequentially. + /// + /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`. + const_shadowing_mode: ConstShadowingMode, + /// Whether or not a generic type parameters shadows previous generic type parameters. + /// + /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation. + generic_shadowing_mode: GenericShadowingMode, +} + +impl<'a> SymbolResolveContext<'a> { + /// Initialize a symbol resolving context with a namespace. + pub fn new( + engines: &'a Engines, + symbol_collection_ctx: &'a mut SymbolCollectionContext, + ) -> Self { + Self { + engines, + symbol_collection_ctx, + self_type: None, + const_shadowing_mode: ConstShadowingMode::ItemStyle, + generic_shadowing_mode: GenericShadowingMode::Disallow, + } + } + + /// Create a new context that mutably borrows the inner `namespace` with a lifetime bound by + /// `self`. + /// + /// This is particularly useful when symbol resolving a node that has more than one child node + /// (very often the case). By taking the context with the namespace lifetime bound to `self` + /// rather than the original namespace reference, we instead restrict the returned context to + /// the local scope and avoid consuming the original context when providing context to the + /// first visited child node. + pub fn by_ref(&mut self) -> SymbolResolveContext<'_> { + SymbolResolveContext { + engines: self.engines, + symbol_collection_ctx: self.symbol_collection_ctx, + self_type: self.self_type, + const_shadowing_mode: self.const_shadowing_mode, + generic_shadowing_mode: self.generic_shadowing_mode, + } + } + + /// Scope the `SymbolResolveContext` with a new namespace lexical scope. + pub fn scoped( + self, + with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result, + ) -> Result { + let engines = self.engines; + self.symbol_collection_ctx + .enter_lexical_scope(engines, |sub_scope_collect_ctx| { + let sub_scope_resolve_ctx = + SymbolResolveContext::new(engines, sub_scope_collect_ctx); + with_scoped_ctx(sub_scope_resolve_ctx) + }) + } + + /// Enter the submodule with the given name and a symbol resolve context ready for + /// symbol resolving its content. + /// + /// Returns the result of the given `with_submod_ctx` function. + pub fn enter_submodule( + self, + mod_name: Ident, + visibility: Visibility, + module_span: Span, + with_submod_ctx: impl FnOnce(SymbolResolveContext) -> T, + ) -> T { + let engines = self.engines; + self.symbol_collection_ctx.enter_submodule( + engines, + mod_name, + visibility, + module_span, + |submod_collect_ctx| { + let submod_ctx = SymbolResolveContext::new(engines, submod_collect_ctx); + with_submod_ctx(submod_ctx) + }, + ) + } + + /// Returns a mutable reference to the current namespace. + pub fn namespace_mut(&mut self) -> &mut Namespace { + &mut self.symbol_collection_ctx.namespace + } + + /// Returns a reference to the current namespace. + pub fn namespace(&self) -> &Namespace { + &self.symbol_collection_ctx.namespace + } + + /// Map this `SymbolResolveContext` instance to a new one with the given const shadowing `mode`. + #[allow(unused)] + pub(crate) fn with_const_shadowing_mode( + self, + const_shadowing_mode: ConstShadowingMode, + ) -> Self { + Self { + const_shadowing_mode, + ..self + } + } + + /// Map this `SymbolResolveContext` instance to a new one with the given generic shadowing `mode`. + #[allow(unused)] + pub(crate) fn with_generic_shadowing_mode( + self, + generic_shadowing_mode: GenericShadowingMode, + ) -> Self { + Self { + generic_shadowing_mode, + ..self + } + } + + // A set of accessor methods. We do this rather than making the fields `pub` in order to ensure + // that these are only updated via the `with_*` methods that produce a new `SymbolResolveContext`. + #[allow(unused)] + pub(crate) fn self_type(&self) -> Option { + self.self_type + } + + #[allow(unused)] + pub(crate) fn const_shadowing_mode(&self) -> ConstShadowingMode { + self.const_shadowing_mode + } + + #[allow(unused)] + pub(crate) fn generic_shadowing_mode(&self) -> GenericShadowingMode { + self.generic_shadowing_mode + } + + /// Get the engines needed for engine threading. + pub(crate) fn engines(&self) -> &'a Engines { + self.engines + } + + /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`. + pub(crate) fn resolve_call_path_with_visibility_check( + &self, + handler: &Handler, + call_path: &CallPath, + ) -> Result { + self.resolve_call_path_with_visibility_check_and_modpath( + handler, + &self.namespace().mod_path, + call_path, + ) + } + + /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. + /// + /// This will concatenate the `mod_path` with the `call_path`'s prefixes and + /// then calling `resolve_symbol` with the resulting path and call_path's suffix. + /// + /// The `mod_path` is significant here as we assume the resolution is done within the + /// context of the module pointed to by `mod_path` and will only check the call path prefixes + /// and the symbol's own visibility. + pub(crate) fn resolve_call_path_with_visibility_check_and_modpath( + &self, + handler: &Handler, + mod_path: &ModulePath, + call_path: &CallPath, + ) -> Result { + let (decl, mod_path) = self.namespace().root.resolve_call_path_and_mod_path( + handler, + self.engines, + mod_path, + call_path, + self.self_type, + )?; + + // In case there is no mod path we don't need to check visibility + if mod_path.is_empty() { + return Ok(decl); + } + + // In case there are no prefixes we don't need to check visibility + if call_path.prefixes.is_empty() { + return Ok(decl); + } + + // check the visibility of the call path elements + // we don't check the first prefix because direct children are always accessible + for prefix in iter_prefixes(&call_path.prefixes).skip(1) { + let module = self.namespace().lookup_submodule_from_absolute_path( + handler, + self.engines(), + prefix, + )?; + if module.visibility().is_private() { + let prefix_last = prefix[prefix.len() - 1].clone(); + handler.emit_err(CompileError::ImportPrivateModule { + span: prefix_last.span(), + name: prefix_last, + }); + } + } + + // check the visibility of the symbol itself + if !decl.visibility(self.engines).is_public() { + handler.emit_err(CompileError::ImportPrivateSymbol { + name: call_path.suffix.clone(), + span: call_path.suffix.span(), + }); + } + + Ok(decl) + } +} + +/// This type is used to denote if, during monomorphization, the compiler +/// should enforce that type arguments be provided. An example of that +/// might be this: +/// +/// ```ignore +/// struct Point { +/// x: u64, +/// y: u64 +/// } +/// +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +/// +/// `EnforceTypeArguments` would require that the type annotations +/// for `p1` and `p2` contain `<...>`. This is to avoid ambiguous definitions: +/// +/// ```ignore +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +#[allow(dead_code)] +#[derive(Clone, Copy)] +pub(crate) enum EnforceTypeArguments { + Yes, + No, +} diff --git a/sway-core/src/transform/to_parsed_lang/context.rs b/sway-core/src/transform/to_parsed_lang/context.rs index 4358abec4f0..dcd661a685b 100644 --- a/sway-core/src/transform/to_parsed_lang/context.rs +++ b/sway-core/src/transform/to_parsed_lang/context.rs @@ -1,4 +1,8 @@ -use crate::{build_config::ExperimentalFlags, language::parsed::TreeType, BuildTarget}; +use crate::{ + build_config::ExperimentalFlags, + language::parsed::{Declaration, TreeType}, + BuildTarget, +}; pub struct Context { pub experimental: ExperimentalFlags, @@ -21,6 +25,9 @@ pub struct Context { /// The program type. program_type: Option, + + /// Keeps track of the implementing type as we convert the tree. + pub(crate) implementing_type: Option, } impl Context { @@ -34,6 +41,7 @@ impl Context { destructured_tuple_unique_suffix: std::default::Default::default(), match_expression_matched_value_unique_suffix: std::default::Default::default(), program_type: std::default::Default::default(), + implementing_type: None, } } diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 4e70c070b5e..e96a20a1156 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -174,9 +174,17 @@ pub fn item_to_ast_nodes( .into_iter() .map(AstNodeContent::UseStatement) .collect(), - ItemKind::Struct(item_struct) => decl(Declaration::StructDeclaration( - item_struct_to_struct_declaration(context, handler, engines, item_struct, attributes)?, - )), + ItemKind::Struct(item_struct) => { + let struct_decl = Declaration::StructDeclaration(item_struct_to_struct_declaration( + context, + handler, + engines, + item_struct, + attributes, + )?); + context.implementing_type = Some(struct_decl.clone()); + decl(struct_decl) + } ItemKind::Enum(item_enum) => decl(Declaration::EnumDeclaration( item_enum_to_enum_declaration(context, handler, engines, item_enum, attributes)?, )), @@ -203,15 +211,25 @@ pub fn item_to_ast_nodes( function_declaration_decl_id, )) } - ItemKind::Trait(item_trait) => decl(Declaration::TraitDeclaration( - item_trait_to_trait_declaration(context, handler, engines, item_trait, attributes)?, - )), - ItemKind::Impl(item_impl) => decl(item_impl_to_declaration( - context, handler, engines, item_impl, - )?), - ItemKind::Abi(item_abi) => decl(Declaration::AbiDeclaration(item_abi_to_abi_declaration( - context, handler, engines, item_abi, attributes, - )?)), + ItemKind::Trait(item_trait) => { + let trait_decl = Declaration::TraitDeclaration(item_trait_to_trait_declaration( + context, handler, engines, item_trait, attributes, + )?); + context.implementing_type = Some(trait_decl.clone()); + decl(trait_decl) + } + ItemKind::Impl(item_impl) => { + let impl_decl = item_impl_to_declaration(context, handler, engines, item_impl)?; + context.implementing_type = Some(impl_decl.clone()); + decl(impl_decl) + } + ItemKind::Abi(item_abi) => { + let abi_decl = Declaration::AbiDeclaration(item_abi_to_abi_declaration( + context, handler, engines, item_abi, attributes, + )?); + context.implementing_type = Some(abi_decl.clone()); + decl(abi_decl) + } ItemKind::Const(item_const) => decl(Declaration::ConstantDeclaration({ item_const_to_constant_declaration( context, handler, engines, item_const, attributes, true, @@ -545,6 +563,7 @@ pub fn item_fn_to_function_declaration( }; let kind = override_kind.unwrap_or(kind); + let implementing_type = context.implementing_type.clone(); let fn_decl = FunctionDeclaration { purity: get_attributed_purity(context, handler, &attributes)?, @@ -578,6 +597,8 @@ pub fn item_fn_to_function_declaration( .transpose()? .unwrap_or(vec![]), kind, + implementing_type, + lexical_scope: 0, }; let decl_id = engines.pe().insert(fn_decl); Ok(decl_id) @@ -778,6 +799,7 @@ pub fn item_impl_to_declaration( impl_type_parameters, trait_name: trait_name.to_call_path(handler)?, trait_type_arguments, + trait_decl_ref: None, implementing_for, items, block_span, @@ -796,6 +818,7 @@ pub fn item_impl_to_declaration( prefixes: vec![], suffix: BaseIdent::dummy(), }, + trait_decl_ref: None, trait_type_arguments: vec![], implementing_for, impl_type_parameters, @@ -1761,6 +1784,7 @@ fn struct_path_and_fields_to_struct_expression( }; Ok(Box::new(StructExpression { call_path_binding, + resolved_call_path_binding: None, fields, })) } @@ -1909,6 +1933,7 @@ fn expr_func_app_to_expression_kind( type_arguments: TypeArgs::Regular(type_arguments), span: span.clone(), }, + resolved_call_path_binding: None, arguments, }, )), @@ -2605,6 +2630,7 @@ fn configurable_field_to_configurable_declaration( type_arguments: TypeArgs::Regular(vec![type_ascription.clone()]), span: span.clone(), }, + resolved_call_path_binding: None, arguments: vec![value], })); Expression { diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 699a99470ba..d6022709fa6 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -3,10 +3,18 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ - decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef}, + decl_engine::{ + parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef, + }, engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}, - language::{ty, CallPath, QualifiedCallPath}, - semantic_analysis::{type_check_context::EnforceTypeArguments, TypeCheckContext}, + language::{ + parsed::{FunctionDeclaration, StructDeclaration}, + ty, CallPath, QualifiedCallPath, + }, + semantic_analysis::{ + symbol_resolve::ResolveSymbols, symbol_resolve_context::SymbolResolveContext, + type_check_context::EnforceTypeArguments, TypeCheckContext, + }, type_system::priv_prelude::*, Ident, }; @@ -184,6 +192,17 @@ impl TypeBinding { span: self.span, } } + + pub(crate) fn resolve_symbols(&mut self, handler: &Handler, mut ctx: SymbolResolveContext<'_>) { + match self.type_arguments { + TypeArgs::Regular(ref mut args) => args + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())), + TypeArgs::Prefix(ref mut args) => args + .iter_mut() + .for_each(|arg| arg.resolve_symbols(handler, ctx.by_ref())), + } + } } impl TypeBinding> { @@ -249,6 +268,32 @@ pub(crate) trait TypeCheckTypeBinding { ) -> Result<(DeclRef>, Option, Option), ErrorEmitted>; } +#[allow(clippy::type_complexity)] +pub trait SymbolResolveTypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted>; +} + +impl SymbolResolveTypeBinding for TypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted> { + let engines = ctx.engines(); + // Grab the declaration. + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; + // Check to see if this is a function declaration. + let fn_decl = unknown_decl + .resolve_parsed(engines.de()) + .to_fn_ref(handler, engines)?; + Ok(fn_decl) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -309,6 +354,24 @@ 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 = unknown_decl.to_struct_decl(handler, engines)?; + struct_decl + .resolve_parsed(engines.de()) + .to_struct_decl(handler, engines) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -328,7 +391,7 @@ impl TypeCheckTypeBinding for TypeBinding { // 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_id = unknown_decl.to_struct_id(handler, engines)?; + let struct_id = unknown_decl.to_struct_decl(handler, engines)?; // Get a new copy from the declaration engine. let mut new_copy = (*decl_engine.get_struct(&struct_id)).clone(); // Monomorphize the copy, in place. diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index 85f21f9e132..7a3a50d35fe 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -1,4 +1,4 @@ -mod ast_elements; +pub(crate) mod ast_elements; mod engine; mod id; mod info; diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 39ba771f879..8f39f6e4480 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -133,6 +133,7 @@ impl Parse for Declaration { Declaration::StorageDeclaration(decl_id) => decl_id.parse(ctx), Declaration::TypeAliasDeclaration(decl_id) => decl_id.parse(ctx), Declaration::TraitTypeDeclaration(decl_id) => decl_id.parse(ctx), + Declaration::TraitFnDeclaration(decl_id) => decl_id.parse(ctx), } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.lock new file mode 100644 index 00000000000..e5570689316 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "alias" +source = "path+from-root-DE984AFD05391BAA" + +[[package]] +name = "use-alias" +source = "member" +dependencies = ["alias"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.toml new file mode 100644 index 00000000000..a0d6afeeff2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/Forc.toml @@ -0,0 +1,6 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "type_alias_basic" +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/src/main.sw new file mode 100644 index 00000000000..fa400cbfbc4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_basic/src/main.sw @@ -0,0 +1,4 @@ +library; + +struct S {} +pub type Alias = S; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.lock new file mode 100644 index 00000000000..69e0c1abf7b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "type_alias_basic" +source = "path+from-root-05B061D32AED907C" + +[[package]] +name = "type_alias_from_dependency" +source = "member" +dependencies = ["type_alias_basic"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.toml new file mode 100644 index 00000000000..82ceffc153f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "type_alias_from_dependency" +implicit-std = false + +[dependencies] +type_alias_basic = { path = "../type_alias_basic" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/src/main.sw new file mode 100644 index 00000000000..92e8e146129 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/src/main.sw @@ -0,0 +1,7 @@ +library; + +use type_alias_basic::*; + +fn foo() { + let z = type_alias_basic::Alias { }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/test.toml new file mode 100644 index 00000000000..848f61f7cd7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/type_alias_from_dependency/test.toml @@ -0,0 +1,3 @@ +category = "compile" +validate_abi = false +expected_warnings = 2