From 6575c4b4533a44dd5657a12a30abc1724c2b3f84 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Sun, 6 Oct 2024 11:50:04 +0100 Subject: [PATCH 1/3] Add `TypeInfo::UntypedEnum` and `TypeInfo::UntypedStruct`. --- sway-core/src/abi_generation/abi_str.rs | 8 ++ sway-core/src/abi_generation/evm_abi.rs | 8 ++ sway-core/src/decl_engine/mod.rs | 1 + sway-core/src/decl_engine/parsed_engine.rs | 22 +++- sway-core/src/decl_engine/parsed_id.rs | 21 +++- sway-core/src/ir_generation/convert.rs | 2 + .../semantic_analysis/namespace/trait_map.rs | 4 +- .../semantic_analysis/node_dependencies.rs | 2 + .../semantic_analysis/type_check_context.rs | 2 +- sway-core/src/type_system/engine.rs | 49 ++++++-- sway-core/src/type_system/id.rs | 50 ++++++++ sway-core/src/type_system/info.rs | 119 ++++++++++++++---- .../src/type_system/substitute/subst_map.rs | 61 ++++++++- 13 files changed, 308 insertions(+), 41 deletions(-) diff --git a/sway-core/src/abi_generation/abi_str.rs b/sway-core/src/abi_generation/abi_str.rs index 2972c9cee0e..254b8a805ad 100644 --- a/sway-core/src/abi_generation/abi_str.rs +++ b/sway-core/src/abi_generation/abi_str.rs @@ -117,6 +117,14 @@ impl TypeInfo { Numeric => "u64".into(), // u64 is the default Contract => "contract".into(), ErrorRecovery(_) => "unknown due to error".into(), + UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + format!("untyped enum {}", decl.name) + } + UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + format!("untyped struct {}", decl.name) + } Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); let type_params = if (ctx.abi_root_type_without_generic_type_parameters && is_root) diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index f899e0de209..f723f36d14a 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -93,6 +93,14 @@ pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String { Numeric => "u64".into(), // u64 is the default Contract => "contract".into(), ErrorRecovery(_) => "unknown due to error".into(), + UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + format!("untyped enum {}", decl.name) + } + UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + format!("untyped struct {}", decl.name) + } Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); format!("enum {}", decl.call_path.suffix) diff --git a/sway-core/src/decl_engine/mod.rs b/sway-core/src/decl_engine/mod.rs index 94f6e7987f7..78f4c3ab256 100644 --- a/sway-core/src/decl_engine/mod.rs +++ b/sway-core/src/decl_engine/mod.rs @@ -26,6 +26,7 @@ pub use engine::*; pub(crate) use id::*; pub use interface_decl_id::*; pub(crate) use mapping::*; +pub use parsed_engine::*; pub use r#ref::*; pub(crate) use replace_decls::*; use sway_types::Ident; diff --git a/sway-core/src/decl_engine/parsed_engine.rs b/sway-core/src/decl_engine/parsed_engine.rs index 2177131ceb4..5c330346fd9 100644 --- a/sway-core/src/decl_engine/parsed_engine.rs +++ b/sway-core/src/decl_engine/parsed_engine.rs @@ -1,6 +1,5 @@ use crate::{ concurrent_slab::ConcurrentSlab, - decl_engine::*, language::parsed::{ AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, EnumDeclaration, EnumVariant, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, StructDeclaration, @@ -47,7 +46,7 @@ pub trait ParsedDeclEngineReplace { #[allow(unused)] pub trait ParsedDeclEngineIndex: - ParsedDeclEngineGet, T> + ParsedDeclEngineInsert + ParsedDeclEngineReplace + ParsedDeclEngineGet, T> + ParsedDeclEngineInsert + ParsedDeclEngineReplace { } @@ -136,6 +135,25 @@ macro_rules! decl_engine_clear { }; } +macro_rules! decl_engine_index { + ($slab:ident, $decl:ty) => { + impl ParsedDeclEngineIndex<$decl> for ParsedDeclEngine {} + }; +} +decl_engine_index!(variable_slab, VariableDeclaration); +decl_engine_index!(function_slab, FunctionDeclaration); +decl_engine_index!(trait_slab, TraitDeclaration); +decl_engine_index!(trait_fn_slab, TraitFn); +decl_engine_index!(trait_type_slab, TraitTypeDeclaration); +decl_engine_index!(impl_self_or_trait_slab, ImplSelfOrTrait); +decl_engine_index!(struct_slab, StructDeclaration); +decl_engine_index!(storage_slab, StorageDeclaration); +decl_engine_index!(abi_slab, AbiDeclaration); +decl_engine_index!(configurable_slab, ConfigurableDeclaration); +decl_engine_index!(constant_slab, ConstantDeclaration); +decl_engine_index!(enum_slab, EnumDeclaration); +decl_engine_index!(type_alias_slab, TypeAliasDeclaration); + decl_engine_clear!( variable_slab, VariableDeclaration; function_slab, FunctionDeclaration; diff --git a/sway-core/src/decl_engine/parsed_id.rs b/sway-core/src/decl_engine/parsed_id.rs index 561c811c1dd..3a97459aa75 100644 --- a/sway-core/src/decl_engine/parsed_id.rs +++ b/sway-core/src/decl_engine/parsed_id.rs @@ -2,8 +2,14 @@ use std::hash::{DefaultHasher, Hasher}; use std::marker::PhantomData; use std::{fmt, hash::Hash}; -use crate::engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}; +use sway_types::{Named, Spanned}; +use crate::engine_threading::{ + EqWithEngines, HashWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, +}; +use crate::Engines; + +use super::parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet, ParsedDeclEngineIndex}; use super::DeclUniqueId; pub type ParsedDeclIdIndexType = usize; @@ -61,6 +67,19 @@ impl Hash for ParsedDeclId { } } +impl HashWithEngines for ParsedDeclId +where + ParsedDeclEngine: ParsedDeclEngineIndex, + T: Named + Spanned + HashWithEngines, +{ + fn hash(&self, state: &mut H, engines: &Engines) { + let decl_engine = engines.pe(); + let decl = decl_engine.get(self); + decl.name().hash(state); + decl.hash(state, engines); + } +} + impl PartialOrd for ParsedDeclId { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index 3aa22401338..4d0ee1d20c7 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -177,6 +177,8 @@ fn convert_resolved_type_info( TypeInfo::Custom { .. } => reject_type!("Custom"), TypeInfo::Contract => reject_type!("Contract"), TypeInfo::ContractCaller { .. } => reject_type!("ContractCaller"), + TypeInfo::UntypedEnum(_) => reject_type!("UntypedEnum"), + TypeInfo::UntypedStruct(_) => reject_type!("UntypedStruct"), TypeInfo::Unknown => reject_type!("Unknown"), TypeInfo::UnknownGeneric { .. } => reject_type!("Generic"), TypeInfo::Placeholder(_) => reject_type!("Placeholder"), diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index d615b96e9ec..4d6999931b1 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -882,7 +882,7 @@ impl TraitMap { }, } in impls.iter() { - if !type_info.can_change(decl_engine) && *type_id == *map_type_id { + if !type_info.can_change(engines) && *type_id == *map_type_id { trait_map.insert_inner( map_trait_name.clone(), impl_span.clone(), @@ -1548,6 +1548,8 @@ impl TraitMap { Contract => TypeRootFilter::Contract, ErrorRecovery(_) => TypeRootFilter::ErrorRecovery, Tuple(fields) => TypeRootFilter::Tuple(fields.len()), + UntypedEnum(decl_id) => TypeRootFilter::Enum(*decl_id), + UntypedStruct(decl_id) => TypeRootFilter::Struct(*decl_id), Enum(decl_id) => { // TODO Remove unwrap once #6475 is fixed TypeRootFilter::Enum(engines.de().get_parsed_decl_id(decl_id).unwrap()) diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 398c590566a..c34feeab4e6 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -1031,6 +1031,8 @@ fn type_info_name(type_info: &TypeInfo) -> String { TypeInfo::ContractCaller { abi_name, .. } => { return format!("contract caller {abi_name}"); } + TypeInfo::UntypedEnum(_) => "untyped enum", + TypeInfo::UntypedStruct(_) => "untyped struct", TypeInfo::Struct { .. } => "struct", TypeInfo::Enum { .. } => "enum", TypeInfo::Array(..) => "array", diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 0f515bccdf9..455cc21fb4b 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -820,7 +820,7 @@ impl<'a> TypeCheckContext<'a> { let coercion_check = UnifyCheck::coercion(self.engines); // default numeric types to u64 - if type_engine.contains_numeric(decl_engine, type_id) { + if type_engine.contains_numeric(self.engines, type_id) { // While collecting unification we don't decay numeric and will ignore this error. if self.collecting_unifications { return Err(handler.emit_err(CompileError::MethodNotFound { diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index e85fb05a012..7dea1cbb281 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -84,9 +84,7 @@ impl TypeEngine { }); match raw_entry { RawEntryMut::Occupied(o) => return *o.get(), - RawEntryMut::Vacant(_) if ty.can_change(engines.de()) => { - TypeId::new(self.slab.insert(tsi)) - } + RawEntryMut::Vacant(_) if ty.can_change(engines) => TypeId::new(self.slab.insert(tsi)), RawEntryMut::Vacant(v) => { let type_id = TypeId::new(self.slab.insert(tsi.clone())); v.insert_with_hasher(ty_hash, tsi, type_id, make_hasher(&hash_builder, engines)); @@ -332,33 +330,48 @@ impl TypeEngine { } /// Return whether a given type still contains undecayed references to [TypeInfo::Numeric] - pub(crate) fn contains_numeric(&self, decl_engine: &DeclEngine, type_id: TypeId) -> bool { + pub(crate) fn contains_numeric(&self, engines: &Engines, type_id: TypeId) -> bool { + let decl_engine = engines.de(); match &&*self.get(type_id) { + TypeInfo::UntypedEnum(decl_id) => { + engines + .pe() + .get_enum(decl_id) + .variants + .iter() + .all(|variant_type| { + self.contains_numeric(engines, variant_type.type_argument.type_id) + }) + } + TypeInfo::UntypedStruct(decl_id) => engines + .pe() + .get_struct(decl_id) + .fields + .iter() + .any(|field| self.contains_numeric(engines, field.type_argument.type_id)), TypeInfo::Enum(decl_ref) => { decl_engine .get_enum(decl_ref) .variants .iter() .all(|variant_type| { - self.contains_numeric(decl_engine, variant_type.type_argument.type_id) + self.contains_numeric(engines, variant_type.type_argument.type_id) }) } TypeInfo::Struct(decl_ref) => decl_engine .get_struct(decl_ref) .fields .iter() - .any(|field| self.contains_numeric(decl_engine, field.type_argument.type_id)), + .any(|field| self.contains_numeric(engines, field.type_argument.type_id)), TypeInfo::Tuple(fields) => fields .iter() - .any(|field_type| self.contains_numeric(decl_engine, field_type.type_id)), - TypeInfo::Array(elem_ty, _length) => { - self.contains_numeric(decl_engine, elem_ty.type_id) - } - TypeInfo::Ptr(targ) => self.contains_numeric(decl_engine, targ.type_id), - TypeInfo::Slice(targ) => self.contains_numeric(decl_engine, targ.type_id), + .any(|field_type| self.contains_numeric(engines, field_type.type_id)), + TypeInfo::Array(elem_ty, _length) => self.contains_numeric(engines, elem_ty.type_id), + TypeInfo::Ptr(targ) => self.contains_numeric(engines, targ.type_id), + TypeInfo::Slice(targ) => self.contains_numeric(engines, targ.type_id), TypeInfo::Ref { referenced_type, .. - } => self.contains_numeric(decl_engine, referenced_type.type_id), + } => self.contains_numeric(engines, referenced_type.type_id), TypeInfo::Unknown | TypeInfo::Never | TypeInfo::UnknownGeneric { .. } @@ -393,6 +406,16 @@ impl TypeEngine { let decl_engine = engines.de(); match &&*self.get(type_id) { + TypeInfo::UntypedEnum(decl_id) => { + for variant_type in &engines.pe().get_enum(decl_id).variants { + self.decay_numeric(handler, engines, variant_type.type_argument.type_id, span)?; + } + } + TypeInfo::UntypedStruct(decl_id) => { + for field in &engines.pe().get_struct(decl_id).fields { + self.decay_numeric(handler, engines, field.type_argument.type_id, span)?; + } + } TypeInfo::Enum(decl_ref) => { for variant_type in &decl_engine.get_enum(decl_ref).variants { self.decay_numeric(handler, engines, variant_type.type_argument.type_id, span)?; diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index d341c150779..b1eda847745 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -228,6 +228,56 @@ impl TypeId { | TypeInfo::Contract | TypeInfo::ErrorRecovery(_) | TypeInfo::TraitType { .. } => {} + TypeInfo::UntypedEnum(decl_id) => { + let enum_decl = engines.pe().get_enum(decl_id); + for type_param in &enum_decl.type_parameters { + extend( + &mut found, + type_param.type_id.extract_any_including_self( + engines, + filter_fn, + type_param.trait_constraints.clone(), + depth + 1, + ), + ); + } + for variant in &enum_decl.variants { + extend( + &mut found, + variant.type_argument.type_id.extract_any_including_self( + engines, + filter_fn, + vec![], + depth + 1, + ), + ); + } + } + TypeInfo::UntypedStruct(decl_id) => { + let struct_decl = engines.pe().get_struct(decl_id); + for type_param in &struct_decl.type_parameters { + extend( + &mut found, + type_param.type_id.extract_any_including_self( + engines, + filter_fn, + type_param.trait_constraints.clone(), + depth + 1, + ), + ); + } + for field in &struct_decl.fields { + extend( + &mut found, + field.type_argument.type_id.extract_any_including_self( + engines, + filter_fn, + vec![], + depth + 1, + ), + ); + } + } TypeInfo::Enum(enum_ref) => { let enum_decl = decl_engine.get_enum(enum_ref); for type_param in &enum_decl.type_parameters { diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 30b3af262a8..a6c8a219853 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -1,10 +1,11 @@ use crate::{ - decl_engine::{DeclEngine, DeclEngineGet, DeclId}, + decl_engine::{parsed_id::ParsedDeclId, DeclEngine, DeclEngineGet, DeclId}, engine_threading::{ DebugWithEngines, DisplayWithEngines, Engines, EqWithEngines, HashWithEngines, OrdWithEngines, OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext, }, language::{ + parsed::{EnumDeclaration, StructDeclaration}, ty::{self, TyEnumDecl, TyStructDecl}, CallPath, QualifiedCallPath, }, @@ -131,6 +132,8 @@ pub enum TypeInfo { StringSlice, StringArray(Length), UnsignedInteger(IntegerBits), + UntypedEnum(ParsedDeclId), + UntypedStruct(ParsedDeclId), Enum(DeclId), Struct(DeclId), Boolean, @@ -209,12 +212,10 @@ impl HashWithEngines for TypeInfo { TypeInfo::Tuple(fields) => { fields.hash(state, engines); } - TypeInfo::Enum(decl_id) => { - HashWithEngines::hash(&decl_id, state, engines); - } - TypeInfo::Struct(decl_id) => { - HashWithEngines::hash(&decl_id, state, engines); - } + TypeInfo::UntypedEnum(decl_id) => decl_id.unique_id().hash(state), + TypeInfo::UntypedStruct(decl_id) => decl_id.unique_id().hash(state), + TypeInfo::Enum(decl_id) => decl_id.unique_id().hash(state), + TypeInfo::Struct(decl_id) => decl_id.unique_id().hash(state), TypeInfo::ContractCaller { abi_name, address } => { abi_name.hash(state); let address = address @@ -612,6 +613,22 @@ impl DisplayWithEngines for TypeInfo { Numeric => "numeric".into(), Contract => "contract".into(), ErrorRecovery(_) => "unknown".into(), + UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + print_inner_types( + engines, + decl.name.as_str(), + decl.type_parameters.iter().map(|x| x.type_id), + ) + } + UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + print_inner_types( + engines, + decl.name.as_str(), + decl.type_parameters.iter().map(|x| x.type_id), + ) + } Enum(decl_ref) => { let decl = engines.de().get_enum(decl_ref); print_inner_types( @@ -663,12 +680,7 @@ impl DisplayWithEngines for TypeInfo { impl DebugWithEngines for TypeInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { - use TypeInfo::{ - Alias, Array, Boolean, Contract, ContractCaller, Custom, Enum, ErrorRecovery, Never, - Numeric, Placeholder, Ptr, RawUntypedPtr, RawUntypedSlice, Ref, Slice, Storage, - StringArray, StringSlice, Struct, TraitType, Tuple, TypeParam, Unknown, UnknownGeneric, - UnsignedInteger, B256, - }; + use TypeInfo::*; let s = match self { Unknown => "unknown".into(), Never => "!".into(), @@ -732,6 +744,22 @@ impl DebugWithEngines for TypeInfo { Numeric => "numeric".into(), Contract => "contract".into(), ErrorRecovery(_) => "unknown due to error".into(), + UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + print_inner_types_debug( + engines, + decl.name.as_str(), + decl.type_parameters.iter().map(|x| x.type_id), + ) + } + UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + print_inner_types_debug( + engines, + decl.name.as_str(), + decl.type_parameters.iter().map(|x| x.type_id), + ) + } Enum(decl_ref) => { let decl = engines.de().get_enum(decl_ref); print_inner_types_debug( @@ -826,6 +854,8 @@ impl TypeInfo { TypeInfo::TraitType { .. } => 24, TypeInfo::Ref { .. } => 25, TypeInfo::Never => 26, + TypeInfo::UntypedEnum(_) => 27, + TypeInfo::UntypedStruct(_) => 28, } } @@ -1242,12 +1272,13 @@ impl TypeInfo { return Ok(self); } match self { - TypeInfo::Enum { .. } | TypeInfo::Struct { .. } => { - Err(handler.emit_err(CompileError::Internal( - "did not expect to apply type arguments to this type", - span.clone(), - ))) - } + TypeInfo::UntypedEnum(_) + | TypeInfo::UntypedStruct(_) + | TypeInfo::Enum { .. } + | TypeInfo::Struct { .. } => Err(handler.emit_err(CompileError::Internal( + "did not expect to apply type arguments to this type", + span.clone(), + ))), TypeInfo::Custom { qualified_call_path: call_path, type_arguments: other_type_arguments, @@ -1316,6 +1347,8 @@ impl TypeInfo { match self { TypeInfo::UnsignedInteger(_) + | TypeInfo::UntypedEnum(_) + | TypeInfo::UntypedStruct(_) | TypeInfo::Enum { .. } | TypeInfo::Struct { .. } | TypeInfo::Boolean @@ -1392,6 +1425,8 @@ impl TypeInfo { } match self { TypeInfo::UnsignedInteger(_) + | TypeInfo::UntypedEnum { .. } + | TypeInfo::UntypedStruct { .. } | TypeInfo::Enum { .. } | TypeInfo::Struct { .. } | TypeInfo::Boolean @@ -1434,16 +1469,24 @@ impl TypeInfo { } } - pub(crate) fn can_change(&self, decl_engine: &DeclEngine) -> bool { + pub(crate) fn can_change(&self, engines: &Engines) -> bool { // TODO: there might be an optimization here that if the type params hold // only non-dynamic types, then it doesn't matter that there are type params match self { + TypeInfo::UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + !decl.type_parameters.is_empty() + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + !decl.type_parameters.is_empty() + } TypeInfo::Enum(decl_ref) => { - let decl = decl_engine.get_enum(decl_ref); + let decl = engines.de().get_enum(decl_ref); !decl.type_parameters.is_empty() } TypeInfo::Struct(decl_ref) => { - let decl = decl_engine.get_struct(decl_ref); + let decl = engines.de().get_struct(decl_ref); !decl.type_parameters.is_empty() } TypeInfo::StringArray(_) @@ -1702,6 +1745,38 @@ impl TypeInfo { Numeric => "u64".into(), // u64 is the default Contract => "contract".into(), ErrorRecovery(_) => "unknown due to error".into(), + UntypedEnum(decl_id) => { + let decl = engines.pe().get_enum(decl_id); + let type_params = if decl.type_parameters.is_empty() { + "".into() + } else { + format!( + "<{}>", + decl.type_parameters + .iter() + .map(|p| p.type_id.get_type_str(engines)) + .collect::>() + .join(",") + ) + }; + format!("untyped enum {}{}", &decl.name, type_params) + } + UntypedStruct(decl_id) => { + let decl = engines.pe().get_struct(decl_id); + let type_params = if decl.type_parameters.is_empty() { + "".into() + } else { + format!( + "<{}>", + decl.type_parameters + .iter() + .map(|p| p.type_id.get_type_str(engines)) + .collect::>() + .join(",") + ) + }; + format!("untyped struct {}{}", &decl.name, type_params) + } Enum(decl_ref) => { let decl = engines.de().get_enum(decl_ref); let type_params = if decl.type_parameters.is_empty() { diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index 8020e1c4d63..4b1a9fa93c7 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -1,5 +1,7 @@ use crate::{ - decl_engine::{DeclEngine, DeclEngineGetParsedDeclId, DeclEngineInsert}, + decl_engine::{ + DeclEngine, DeclEngineGetParsedDeclId, DeclEngineInsert, ParsedDeclEngineInsert, + }, engine_threading::{ DebugWithEngines, Engines, PartialEqWithEngines, PartialEqWithEnginesContext, }, @@ -357,12 +359,69 @@ impl TypeSubstMap { pub(crate) fn find_match(&self, type_id: TypeId, engines: &Engines) -> Option { let type_engine = engines.te(); let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); let type_info = type_engine.get(type_id); match (*type_info).clone() { TypeInfo::Custom { .. } => iter_for_match(engines, self, &type_info), TypeInfo::UnknownGeneric { .. } => iter_for_match(engines, self, &type_info), TypeInfo::Placeholder(_) => iter_for_match(engines, self, &type_info), TypeInfo::TypeParam(_) => None, + TypeInfo::UntypedEnum(decl_id) => { + let mut decl = (*parsed_decl_engine.get_enum(&decl_id)).clone(); + let mut need_to_create_new = false; + + for variant in &mut decl.variants { + if let Some(type_id) = self.find_match(variant.type_argument.type_id, engines) { + need_to_create_new = true; + variant.type_argument.type_id = type_id; + } + } + + for type_param in &mut decl.type_parameters { + if let Some(type_id) = self.find_match(type_param.type_id, engines) { + need_to_create_new = true; + type_param.type_id = type_id; + } + } + if need_to_create_new { + let source_id = decl.span.source_id().copied(); + let new_decl_id = engines.pe().insert(decl); + Some(type_engine.insert( + engines, + TypeInfo::UntypedEnum(new_decl_id), + source_id.as_ref(), + )) + } else { + None + } + } + TypeInfo::UntypedStruct(decl_id) => { + let mut decl = (*parsed_decl_engine.get_struct(&decl_id)).clone(); + let mut need_to_create_new = false; + for field in &mut decl.fields { + if let Some(type_id) = self.find_match(field.type_argument.type_id, engines) { + need_to_create_new = true; + field.type_argument.type_id = type_id; + } + } + for type_param in &mut decl.type_parameters { + if let Some(type_id) = self.find_match(type_param.type_id, engines) { + need_to_create_new = true; + type_param.type_id = type_id; + } + } + if need_to_create_new { + let source_id = decl.span.source_id().copied(); + let new_decl_id = parsed_decl_engine.insert(decl); + Some(type_engine.insert( + engines, + TypeInfo::UntypedStruct(new_decl_id), + source_id.as_ref(), + )) + } else { + None + } + } TypeInfo::Struct(decl_id) => { let mut decl = (*decl_engine.get_struct(&decl_id)).clone(); let mut need_to_create_new = false; From cc1a7678564a25251d33b1b263df0f52fc5d9d85 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 14 Oct 2024 12:15:33 +0100 Subject: [PATCH 2/3] Change `SubstTypesContext` to contain an optional `TypeSubstMap`. --- sway-core/src/decl_engine/ref.rs | 2 +- sway-core/src/type_system/id.rs | 5 +++- .../src/type_system/substitute/subst_types.rs | 26 ++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index 663fd563a60..7a737651115 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -103,7 +103,7 @@ where let decl_engine = ctx.engines.de(); if ctx .type_subst_map - .source_ids_contains_concrete_type(ctx.engines) + .is_some_and(|tsm| tsm.source_ids_contains_concrete_type(ctx.engines)) || !decl_engine.get(&self.id).is_concrete(ctx.engines) { let mut decl = (*decl_engine.get(&self.id)).clone(); diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index b1eda847745..c4fc2d13842 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -93,7 +93,10 @@ impl CollectTypesMetadata for TypeId { impl SubstTypes for TypeId { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { let type_engine = ctx.engines.te(); - if let Some(matching_id) = ctx.type_subst_map.find_match(*self, ctx.engines) { + if let Some(matching_id) = ctx + .type_subst_map + .and_then(|tsm| tsm.find_match(*self, ctx.engines)) + { if !matches!(&*type_engine.get(matching_id), TypeInfo::ErrorRecovery(_)) { *self = matching_id; HasChanges::Yes diff --git a/sway-core/src/type_system/substitute/subst_types.rs b/sway-core/src/type_system/substitute/subst_types.rs index f5107ebd59a..8b2ea5068e1 100644 --- a/sway-core/src/type_system/substitute/subst_types.rs +++ b/sway-core/src/type_system/substitute/subst_types.rs @@ -24,31 +24,39 @@ impl std::ops::BitOr for HasChanges { } } -pub struct SubstTypesContext<'a, 'b> { - pub engines: &'a Engines, - pub type_subst_map: &'b TypeSubstMap, +pub struct SubstTypesContext<'eng, 'tsm> { + pub engines: &'eng Engines, + pub type_subst_map: Option<&'tsm TypeSubstMap>, pub subst_function_body: bool, } -impl<'a, 'b> SubstTypesContext<'a, 'b> { +impl<'eng, 'tsm> SubstTypesContext<'eng, 'tsm> { pub fn new( - engines: &'a Engines, - type_subst_map: &'b TypeSubstMap, + engines: &'eng Engines, + type_subst_map: &'tsm TypeSubstMap, subst_function_body: bool, - ) -> SubstTypesContext<'a, 'b> { + ) -> SubstTypesContext<'eng, 'tsm> { SubstTypesContext { engines, - type_subst_map, + type_subst_map: Some(type_subst_map), subst_function_body, } } + + pub fn dummy(engines: &'eng Engines) -> SubstTypesContext<'eng, 'tsm> { + SubstTypesContext { + engines, + type_subst_map: None, + subst_function_body: false, + } + } } pub trait SubstTypes { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges; fn subst(&mut self, ctx: &SubstTypesContext) -> HasChanges { - if ctx.type_subst_map.is_empty() { + if ctx.type_subst_map.is_some_and(|tsm| tsm.is_empty()) { HasChanges::No } else { self.subst_inner(ctx) From f0bbca41cad5e6928f68d3437b329123d9963ec5 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Thu, 24 Oct 2024 18:31:43 +0100 Subject: [PATCH 3/3] Implement `DelineatedPathExpression` AST resolve handling. --- .vscode/launch.json | 24 +- sway-core/src/language/parsed/declaration.rs | 30 +- .../src/language/parsed/declaration/struct.rs | 4 + .../src/language/parsed/expression/mod.rs | 4 +- sway-core/src/lib.rs | 15 +- .../ast_node/declaration/impl_trait.rs | 55 +++- .../ast_node/expression/typed_expression.rs | 1 + .../src/semantic_analysis/namespace/root.rs | 72 ++++- .../semantic_analysis/node_dependencies.rs | 1 + .../symbol_collection_context.rs | 5 +- .../src/semantic_analysis/symbol_resolve.rs | 59 ++-- .../symbol_resolve_context.rs | 25 +- .../src/semantic_analysis/type_resolve.rs | 22 +- .../to_parsed_lang/convert_parse_tree.rs | 2 + .../src/type_system/ast_elements/binding.rs | 298 ++++++++++++++++-- sway-core/src/type_system/monomorphization.rs | 10 + sway-lsp/src/traverse/parsed_tree.rs | 1 + .../primitive_type_argument/src/foo.sw | 2 +- 18 files changed, 560 insertions(+), 70 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index eb5c4aa3642..70a0b12bde7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,6 +18,28 @@ "name": "Attach to forc-lsp", "pid": "${command:pickProcess}", "program": "${env:HOME}/.cargo/bin/forc-lsp" - } + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'forc'", + "cargo": { + "args": [ + "build", + "--bin=forc", + "--package=forc" + ], + "filter": { + "name": "forc", + "kind": "bin" + } + }, + "args": [ + "build", + "--path", + "const_rec" + ], + "cwd": "${workspaceFolder}" + }, ] } \ No newline at end of file diff --git a/sway-core/src/language/parsed/declaration.rs b/sway-core/src/language/parsed/declaration.rs index a47c4895c1b..2bac9f31b7f 100644 --- a/sway-core/src/language/parsed/declaration.rs +++ b/sway-core/src/language/parsed/declaration.rs @@ -122,7 +122,7 @@ impl Declaration { } } - pub(crate) fn to_fn_ref( + pub(crate) fn to_fn_decl( &self, handler: &Handler, engines: &Engines, @@ -166,6 +166,34 @@ impl Declaration { } } + pub(crate) fn to_enum_decl( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result, ErrorEmitted> { + match self { + Declaration::EnumDeclaration(decl_id) => Ok(*decl_id), + decl => Err(handler.emit_err(CompileError::DeclIsNotAnEnum { + actually: decl.friendly_type_name().to_string(), + span: decl.span(engines), + })), + } + } + + pub(crate) fn to_const_decl( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result, ErrorEmitted> { + match self { + Declaration::ConstantDeclaration(decl_id) => Ok(*decl_id), + decl => Err(handler.emit_err(CompileError::DeclIsNotAConstant { + actually: decl.friendly_type_name().to_string(), + span: decl.span(engines), + })), + } + } + #[allow(unused)] pub(crate) fn visibility(&self, decl_engine: &ParsedDeclEngine) -> Visibility { match self { diff --git a/sway-core/src/language/parsed/declaration/struct.rs b/sway-core/src/language/parsed/declaration/struct.rs index b69147fb579..26e6e94ecb1 100644 --- a/sway-core/src/language/parsed/declaration/struct.rs +++ b/sway-core/src/language/parsed/declaration/struct.rs @@ -7,6 +7,8 @@ use crate::{ }; use sway_types::{ident::Ident, span::Span, Named, Spanned}; +use super::ImplSelfOrTrait; + #[derive(Debug, Clone)] pub struct StructDeclaration { pub name: Ident, @@ -15,6 +17,8 @@ pub struct StructDeclaration { pub type_parameters: Vec, pub visibility: Visibility, pub(crate) span: Span, + // the impl blocks implementing this struct + pub impls: Vec, } impl EqWithEngines for StructDeclaration {} diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 90d41fbf19b..557a89c03de 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -23,7 +23,7 @@ pub use method_name::MethodName; pub use scrutinee::*; use sway_ast::intrinsics::Intrinsic; -use super::{FunctionDeclaration, StructDeclaration}; +use super::{Declaration, FunctionDeclaration, StructDeclaration}; /// Represents a parsed, but not yet type checked, [Expression](https://en.wikipedia.org/wiki/Expression_(computer_science)). #[derive(Debug, Clone)] @@ -295,6 +295,8 @@ impl PartialEqWithEngines for AmbiguousPathExpression { #[derive(Debug, Clone)] pub struct DelineatedPathExpression { pub call_path_binding: TypeBinding, + pub resolved_call_path_binding: Option>>, + /// When args is equal to Option::None then it means that the /// [DelineatedPathExpression] was initialized from an expression /// that does not end with parenthesis. diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index fcc524ce8a0..0065b5ca30f 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -36,6 +36,8 @@ pub use debug_generation::write_dwarf; use indexmap::IndexMap; use metadata::MetadataManager; use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, 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}; @@ -568,10 +570,15 @@ pub fn parsed_to_ast( // Build the dependency graph for the submodules. build_module_dep_graph(handler, &mut parse_program.root)?; - let namespace = Namespace::init_root(initial_namespace); + let initial_namespace = Namespace::init_root(initial_namespace); // Collect the program symbols. - let mut collection_ctx = - ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; + let namespace = initial_namespace.clone(); + let mut collection_ctx = ty::TyProgram::collect(handler, engines, parse_program, namespace)?; + + println!("namespace {:#?}", collection_ctx.namespace); + + let resolve_ctx = SymbolResolveContext::new(engines, &mut collection_ctx); + parse_program.resolve_symbols(handler, resolve_ctx); // Type check the program. let typed_program_opt = ty::TyProgram::type_check( @@ -579,7 +586,7 @@ pub fn parsed_to_ast( engines, parse_program, &mut collection_ctx, - namespace, + initial_namespace, package_name, build_config, ); 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 033fe5cff9b..f991a9a2208 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 @@ -23,9 +23,9 @@ use crate::{ }, namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, semantic_analysis::{ - symbol_collection_context::SymbolCollectionContext, AbiMode, ConstShadowingMode, - TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, - TypeCheckFinalization, TypeCheckFinalizationContext, + symbol_collection_context::SymbolCollectionContext, type_resolve::resolve_type, AbiMode, + ConstShadowingMode, TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, + TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, }, type_system::*, }; @@ -37,15 +37,22 @@ impl TyImplSelfOrTrait { ctx: &mut SymbolCollectionContext, decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { - let impl_trait = engines.pe().get_impl_self_or_trait(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - impl_trait.trait_name.suffix.clone(), - Declaration::ImplSelfOrTrait(*decl_id), - )?; + let mut impl_trait = engines + .pe() + .get_impl_self_or_trait(decl_id) + .as_ref() + .clone(); + + if !impl_trait.is_self { + ctx.insert_parsed_symbol( + handler, + engines, + impl_trait.trait_name.suffix.clone(), + Declaration::ImplSelfOrTrait(*decl_id), + )?; + } - let _ = ctx.scoped(engines, impl_trait.block_span.clone(), |scoped_ctx| { + let (_ret, _scope) = ctx.scoped(engines, impl_trait.block_span.clone(), |scoped_ctx| { impl_trait.items.iter().for_each(|item| match item { ImplItem::Fn(decl_id) => { let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); @@ -59,6 +66,32 @@ impl TyImplSelfOrTrait { }); Ok(()) }); + + // println!( + // "impl type id {:?}", + // engines.help_out(impl_trait.implementing_for.type_id) + // ); + + impl_trait.implementing_for.type_id = resolve_type( + handler, + engines, + &ctx.namespace, + ctx.namespace.mod_path(), + impl_trait.implementing_for.type_id, + &impl_trait.implementing_for.span, + EnforceTypeArguments::Yes, + None, + None, + &SubstTypesContext::dummy(engines), + )?; + + // println!( + // "after impl type id resolve {:?}", + // engines.help_out(impl_trait.implementing_for.type_id) + // ); + + engines.pe().replace(*decl_id, impl_trait); + Ok(()) } 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 af790c3d2ed..8d2e0194954 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 @@ -445,6 +445,7 @@ impl ty::TyExpression { ExpressionKind::DelineatedPath(delineated_path_expression) => { let DelineatedPathExpression { call_path_binding, + resolved_call_path_binding: _, args, } = *delineated_path_expression.clone(); Self::type_check_delineated_path( diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 7d4e22b7265..97c4b803e0b 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -739,13 +739,81 @@ impl Root { .chain(&call_path.prefixes) .cloned() .collect(); - self.resolve_symbol_and_mod_path( + let res = self.resolve_symbol_and_mod_path( handler, engines, &symbol_path, &call_path.suffix, self_type, - ) + ); + + if res.is_ok() { + return res; + } + + // First lets get the submodule and then hierarchically lookup the call path, + // starting from the module's root scope. + let submodule = self.module.lookup_submodule(handler, engines, mod_path)?; + let mut scope_id_opt = Some(submodule.root_lexical_scope_id()); + let mut item; + + for ident in call_path.prefixes.iter() { + // println!("checking for ident {:?}", ident); + if scope_id_opt.is_none() { + break; + } + + let scope = submodule.lexical_scopes.get(scope_id_opt.unwrap()).unwrap(); + item = scope.items.symbols().get(ident); + // println!("new item looked up {:?}", engines.help_out(item)); + if item.is_none() { + break; + } + + match item.unwrap() { + ResolvedDeclaration::Parsed(decl_id) => { + let span = decl_id.span(engines); + scope_id_opt = submodule.lexical_scopes_spans.get(&span).copied(); + // println!("new scope from item span {:?}", scope_id_opt); + } + ResolvedDeclaration::Typed(decl_id) => { + let span = decl_id.span(engines); + scope_id_opt = submodule.lexical_scopes_spans.get(&span).copied(); + } + }; + } + + // If we matched a struct or enum, then lets look through its impls for + // resolving our suffix. We have to take care to fetch the correct scope + // if we have a binding. + + if let Some(scope_id) = scope_id_opt { + let scope = submodule.lexical_scopes.get(scope_id).unwrap(); + + // match item.unwrap() { + // ResolvedDeclaration::Parsed(decl_id) => { + // let span = decl_id.span(engines); + // scope_id_opt = submodule.lexical_scopes_spans.get(&span).copied(); + // // println!("new scope from item span {:?}", scope_id_opt); + // } + // ResolvedDeclaration::Typed(decl_id) => { + // let span = decl_id.span(engines); + // scope_id_opt = submodule.lexical_scopes_spans.get(&span).copied(); + // }, + // }; + + // scope.items.reso + // let r = self + // .resolve_symbol(handler, engines, scope, &call_path.suffix, self_type) + // .map(|rd| (rd, mod_path.to_vec())); + // println!( + // "resolve_symbol_from_scope symbol {:?} {:?}", + // call_path.suffix, r + // ); + // return r; + } + + res } /// Given a path to a module and the identifier of a symbol within that module, resolve its diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index c34feeab4e6..01e03414446 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -634,6 +634,7 @@ impl Dependencies { ExpressionKind::DelineatedPath(delineated_path_expression) => { let DelineatedPathExpression { call_path_binding, + resolved_call_path_binding: _, args, } = &**delineated_path_expression; // It's either a module path which we can ignore, or an enum variant path, in which diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index 2a3be6aa35d..d093cb42bf8 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -1,7 +1,6 @@ use crate::{ language::{parsed::Declaration, Visibility}, - namespace::LexicalScopeId, - namespace::ModulePath, + namespace::{LexicalScopeId, ModulePath}, semantic_analysis::Namespace, Engines, }; @@ -10,7 +9,7 @@ use sway_types::{span::Span, Ident}; use super::{ConstShadowingMode, GenericShadowingMode}; -#[derive(Clone)] +//#[derive(Clone)] /// Contextual state tracked and accumulated throughout symbol collecting. pub struct SymbolCollectionContext { /// The namespace context accumulated throughout symbol collecting. diff --git a/sway-core/src/semantic_analysis/symbol_resolve.rs b/sway-core/src/semantic_analysis/symbol_resolve.rs index 60ac3da6a53..82bb2e3f17e 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -15,7 +15,7 @@ use crate::{ }, CallPath, CallPathTree, ResolvedCallPath, }, - TraitConstraint, TypeArgument, TypeBinding, TypeParameter, + TraitConstraint, TypeArgs, TypeArgument, TypeBinding, TypeParameter, }; use super::symbol_resolve_context::SymbolResolveContext; @@ -495,23 +495,14 @@ impl ResolveSymbols for StructScrutineeField { } 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 { + match &mut self.kind { ExpressionKind::Error(_, _) => {} ExpressionKind::Literal(_) => {} ExpressionKind::AmbiguousPathExpression(_) => {} ExpressionKind::FunctionApplication(expr) => { - let result = SymbolResolveTypeBinding::resolve_symbol( - &mut expr.call_path_binding, - &Handler::default(), - ctx.by_ref(), - ); + let result = expr.call_path_binding.resolve_symbol(handler, ctx.by_ref()); + if let Ok(result) = result { expr.resolved_call_path_binding = Some(TypeBinding::< ResolvedCallPath>, @@ -547,13 +538,11 @@ impl ResolveSymbols for ExpressionKind { .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(), - ); + // expr.call_path_binding + // .resolve_symbols(handler, ctx.by_ref()); + + let result = expr.call_path_binding.resolve_symbol(handler, ctx.by_ref()); + if let Ok(result) = result { expr.resolved_call_path_binding = Some(TypeBinding::< ResolvedCallPath>, @@ -604,7 +593,22 @@ impl ResolveSymbols for ExpressionKind { } ExpressionKind::Subfield(expr) => expr.prefix.resolve_symbols(handler, ctx), ExpressionKind::DelineatedPath(expr) => { - expr.call_path_binding.resolve_symbols(handler, ctx) + let result = + expr.call_path_binding + .resolve_symbol(handler, ctx.by_ref(), self.span.clone()); + + 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::AbiCast(expr) => { expr.abi_name.resolve_symbols(handler, ctx.by_ref()); @@ -644,3 +648,16 @@ impl ResolveSymbols for ExpressionKind { } } } + +impl ResolveSymbols for TypeBinding { + 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())), + } + } +} diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 01bc631ec0e..107afbd7132 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -1,9 +1,9 @@ use crate::{ engine_threading::*, - language::{CallPath, Visibility}, + language::{CallPath, QualifiedCallPath, Visibility}, namespace::{ModulePath, ResolvedDeclaration}, semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, - type_system::TypeId, + type_system::TypeId, SubstTypesContext, }; use sway_error::{ error::CompileError, @@ -12,7 +12,10 @@ use sway_error::{ use sway_types::{span::Span, Ident, Spanned}; use sway_utils::iter_prefixes; -use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; +use super::{ + symbol_collection_context::SymbolCollectionContext, type_resolve::resolve_qualified_call_path, + GenericShadowingMode, +}; /// Contextual state tracked and accumulated throughout symbol resolving. pub struct SymbolResolveContext<'a> { @@ -250,4 +253,20 @@ impl<'a> SymbolResolveContext<'a> { Ok(decl) } + + pub(crate) fn resolve_qualified_call_path_with_visibility_check( + &mut self, + handler: &Handler, + qualified_call_path: &QualifiedCallPath, + ) -> Result { + resolve_qualified_call_path( + handler, + self.engines(), + self.namespace(), + &self.namespace().mod_path.clone(), + qualified_call_path, + self.self_type(), + &SubstTypesContext::dummy(self.engines()), + ) + } } diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index f2498364acf..f977ca1fdf4 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -7,6 +7,7 @@ use sway_utils::iter_prefixes; use crate::{ language::{ + parsed::Declaration, ty::{self, TyTraitItem}, CallPath, QualifiedCallPath, }, @@ -354,7 +355,26 @@ pub fn decl_to_type_info( decl: ResolvedDeclaration, ) -> Result { match decl { - ResolvedDeclaration::Parsed(_decl) => todo!(), + ResolvedDeclaration::Parsed(decl) => Ok(match decl.clone() { + Declaration::StructDeclaration(decl_id) => TypeInfo::UntypedStruct(decl_id), + Declaration::EnumDeclaration(decl_id) => TypeInfo::UntypedEnum(decl_id), + Declaration::TraitTypeDeclaration(decl_id) => { + let trait_type_decl = engines.pe().get_trait_type(&decl_id); + if trait_type_decl.ty_opt.is_none() { + return Err(handler.emit_err(CompileError::Internal( + "Trait type declaration has no type", + symbol.span(), + ))); + } + (*engines.te().get(trait_type_decl.ty_opt.clone().unwrap().type_id)).clone() + } + _ => { + return Err(handler.emit_err(CompileError::SymbolNotFound { + name: symbol.clone(), + span: symbol.span(), + })) + } + }), ResolvedDeclaration::Typed(decl) => Ok(match decl.clone() { ty::TyDecl::StructDecl(struct_ty_decl) => TypeInfo::Struct(struct_ty_decl.decl_id), ty::TyDecl::EnumDecl(enum_ty_decl) => TypeInfo::Enum(enum_ty_decl.decl_id), 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 b48cce083eb..a3ce9bd3239 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 @@ -454,6 +454,7 @@ fn item_struct_to_struct_declaration( )?, visibility: pub_token_opt_to_visibility(item_struct.visibility), span, + impls: vec![], }); Ok(struct_declaration_id) } @@ -2903,6 +2904,7 @@ fn path_expr_to_expression( Expression { kind: ExpressionKind::DelineatedPath(Box::new(DelineatedPathExpression { call_path_binding, + resolved_call_path_binding: None, args: None, })), span, diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 9a4c7c1dd43..8d08b1b0b65 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -1,5 +1,9 @@ use sway_ast::Intrinsic; -use sway_error::handler::{ErrorEmitted, Handler}; +use sway_error::{ + convert_parse_tree_error::ConvertParseTreeError, + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Span, Spanned}; use crate::{ @@ -8,13 +12,14 @@ use crate::{ }, engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}, language::{ - parsed::{FunctionDeclaration, StructDeclaration}, + parsed::{ + ConstantDeclaration, Declaration, EnumDeclaration, EnumVariantDeclaration, + FunctionDeclaration, StructDeclaration, + }, ty, CallPath, QualifiedCallPath, }, - semantic_analysis::{ - symbol_resolve::ResolveSymbols, symbol_resolve_context::SymbolResolveContext, - TypeCheckContext, - }, + semantic_analysis::{symbol_resolve_context::SymbolResolveContext, TypeCheckContext}, + transform::to_parsed_lang::type_name_to_type_info_opt, type_system::priv_prelude::*, EnforceTypeArguments, Ident, }; @@ -192,17 +197,6 @@ 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> { @@ -274,10 +268,10 @@ pub trait SymbolResolveTypeBinding { &mut self, handler: &Handler, ctx: SymbolResolveContext, - ) -> Result, ErrorEmitted>; + ) -> Result; } -impl SymbolResolveTypeBinding for TypeBinding { +impl SymbolResolveTypeBinding> for TypeBinding { fn resolve_symbol( &mut self, handler: &Handler, @@ -289,11 +283,40 @@ impl SymbolResolveTypeBinding for TypeBinding { // Check to see if this is a function declaration. let fn_decl = unknown_decl .resolve_parsed(engines.de()) - .to_fn_ref(handler, engines)?; + .to_fn_decl(handler, engines)?; Ok(fn_decl) } } +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)? + .expect_parsed(); + + // Check to see if this is a enum declaration. + let enum_decl = if let Declaration::EnumVariantDeclaration(EnumVariantDeclaration { + enum_ref, + .. + }) = &unknown_decl + { + *enum_ref + } else { + // Check to see if this is a enum declaration. + unknown_decl.to_enum_decl(handler, engines)? + }; + + Ok(enum_decl) + } +} + impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, @@ -356,7 +379,7 @@ impl TypeCheckTypeBinding for TypeBinding { } } -impl SymbolResolveTypeBinding for TypeBinding { +impl SymbolResolveTypeBinding> for TypeBinding { fn resolve_symbol( &mut self, handler: &Handler, @@ -473,6 +496,239 @@ impl TypeCheckTypeBinding for TypeBinding { } } +impl TypeBinding { + pub fn resolve_symbol( + &mut self, + handler: &Handler, + mut ctx: SymbolResolveContext, + span: Span, + ) -> Result { + let engines = ctx.engines(); + + println!("resolve_symbol {:?}", self.inner); + + // The first step is to determine if the call path refers to a module, + // enum, function or constant. + // If only one exists, then we use that one. Otherwise, if more than one exist, it is + // an ambiguous reference error. + + let mut is_module = false; + let mut maybe_function: Option<(ParsedDeclId, _)> = None; + let mut maybe_enum: Option<(ParsedDeclId, _, _)> = None; + + let module_probe_handler = Handler::default(); + let function_probe_handler = Handler::default(); + let enum_probe_handler = Handler::default(); + let const_probe_handler = Handler::default(); + + if self.inner.qualified_path_root.is_none() { + // Check if this could be a module + is_module = { + let call_path_binding = self.clone(); + ctx.namespace().program_id(engines).read(engines, |m| { + m.lookup_submodule( + &module_probe_handler, + engines, + &[ + call_path_binding.inner.call_path.prefixes.clone(), + vec![call_path_binding.inner.call_path.suffix.clone()], + ] + .concat(), + ) + .ok() + .is_some() + }) + }; + + // Check if this could be a function + maybe_function = { + let call_path_binding = self.clone(); + let mut call_path_binding = TypeBinding { + inner: call_path_binding.inner.call_path, + type_arguments: call_path_binding.type_arguments, + span: call_path_binding.span, + }; + + let result: Result, ErrorEmitted> = + SymbolResolveTypeBinding::resolve_symbol( + &mut call_path_binding, + &function_probe_handler, + ctx.by_ref(), + ); + + result.ok().map(|fn_ref| (fn_ref, call_path_binding)) + }; + + // Check if this could be an enum + maybe_enum = { + let call_path_binding = self.clone(); + let variant_name = call_path_binding.inner.call_path.suffix.clone(); + let enum_call_path = call_path_binding.inner.call_path.rshift(); + + let mut call_path_binding = TypeBinding { + inner: enum_call_path, + type_arguments: call_path_binding.type_arguments, + span: call_path_binding.span, + }; + + let result: Result, ErrorEmitted> = + SymbolResolveTypeBinding::resolve_symbol( + &mut call_path_binding, + &enum_probe_handler, + ctx.by_ref(), + ); + + result + .ok() + .map(|enum_ref| (enum_ref, variant_name, call_path_binding)) + }; + }; + + // Check if this could be a constant + let maybe_const = SymbolResolveTypeBinding::<( + ParsedDeclId, + TypeBinding, + )>::resolve_symbol(self, &const_probe_handler, ctx.by_ref()) + .ok(); + + // compare the results of the checks + let exp = match (is_module, maybe_function, maybe_enum, maybe_const) { + (false, None, Some((enum_ref, _variant_name, _call_path_binding)), None) => { + handler.append(enum_probe_handler); + Declaration::EnumDeclaration(enum_ref) + } + (false, Some((fn_ref, call_path_binding)), None, None) => { + handler.append(function_probe_handler); + // In case `foo::bar::::baz(...)` throw an error. + if let TypeArgs::Prefix(_) = call_path_binding.type_arguments { + handler.emit_err( + ConvertParseTreeError::GenericsNotSupportedHere { + span: call_path_binding.type_arguments.span(), + } + .into(), + ); + } + Declaration::FunctionDeclaration(fn_ref) + } + (true, None, None, None) => { + handler.append(module_probe_handler); + return Err(handler.emit_err(CompileError::ModulePathIsNotAnExpression { + module_path: self.inner.call_path.to_string(), + span, + })); + } + (false, None, None, Some((const_ref, call_path_binding))) => { + handler.append(const_probe_handler); + if !call_path_binding.type_arguments.to_vec().is_empty() { + // In case `foo::bar::CONST::` throw an error. + // In case `foo::bar::::CONST` throw an error. + handler.emit_err( + ConvertParseTreeError::GenericsNotSupportedHere { + span: self.type_arguments.span(), + } + .into(), + ); + } + Declaration::ConstantDeclaration(const_ref) + } + (false, None, None, None) => { + return Err(handler.emit_err(CompileError::SymbolNotFound { + name: self.inner.call_path.suffix.clone(), + span: self.inner.call_path.suffix.span(), + })); + } + _ => { + return Err(handler.emit_err(CompileError::AmbiguousPath { span })); + } + }; + + Ok(exp) + } +} + +impl SymbolResolveTypeBinding> for TypeBinding { + fn resolve_symbol( + &mut self, + handler: &Handler, + ctx: SymbolResolveContext, + ) -> Result, ErrorEmitted> { + println!( + "resolve_symbol SymbolResolveTypeBinding Constant {:?}", + self + ); + + // Grab the declaration. + let unknown_decl = ctx + .resolve_call_path_with_visibility_check(handler, &self.inner)? + .expect_parsed(); + + // Check to see if this is a const declaration. + let const_ref = unknown_decl.to_const_decl(handler, ctx.engines())?; + + Ok(const_ref) + } +} + +impl SymbolResolveTypeBinding<(ParsedDeclId, TypeBinding)> + for TypeBinding +{ + fn resolve_symbol( + &mut self, + handler: &Handler, + mut ctx: SymbolResolveContext, + ) -> Result<(ParsedDeclId, TypeBinding), ErrorEmitted> { + let mut call_path_binding = TypeBinding { + inner: self.inner.call_path.clone(), + type_arguments: self.type_arguments.clone(), + span: self.span.clone(), + }; + + println!( + "resolve_symbol SymbolResolveTypeBinding Constant {:?}", + call_path_binding + ); + + let type_info_opt = call_path_binding + .clone() + .inner + .prefixes + .last() + .map(|type_name| { + type_name_to_type_info_opt(type_name).unwrap_or(TypeInfo::Custom { + qualified_call_path: type_name.clone().into(), + type_arguments: None, + root_type_id: None, + }) + }); + + if let Some(type_info) = type_info_opt { + if TypeInfo::is_self_type(&type_info) { + call_path_binding.strip_prefixes(); + } + } + + let const_res: Result, ErrorEmitted> = + SymbolResolveTypeBinding::resolve_symbol( + &mut call_path_binding, + &Handler::default(), + ctx.by_ref(), + ); + if const_res.is_ok() { + return const_res.map(|const_ref| (const_ref, call_path_binding.clone())); + } + + // If we didn't find a constant, check for the constant inside the impl. + let unknown_decl = ctx + .resolve_qualified_call_path_with_visibility_check(handler, &self.inner)? + .expect_parsed(); + + // Check to see if this is a const declaration. + let const_ref = unknown_decl.to_const_decl(handler, ctx.engines())?; + + Ok((const_ref, call_path_binding.clone())) + } +} + impl TypeBinding { pub(crate) fn type_check_qualified( &mut self, diff --git a/sway-core/src/type_system/monomorphization.rs b/sway-core/src/type_system/monomorphization.rs index 674650896db..96cb4aa0cc3 100644 --- a/sway-core/src/type_system/monomorphization.rs +++ b/sway-core/src/type_system/monomorphization.rs @@ -7,6 +7,7 @@ use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::{engine::DeclEngineGetParsedDeclId, DeclEngineInsert}, language::{ + parsed::Declaration, ty::{self}, CallPath, }, @@ -231,6 +232,15 @@ pub(crate) fn type_decl_opt_to_type_id( let decl_engine = engines.de(); let type_engine = engines.te(); Ok(match type_decl_opt { + Some(ResolvedDeclaration::Parsed(Declaration::StructDeclaration(decl_id))) => { + type_engine.insert(engines, TypeInfo::UntypedStruct(decl_id), span.source_id()) + } + Some(ResolvedDeclaration::Parsed(Declaration::EnumDeclaration(decl_id))) => { + todo!(); + } + Some(ResolvedDeclaration::Parsed(Declaration::TypeAliasDeclaration(decl_id))) => { + todo!(); + } Some(ResolvedDeclaration::Typed(ty::TyDecl::StructDecl(ty::StructDecl { decl_id: original_id, .. diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 880915f915b..1ed0dba2f2e 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -413,6 +413,7 @@ impl Parse for DelineatedPathExpression { let DelineatedPathExpression { call_path_binding, args, + resolved_call_path_binding: _, } = self; adaptive_iter(&call_path_binding.inner.call_path.prefixes, |ident| { ctx.tokens.insert( diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/primitive_type_argument/src/foo.sw b/test/src/e2e_vm_tests/test_programs/should_fail/primitive_type_argument/src/foo.sw index 871fba91f2b..9c0926b439e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/primitive_type_argument/src/foo.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/primitive_type_argument/src/foo.sw @@ -1,3 +1,3 @@ library; -mod bar; +pub mod bar;