diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index cc5ba3f6f3a..d6ff6eb2f97 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -140,7 +140,6 @@ impl UnconstrainedTypeParameters for TyFunctionDeclaration { type_parameter: &TypeParameter, ) -> bool { let type_engine = engines.te(); - let decl_engine = engines.de(); let mut all_types: HashSet = self .type_parameters .iter() @@ -149,14 +148,14 @@ impl UnconstrainedTypeParameters for TyFunctionDeclaration { all_types.extend(self.parameters.iter().flat_map(|param| { let mut inner = type_engine .get(param.type_argument.type_id) - .extract_inner_types(type_engine, decl_engine); + .extract_inner_types(engines); inner.insert(param.type_argument.type_id); inner })); all_types.extend( type_engine .get(self.return_type.type_id) - .extract_inner_types(type_engine, decl_engine), + .extract_inner_types(engines), ); all_types.insert(self.return_type.type_id); let type_parameter_info = type_engine.get(type_parameter.type_id); diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 25db5bf666f..9f74668150f 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -147,8 +147,13 @@ impl CollectTypesMetadata for TyExpression { StructExpression { fields, instantiation_span, + struct_ref, .. } => { + let struct_decl = decl_engine.get_struct(struct_ref); + for type_parameter in struct_decl.type_parameters { + ctx.call_site_insert(type_parameter.type_id, instantiation_span.clone()); + } if let TypeInfo::Struct(decl_ref) = ctx.type_engine.get(self.return_type) { let decl = decl_engine.get_struct(&decl_ref); for type_parameter in decl.type_parameters { diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index d85824ff698..a8d4f3de81e 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -189,19 +189,18 @@ impl TyProgram { { let storage_decl = decl_engine.get_storage(decl_id); for field in storage_decl.fields.iter() { - let type_info = ty_engine.get(field.type_argument.type_id); - let type_info_str = engines.help_out(&type_info).to_string(); - let raw_ptr_type = type_info - .extract_nested_types(engines, &field.span) - .value - .and_then(|value| { - value - .into_iter() - .find(|ty| matches!(ty, TypeInfo::RawUntypedPtr)) - }); - if raw_ptr_type.is_some() { + if !field + .type_argument + .type_id + .extract_any_including_self(engines, &|type_info| { + matches!(type_info, TypeInfo::RawUntypedPtr) + }) + .is_empty() + { errors.push(CompileError::TypeNotAllowedInContractStorage { - ty: type_info_str, + ty: engines + .help_out(&ty_engine.get(field.type_argument.type_id)) + .to_string(), span: field.span.clone(), }); } @@ -260,27 +259,24 @@ impl TyProgram { // Directly returning a `raw_slice` is allowed, which will be just mapped to a RETD. // TODO: Allow returning nested `raw_slice`s when our spec supports encoding DSTs. let main_func = mains.remove(0); - let main_return_type_info = ty_engine.get(main_func.return_type.type_id); - let nested_types = check!( - main_return_type_info - .clone() - .extract_nested_types(engines, &main_func.return_type.span), - vec![], - warnings, - errors - ); - if nested_types - .iter() - .any(|ty| matches!(ty, TypeInfo::RawUntypedPtr)) + if !main_func + .return_type + .type_id + .extract_any_including_self(engines, &|type_info| { + matches!(type_info, TypeInfo::RawUntypedPtr) + }) + .is_empty() { errors.push(CompileError::PointerReturnNotAllowedInMain { span: main_func.return_type.span.clone(), }); } - if !matches!(main_return_type_info, TypeInfo::RawUntypedSlice) - && nested_types - .iter() - .any(|ty| matches!(ty, TypeInfo::RawUntypedSlice)) + if !ty_engine + .get(main_func.return_type.type_id) + .extract_any(engines, &|type_info| { + matches!(type_info, TypeInfo::RawUntypedSlice) + }) + .is_empty() { errors.push(CompileError::NestedSliceReturnNotAllowedInMain { span: main_func.return_type.span.clone(), 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 1a36818c611..e1bb29b87e6 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 @@ -86,7 +86,6 @@ impl ty::TyImplTrait { &new_impl_type_parameters, &trait_type_arguments, implementing_for.type_id, - &implementing_for.span ), return err(warnings, errors), warnings, @@ -495,7 +494,6 @@ impl ty::TyImplTrait { &new_impl_type_parameters, &[], implementing_for.type_id, - &implementing_for.span ), return err(warnings, errors), warnings, @@ -1191,9 +1189,8 @@ fn check_for_unconstrained_type_parameters( type_parameters: &[TypeParameter], trait_type_arguments: &[TypeArgument], self_type: TypeId, - self_type_span: &Span, ) -> CompileResult<()> { - let mut warnings = vec![]; + let warnings = vec![]; let mut errors = vec![]; // create a list of defined generics, with the generic and a span @@ -1207,25 +1204,14 @@ fn check_for_unconstrained_type_parameters( // create a list of the generics in use in the impl signature let mut generics_in_use = HashSet::new(); for type_arg in trait_type_arguments.iter() { - generics_in_use.extend(check!( + generics_in_use.extend( engines .te() .get(type_arg.type_id) - .extract_nested_generics(engines, &type_arg.span), - HashSet::new(), - warnings, - errors - )); + .extract_nested_generics(engines), + ); } - generics_in_use.extend(check!( - engines - .te() - .get(self_type) - .extract_nested_generics(engines, self_type_span), - HashSet::new(), - warnings, - errors - )); + generics_in_use.extend(engines.te().get(self_type).extract_nested_generics(engines)); // TODO: add a lookup in the trait constraints here and add it to // generics_in_use diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs index dc8864c193a..735a581ceac 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs @@ -18,20 +18,9 @@ pub(crate) struct ConstructorFactory { } impl ConstructorFactory { - pub(crate) fn new(engines: Engines<'_>, type_id: TypeId, span: &Span) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - let possible_types = check!( - engines - .te() - .get(type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors - ); - let factory = ConstructorFactory { possible_types }; - ok(factory, warnings, errors) + pub(crate) fn new(engines: Engines<'_>, type_id: TypeId) -> Self { + let possible_types = engines.te().get(type_id).extract_nested_types(engines); + ConstructorFactory { possible_types } } /// Given Σ, computes a `Pattern` not present in Σ from the type of the diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs index 643278a5b13..3fea3f24388 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs @@ -223,12 +223,7 @@ pub(crate) fn check_match_expression_usefulness( return ok((witness_report, arms_reachability), warnings, errors); } - let factory = check!( - ConstructorFactory::new(engines, type_id, &span), - return err(warnings, errors), - warnings, - errors - ); + let factory = ConstructorFactory::new(engines, type_id); for scrutinee in scrutinees.into_iter() { let pat = check!( Pattern::from_scrutinee(scrutinee.clone()), 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 50d200a2a47..e94118304c2 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 @@ -463,17 +463,9 @@ impl ty::TyExpression { let mut warnings = vec![]; let mut errors = vec![]; - // Grab the declaration. - let (unknown_decl, _type_id) = check!( - TypeBinding::type_check_with_ident(&mut call_path_binding, ctx.by_ref()), - return err(warnings, errors), - warnings, - errors - ); - - // Unwrap a fn ref if possible. - let fn_ref = check!( - unknown_decl.to_fn_ref(), + // Grab the fn declaration. + let (fn_ref, _): (DeclRefFunction, _) = check!( + TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()), return err(warnings, errors), warnings, errors @@ -1087,19 +1079,17 @@ impl ty::TyExpression { // Check if this could be a function let mut function_probe_warnings = Vec::new(); let mut function_probe_errors = Vec::new(); - - let maybe_function = { + let maybe_function: Option<(DeclRefFunction, _)> = { let mut call_path_binding = unknown_call_path_binding.clone(); - TypeBinding::type_check_with_ident(&mut call_path_binding, ctx.by_ref()) - .flat_map(|(decl, _type_id)| decl.to_fn_ref()) + TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) .ok(&mut function_probe_warnings, &mut function_probe_errors) - .map(|fn_ref| (fn_ref, call_path_binding)) + .map(|(fn_ref, _)| (fn_ref, call_path_binding)) }; // Check if this could be an enum let mut enum_probe_warnings = vec![]; let mut enum_probe_errors = vec![]; - let maybe_enum = { + let maybe_enum: Option<(DeclRefEnum, _, _)> = { let call_path_binding = unknown_call_path_binding.clone(); let variant_name = call_path_binding.inner.suffix.clone(); let enum_call_path = call_path_binding.inner.rshift(); @@ -1109,10 +1099,9 @@ impl ty::TyExpression { type_arguments: call_path_binding.type_arguments, span: call_path_binding.span, }; - TypeBinding::type_check_with_ident(&mut call_path_binding, ctx.by_ref()) - .flat_map(|(unknown_decl, _type_id)| unknown_decl.to_enum_ref(ctx.engines())) + TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) .ok(&mut enum_probe_warnings, &mut enum_probe_errors) - .map(|enum_ref| (enum_ref, variant_name, call_path_binding)) + .map(|(enum_ref, _)| (enum_ref, variant_name, call_path_binding)) }; // Check if this could be a constant @@ -1224,10 +1213,10 @@ impl ty::TyExpression { call_path_binding.strip_prefixes(); } - let const_opt = TypeBinding::type_check_with_ident(&mut call_path_binding, ctx.by_ref()) - .flat_map(|(unknown_decl, _type_id)| unknown_decl.to_const_ref()) - .ok(const_probe_warnings, const_probe_errors) - .map(|const_decl| (const_decl, call_path_binding.clone())); + let const_opt: Option<(DeclRefConstant, _)> = + TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) + .ok(const_probe_warnings, const_probe_errors) + .map(|(const_ref, _)| (const_ref, call_path_binding.clone())); if const_opt.is_some() { return const_opt; } @@ -1245,19 +1234,16 @@ impl ty::TyExpression { span: call_path_binding.span.clone(), }; - let struct_type_id = match check!( - TypeBinding::type_check_with_ident(&mut const_call_path_binding, ctx.by_ref()), + let (_, struct_type_id): (DeclRefStruct, _) = check!( + TypeBinding::type_check(&mut const_call_path_binding, ctx.by_ref()), return None, const_probe_warnings, const_probe_errors - ) { - (ty::TyDeclaration::StructDeclaration { .. }, Some(type_id)) => type_id, - _ => return None, - }; + ); let const_decl_ref = check!( ctx.namespace.find_constant_for_type( - struct_type_id, + struct_type_id.unwrap(), &suffix, ctx.self_type(), ctx.engines(), diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1eb3b64422a..8bcafc38a22 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -2,6 +2,7 @@ use sway_error::error::CompileError; use sway_types::{Ident, Span, Spanned}; use crate::{ + decl_engine::DeclRefStruct, error::*, language::{parsed::*, ty, CallPath}, semantic_analysis::TypeCheckContext, @@ -24,7 +25,8 @@ pub(crate) fn struct_instantiation( // We need the call_path_binding to have types that point to proper definitions so the LSP can // look for them, but its types haven't been resolved yet. // To that end we do a dummy type check which has the side effect of resolving the types. - let _ = TypeBinding::type_check_with_ident(&mut call_path_binding, ctx.by_ref()); + let _: CompileResult<(DeclRefStruct, _)> = + TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()); let TypeBinding { inner: CallPath { diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 6a1ac3305ac..b26cf75362b 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -477,14 +477,11 @@ impl TraitMap { /// with those entries for `Data`. pub(crate) fn filter_by_type(&self, type_id: TypeId, engines: Engines<'_>) -> TraitMap { let type_engine = engines.te(); - let decl_engine = engines.de(); // a curried version of the decider protocol to use in the helper functions let decider = |type_info: &TypeInfo, map_type_info: &TypeInfo| { type_info.is_subset_of(map_type_info, engines) }; - let mut all_types = type_engine - .get(type_id) - .extract_inner_types(type_engine, decl_engine); + let mut all_types = type_engine.get(type_id).extract_inner_types(engines); all_types.insert(type_id); let all_types = all_types.into_iter().collect::>(); self.filter_by_type_inner(engines, all_types, decider) @@ -554,7 +551,6 @@ impl TraitMap { engines: Engines<'_>, ) -> TraitMap { let type_engine = engines.te(); - let decl_engine = engines.de(); // a curried version of the decider protocol to use in the helper functions let decider = |type_info: &TypeInfo, map_type_info: &TypeInfo| { type_info.is_subset_of(map_type_info, engines) @@ -563,7 +559,7 @@ impl TraitMap { let mut trait_map = self.filter_by_type_inner(engines, vec![type_id], decider); let all_types = type_engine .get(type_id) - .extract_inner_types(type_engine, decl_engine) + .extract_inner_types(engines) .into_iter() .collect::>(); // a curried version of the decider protocol to use in the helper functions diff --git a/sway-core/src/semantic_analysis/storage_only_types.rs b/sway-core/src/semantic_analysis/storage_only_types.rs index d9adb71ab1b..ec111a622ae 100644 --- a/sway-core/src/semantic_analysis/storage_only_types.rs +++ b/sway-core/src/semantic_analysis/storage_only_types.rs @@ -156,12 +156,7 @@ fn check_type( warnings, errors ); - let nested_types = check!( - type_info.clone().extract_nested_types(engines, &span), - vec![], - warnings, - errors - ); + let nested_types = type_info.clone().extract_nested_types(engines); for ty in nested_types { if ignore_self && ty.eq(&type_info, engines) { continue; diff --git a/sway-core/src/type_system/binding.rs b/sway-core/src/type_system/binding.rs index 643d000f98b..c9f8297a6c3 100644 --- a/sway-core/src/type_system/binding.rs +++ b/sway-core/src/type_system/binding.rs @@ -209,19 +209,28 @@ impl TypeBinding { pub(crate) fn strip_prefixes(&mut self) { self.inner.prefixes = vec![]; } +} + +/// Trait that adds a workaround for easy generic returns in Rust: +/// https://blog.jcoglan.com/2019/04/22/generic-returns-in-rust/ +pub(crate) trait TypeCheckTypeBinding { + fn type_check( + &mut self, + ctx: TypeCheckContext, + ) -> CompileResult<(DeclRef>, Option)>; +} - pub(crate) fn type_check_with_ident( +impl TypeCheckTypeBinding for TypeBinding { + fn type_check( &mut self, mut ctx: TypeCheckContext, - ) -> CompileResult<(ty::TyDeclaration, Option)> { + ) -> CompileResult<(DeclRef>, Option)> { let mut warnings = vec![]; let mut errors = vec![]; - let type_engine = ctx.type_engine; let decl_engine = ctx.decl_engine; let engines = ctx.engines(); - - // grab the declaration + // Grab the declaration. let unknown_decl = check!( ctx.namespace .resolve_call_path_with_visibility_check(engines, &self.inner) @@ -230,68 +239,18 @@ impl TypeBinding { warnings, errors ); - - // replace the self types inside of the type arguments - for type_argument in self.type_arguments.to_vec_mut().iter_mut() { - check!( - ctx.resolve_type_with_self( - type_argument.type_id, - &type_argument.span, - EnforceTypeArguments::Yes, - None - ), - type_engine.insert(decl_engine, TypeInfo::ErrorRecovery), - warnings, - errors, - ); - } - - if !errors.is_empty() { - // Returns ok with error, this allows functions which call this to - // also access the returned TyDeclaration and throw more suitable errors. - return ok((unknown_decl, None), warnings, errors); - } - - // monomorphize the declaration, if needed - let (new_decl, new_type_id) = match unknown_decl { - ty::TyDeclaration::FunctionDeclaration { - decl_id: original_id, - .. - } => { - // get the copy from the declaration engine - let mut new_copy = decl_engine.get_function(&original_id); - - // monomorphize the copy, in place - if let TypeArgs::Regular(_) = self.type_arguments { - check!( - ctx.monomorphize( - &mut new_copy, - self.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &self.span - ), - return err(warnings, errors), - warnings, - errors - ); - } - - // insert the new copy into the declaration engine - let new_decl_ref = ctx - .decl_engine - .insert(new_copy) - .with_parent(ctx.decl_engine, original_id.into()); - - (new_decl_ref.into(), None) - } - ty::TyDeclaration::EnumDeclaration { - decl_id: original_id, - .. - } => { - // get the copy from the declaration engine - let mut new_copy = decl_engine.get_enum(&original_id); - - // monomorphize the copy, in place + // Check to see if this is a fn declaration. + let fn_ref = check!( + unknown_decl.to_fn_ref(), + return err(warnings, errors), + warnings, + errors + ); + // Get a new copy from the declaration engine. + let mut new_copy = decl_engine.get_function(fn_ref.id()); + match self.type_arguments { + // Monomorphize the copy, in place. + TypeArgs::Regular(_) => { check!( ctx.monomorphize( &mut new_copy, @@ -303,51 +262,161 @@ impl TypeBinding { warnings, errors ); + } + TypeArgs::Prefix(_) => { + // Resolve the type arguments without monomorphizing. + for type_argument in self.type_arguments.to_vec_mut().iter_mut() { + check!( + ctx.resolve_type_with_self( + type_argument.type_id, + &type_argument.span, + EnforceTypeArguments::Yes, + None + ), + type_engine.insert(decl_engine, TypeInfo::ErrorRecovery), + warnings, + errors, + ); + } + } + } + // Insert the new copy into the declaration engine. + let new_fn_ref = ctx + .decl_engine + .insert(new_copy) + .with_parent(ctx.decl_engine, fn_ref.id().into()); + ok((new_fn_ref, None), warnings, errors) + } +} - // insert the new copy into the declaration engine - let new_decl_ref = ctx.decl_engine.insert(new_copy); - - let type_id = type_engine.insert(decl_engine, TypeInfo::Enum(new_decl_ref.clone())); - // take any trait methods that apply to this type and copy them to the new type - ctx.namespace - .insert_trait_implementation_for_type(engines, type_id); +impl TypeCheckTypeBinding for TypeBinding { + fn type_check( + &mut self, + mut ctx: TypeCheckContext, + ) -> CompileResult<(DeclRef>, Option)> { + let mut warnings = vec![]; + let mut errors = vec![]; + let type_engine = ctx.type_engine; + let decl_engine = ctx.decl_engine; + let engines = ctx.engines(); + // Grab the declaration. + let unknown_decl = check!( + ctx.namespace + .resolve_call_path_with_visibility_check(engines, &self.inner) + .cloned(), + return err(warnings, errors), + warnings, + errors + ); + // Check to see if this is a struct declaration. + let struct_ref = check!( + unknown_decl.to_struct_ref(engines), + return err(warnings, errors), + warnings, + errors + ); + // Get a new copy from the declaration engine. + let mut new_copy = decl_engine.get_struct(struct_ref.id()); + // Monomorphize the copy, in place. + check!( + ctx.monomorphize( + &mut new_copy, + self.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &self.span + ), + return err(warnings, errors), + warnings, + errors + ); + // Insert the new copy into the declaration engine. + let new_struct_ref = ctx.decl_engine.insert(new_copy); + // Take any trait items that apply to the old type and copy them to the new type. + let type_id = type_engine.insert(decl_engine, TypeInfo::Struct(new_struct_ref.clone())); + ctx.namespace + .insert_trait_implementation_for_type(engines, type_id); + ok((new_struct_ref, Some(type_id)), warnings, errors) + } +} - (new_decl_ref.into(), Some(type_id)) - } - ty::TyDeclaration::StructDeclaration { - decl_id: original_id, - .. - } => { - // get the copy from the declaration engine - let mut new_copy = decl_engine.get_struct(&original_id); +impl TypeCheckTypeBinding for TypeBinding { + fn type_check( + &mut self, + mut ctx: TypeCheckContext, + ) -> CompileResult<(DeclRef>, Option)> { + let mut warnings = vec![]; + let mut errors = vec![]; + let type_engine = ctx.type_engine; + let decl_engine = ctx.decl_engine; + let engines = ctx.engines(); + // Grab the declaration. + let unknown_decl = check!( + ctx.namespace + .resolve_call_path_with_visibility_check(engines, &self.inner) + .cloned(), + return err(warnings, errors), + warnings, + errors + ); + // Check to see if this is a enum declaration. + let enum_ref = check!( + unknown_decl.to_enum_ref(engines), + return err(warnings, errors), + warnings, + errors + ); + // Get a new copy from the declaration engine. + let mut new_copy = decl_engine.get_enum(enum_ref.id()); + // Monomorphize the copy, in place. + check!( + ctx.monomorphize( + &mut new_copy, + self.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &self.span + ), + return err(warnings, errors), + warnings, + errors + ); + // Insert the new copy into the declaration engine. + let new_enum_ref = ctx.decl_engine.insert(new_copy); + // Take any trait items that apply to the old type and copy them to the new type. + let type_id = type_engine.insert(decl_engine, TypeInfo::Enum(new_enum_ref.clone())); + ctx.namespace + .insert_trait_implementation_for_type(engines, type_id); + ok((new_enum_ref, Some(type_id)), warnings, errors) + } +} - // monomorphize the copy, in place - check!( - ctx.monomorphize( - &mut new_copy, - self.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &self.span - ), - return err(warnings, errors), - warnings, - errors - ); +impl TypeCheckTypeBinding for TypeBinding { + fn type_check( + &mut self, + ctx: TypeCheckContext, + ) -> CompileResult<(DeclRef>, Option)> { + let mut warnings = vec![]; + let mut errors = vec![]; - // insert the new copy into the declaration engine - let new_decl_ref = ctx.decl_engine.insert(new_copy); + let engines = ctx.engines(); - // take any trait items that apply to this type and copy them to the new type - let type_id = - type_engine.insert(decl_engine, TypeInfo::Struct(new_decl_ref.clone())); - ctx.namespace - .insert_trait_implementation_for_type(engines, type_id); + // Grab the declaration. + let unknown_decl = check!( + ctx.namespace + .resolve_call_path_with_visibility_check(engines, &self.inner) + .cloned(), + return err(warnings, errors), + warnings, + errors + ); - (new_decl_ref.into(), Some(type_id)) - } - _ => (unknown_decl, None), - }; + // Check to see if this is a const declaration. + let const_ref = check!( + unknown_decl.to_const_ref(), + return err(warnings, errors), + warnings, + errors + ); - ok((new_decl, new_type_id), warnings, errors) + ok((const_ref, None), warnings, errors) } } diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index d79acc2a899..cfe2335bc90 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -4,7 +4,7 @@ use crate::{ engine_threading::*, }; -use std::{collections::HashSet, fmt}; +use std::{collections::BTreeSet, fmt}; /// A identifier to uniquely refer to our type terms #[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] @@ -27,52 +27,31 @@ impl CollectTypesMetadata for TypeId { &self, ctx: &mut CollectTypesMetadataContext, ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + fn filter_fn(type_info: &TypeInfo) -> bool { + matches!(type_info, TypeInfo::UnknownGeneric { .. }) + || matches!(type_info, TypeInfo::Placeholder(_)) + } + let engines = Engines::new(ctx.type_engine, ctx.decl_engine); + let possible = self.extract_any_including_self(engines, &filter_fn); let mut res = vec![]; - match ctx.type_engine.get(*self) { - TypeInfo::UnknownGeneric { - name, - trait_constraints, - } => { - res.push(TypeMetadata::UnresolvedType(name, ctx.call_site_get(self))); - for trait_constraint in trait_constraints.iter() { - res.extend(check!( - trait_constraint.collect_types_metadata(ctx), - continue, - warnings, - errors + for type_id in possible.into_iter() { + match ctx.type_engine.get(type_id) { + TypeInfo::UnknownGeneric { name, .. } => { + res.push(TypeMetadata::UnresolvedType( + name, + ctx.call_site_get(&type_id), )); } - } - TypeInfo::Placeholder(type_param) => { - res.push(TypeMetadata::UnresolvedType( - type_param.name_ident, - ctx.call_site_get(self), - )); - } - _ => {} - } - if let TypeInfo::UnknownGeneric { - name, - trait_constraints, - } = ctx.type_engine.get(*self) - { - res.push(TypeMetadata::UnresolvedType(name, ctx.call_site_get(self))); - for trait_constraint in trait_constraints.iter() { - res.extend(check!( - trait_constraint.collect_types_metadata(ctx), - continue, - warnings, - errors - )); + TypeInfo::Placeholder(type_param) => { + res.push(TypeMetadata::UnresolvedType( + type_param.name_ident, + ctx.call_site_get(self), + )); + } + _ => {} } } - if errors.is_empty() { - ok(res, warnings, errors) - } else { - err(warnings, errors) - } + ok(res, vec![], vec![]) } } @@ -241,8 +220,11 @@ impl ReplaceSelfType for TypeId { impl SubstTypes for TypeId { fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) { + let type_engine = engines.te(); if let Some(matching_id) = type_mapping.find_match(*self, engines) { - *self = matching_id; + if !matches!(type_engine.get(matching_id), TypeInfo::ErrorRecovery) { + *self = matching_id; + } } } } @@ -254,10 +236,7 @@ impl UnconstrainedTypeParameters for TypeId { type_parameter: &TypeParameter, ) -> bool { let type_engine = engines.te(); - let decl_engine = engines.de(); - let mut all_types: HashSet = type_engine - .get(*self) - .extract_inner_types(type_engine, decl_engine); + let mut all_types: BTreeSet = type_engine.get(*self).extract_inner_types(engines); all_types.insert(*self); let type_parameter_info = type_engine.get(type_parameter.type_id); all_types @@ -317,4 +296,21 @@ impl TypeId { _ => false, } } + + pub(crate) fn extract_any_including_self( + &self, + engines: Engines<'_>, + filter_fn: &F, + ) -> BTreeSet + where + F: Fn(&TypeInfo) -> bool, + { + let type_engine = engines.te(); + let type_info = type_engine.get(*self); + let mut found: BTreeSet = type_info.extract_any(engines, filter_fn); + if filter_fn(&type_info) { + found.insert(*self); + } + found + } } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 9e6cea88cda..4c31aa8815d 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -10,7 +10,7 @@ use sway_types::{integer_bits::IntegerBits, span::Span, Spanned}; use std::{ cmp::Ordering, - collections::HashSet, + collections::{BTreeSet, HashSet}, fmt, hash::{Hash, Hasher}, }; @@ -896,178 +896,11 @@ impl TypeInfo { /// Given a `TypeInfo` `self`, analyze `self` and return all inner /// `TypeId`'s of `self`, not including `self`. - pub(crate) fn extract_inner_types( - &self, - type_engine: &TypeEngine, - decl_engine: &DeclEngine, - ) -> HashSet { - let helper = |type_id: TypeId| { - let mut inner_types = HashSet::new(); - match type_engine.get(type_id) { - TypeInfo::Enum(decl_ref) => { - let decl = decl_engine.get_enum(&decl_ref); - inner_types.insert(type_id); - for type_param in decl.type_parameters.iter() { - inner_types.extend( - type_engine - .get(type_param.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - for variant in decl.variants.iter() { - inner_types.extend( - type_engine - .get(variant.type_argument.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - } - TypeInfo::Struct(decl_ref) => { - let decl = decl_engine.get_struct(&decl_ref); - inner_types.insert(type_id); - for type_param in decl.type_parameters.iter() { - inner_types.extend( - type_engine - .get(type_param.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - for field in decl.fields.iter() { - inner_types.extend( - type_engine - .get(field.type_argument.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - } - TypeInfo::Custom { type_arguments, .. } => { - inner_types.insert(type_id); - if let Some(type_arguments) = type_arguments { - for type_arg in type_arguments.iter() { - inner_types.extend( - type_engine - .get(type_arg.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - } - } - TypeInfo::Array(elem_ty, _) => { - inner_types.insert(elem_ty.type_id); - inner_types.extend( - type_engine - .get(type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - TypeInfo::Tuple(elems) => { - inner_types.insert(type_id); - for elem in elems.iter() { - inner_types.extend( - type_engine - .get(elem.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - } - TypeInfo::Storage { fields } => { - inner_types.insert(type_id); - for field in fields.iter() { - inner_types.extend( - type_engine - .get(field.type_argument.type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - } - TypeInfo::Alias { ty, .. } => { - inner_types.insert(ty.type_id); - inner_types.extend( - type_engine - .get(type_id) - .extract_inner_types(type_engine, decl_engine), - ); - } - TypeInfo::Unknown - | TypeInfo::UnknownGeneric { .. } - | TypeInfo::Str(_) - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Boolean - | TypeInfo::ContractCaller { .. } - | TypeInfo::SelfType - | TypeInfo::B256 - | TypeInfo::Numeric - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::Contract - | TypeInfo::Placeholder(_) => { - inner_types.insert(type_id); - } - TypeInfo::TypeParam(_) | TypeInfo::ErrorRecovery => {} - } - inner_types - }; - - let mut inner_types = HashSet::new(); - match self { - TypeInfo::Enum(decl_ref) => { - let decl = decl_engine.get_enum(decl_ref); - for type_param in decl.type_parameters.iter() { - inner_types.extend(helper(type_param.type_id)); - } - for variant in decl.variants.iter() { - inner_types.extend(helper(variant.type_argument.type_id)); - } - } - TypeInfo::Struct(decl_ref) => { - let decl = decl_engine.get_struct(decl_ref); - for type_param in decl.type_parameters.iter() { - inner_types.extend(helper(type_param.type_id)); - } - for field in decl.fields.iter() { - inner_types.extend(helper(field.type_argument.type_id)); - } - } - TypeInfo::Custom { type_arguments, .. } => { - if let Some(type_arguments) = type_arguments { - for type_arg in type_arguments.iter() { - inner_types.extend(helper(type_arg.type_id)); - } - } - } - TypeInfo::Array(elem_ty, _) => { - inner_types.extend(helper(elem_ty.type_id)); - } - TypeInfo::Tuple(elems) => { - for elem in elems.iter() { - inner_types.extend(helper(elem.type_id)); - } - } - TypeInfo::Storage { fields } => { - for field in fields.iter() { - inner_types.extend(helper(field.type_argument.type_id)); - } - } - TypeInfo::Alias { ty, .. } => { - inner_types.extend(helper(ty.type_id)); - } - TypeInfo::Unknown - | TypeInfo::UnknownGeneric { .. } - | TypeInfo::Str(_) - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Boolean - | TypeInfo::ContractCaller { .. } - | TypeInfo::SelfType - | TypeInfo::B256 - | TypeInfo::Numeric - | TypeInfo::Contract - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::ErrorRecovery - | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) => {} + pub(crate) fn extract_inner_types(&self, engines: Engines<'_>) -> BTreeSet { + fn filter_fn(_type_info: &TypeInfo) -> bool { + true } - inner_types + self.extract_any(engines, &filter_fn) } /// Given a `TypeInfo` `self`, check to see if `self` is currently @@ -1155,180 +988,149 @@ impl TypeInfo { /// Given a `TypeInfo` `self`, analyze `self` and return all nested /// `TypeInfo`'s found in `self`, including `self`. - pub(crate) fn extract_nested_types( - self, - engines: Engines<'_>, - span: &Span, - ) -> CompileResult> { + pub(crate) fn extract_nested_types(self, engines: Engines<'_>) -> Vec { let type_engine = engines.te(); - let decl_engine = engines.de(); + let mut inner_types: Vec = self + .extract_inner_types(engines) + .into_iter() + .map(|type_id| type_engine.get(type_id)) + .collect(); + inner_types.push(self); + inner_types + } - let mut warnings = vec![]; - let mut errors = vec![]; - let mut all_nested_types = vec![self.clone()]; + pub(crate) fn extract_any(&self, engines: Engines<'_>, filter_fn: &F) -> BTreeSet + where + F: Fn(&TypeInfo) -> bool, + { + let decl_engine = engines.de(); + let mut found: BTreeSet = BTreeSet::new(); match self { - TypeInfo::Enum(decl_ref) => { - let decl = decl_engine.get_enum(&decl_ref); - for type_parameter in decl.type_parameters.iter() { - let mut nested_types = check!( - type_engine - .get(type_parameter.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + TypeInfo::Unknown + | TypeInfo::Placeholder(_) + | TypeInfo::TypeParam(_) + | TypeInfo::Str(_) + | TypeInfo::UnsignedInteger(_) + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Boolean + | TypeInfo::SelfType + | TypeInfo::B256 + | TypeInfo::Numeric + | TypeInfo::Contract + | TypeInfo::ErrorRecovery => {} + TypeInfo::Enum(enum_ref) => { + let enum_decl = decl_engine.get_enum(enum_ref); + for type_param in enum_decl.type_parameters.iter() { + found.extend( + type_param + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } - for variant_type in decl.variants.iter() { - let mut nested_types = check!( - type_engine - .get(variant_type.type_argument.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + for variant in enum_decl.variants.iter() { + found.extend( + variant + .type_argument + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } } - TypeInfo::Struct(decl_ref) => { - let decl = decl_engine.get_struct(&decl_ref); - for type_parameter in decl.type_parameters.iter() { - let mut nested_types = check!( - type_engine - .get(type_parameter.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + TypeInfo::Struct(struct_ref) => { + let struct_decl = decl_engine.get_struct(struct_ref); + for type_param in struct_decl.type_parameters.iter() { + found.extend( + type_param + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } - for field in decl.fields.iter() { - let mut nested_types = check!( - type_engine - .get(field.type_argument.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + for field in struct_decl.fields.iter() { + found.extend( + field + .type_argument + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } } - TypeInfo::Tuple(type_arguments) => { - for type_argument in type_arguments.iter() { - let mut nested_types = check!( - type_engine - .get(type_argument.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + TypeInfo::Tuple(elems) => { + for elem in elems.iter() { + found.extend(elem.type_id.extract_any_including_self(engines, filter_fn)); + } + } + TypeInfo::ContractCaller { + abi_name: _, + address, + } => { + if let Some(address) = address { + found.extend( + address + .return_type + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } } - TypeInfo::Array(elem_ty, _) => { - let mut nested_types = check!( - type_engine - .get(elem_ty.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors - ); - all_nested_types.append(&mut nested_types); + TypeInfo::Custom { + call_path: _, + type_arguments, + } => { + if let Some(type_arguments) = type_arguments { + for type_arg in type_arguments.iter() { + found.extend( + type_arg + .type_id + .extract_any_including_self(engines, filter_fn), + ); + } + } + } + TypeInfo::Array(ty, _) => { + found.extend(ty.type_id.extract_any_including_self(engines, filter_fn)); } TypeInfo::Storage { fields } => { for field in fields.iter() { - let mut nested_types = check!( - type_engine - .get(field.type_argument.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + found.extend( + field + .type_argument + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } } + TypeInfo::Alias { name: _, ty } => { + found.extend(ty.type_id.extract_any_including_self(engines, filter_fn)); + } TypeInfo::UnknownGeneric { - trait_constraints, .. + name: _, + trait_constraints, } => { for trait_constraint in trait_constraints.iter() { for type_arg in trait_constraint.type_arguments.iter() { - let mut nested_types = check!( - type_engine - .get(type_arg.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors + found.extend( + type_arg + .type_id + .extract_any_including_self(engines, filter_fn), ); - all_nested_types.append(&mut nested_types); } } } - TypeInfo::Alias { ty, .. } => { - let mut nested_types = check!( - type_engine - .get(ty.type_id) - .extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors - ); - all_nested_types.append(&mut nested_types); - } - TypeInfo::Unknown - | TypeInfo::Str(_) - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Boolean - | TypeInfo::ContractCaller { .. } - | TypeInfo::B256 - | TypeInfo::Numeric - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::Contract - | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) => {} - TypeInfo::Custom { .. } | TypeInfo::SelfType => { - errors.push(CompileError::Internal( - "did not expect to find this type here", - span.clone(), - )); - return err(warnings, errors); - } - TypeInfo::ErrorRecovery => { - // return an error but don't create a new error message - return err(warnings, errors); - } } - ok(all_nested_types, warnings, errors) + found } pub(crate) fn extract_nested_generics<'a>( &self, engines: Engines<'a>, - span: &Span, - ) -> CompileResult>> { - let mut warnings = vec![]; - let mut errors = vec![]; - let nested_types = check!( - self.clone().extract_nested_types(engines, span), - return err(warnings, errors), - warnings, - errors - ); - let generics = HashSet::from_iter( + ) -> HashSet> { + let nested_types = self.clone().extract_nested_types(engines); + HashSet::from_iter( nested_types .into_iter() .filter(|x| matches!(x, TypeInfo::UnknownGeneric { .. })) .map(|thing| WithEngines::new(thing, engines)), - ); - ok(generics, warnings, errors) + ) } /// Given two `TypeInfo`'s `self` and `other`, check to see if `self` is diff --git a/sway-core/src/type_system/occurs_check.rs b/sway-core/src/type_system/occurs_check.rs index b8d1ed1d634..835d0b41c3c 100644 --- a/sway-core/src/type_system/occurs_check.rs +++ b/sway-core/src/type_system/occurs_check.rs @@ -1,7 +1,5 @@ use crate::{engine_threading::*, type_system::*}; -use sway_types::Span; - /// Helper struct to perform the occurs check. /// /// --- @@ -32,22 +30,8 @@ impl<'a> OccursCheck<'a> { /// NOTE: This implementation assumes that `other` =/ `generic`, in which /// case the occurs check would return `false`, as this is a valid /// unification. - pub(super) fn check( - &self, - generic: TypeInfo, - other: &TypeInfo, - span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - - let other_generics = check!( - other.extract_nested_generics(self.engines, span), - return err(warnings, errors), - warnings, - errors - ); - let occurs = other_generics.contains(&self.engines.help_out(generic)); - ok(occurs, warnings, errors) + pub(super) fn check(&self, generic: TypeInfo, other: &TypeInfo) -> bool { + let other_generics = other.extract_nested_generics(self.engines); + other_generics.contains(&self.engines.help_out(generic)) } } diff --git a/sway-core/src/type_system/unify.rs b/sway-core/src/type_system/unify.rs index 6b132ff8db3..54be2cc7122 100644 --- a/sway-core/src/type_system/unify.rs +++ b/sway-core/src/type_system/unify.rs @@ -246,10 +246,10 @@ impl<'a> Unifier<'a> { trait_constraints: etc, }, ) if rn.as_str() == en.as_str() && rtc.eq(&etc, self.engines) => (vec![], vec![]), - (r @ UnknownGeneric { .. }, e) if !self.occurs_check(r.clone(), &e, span) => { + (r @ UnknownGeneric { .. }, e) if !self.occurs_check(r.clone(), &e) => { self.replace_received_with_expected(received, expected, &r, e, span) } - (r, e @ UnknownGeneric { .. }) if !self.occurs_check(e.clone(), &r, span) => { + (r, e @ UnknownGeneric { .. }) if !self.occurs_check(e.clone(), &r) => { self.replace_expected_with_received(received, expected, r, &e, span) } @@ -269,11 +269,8 @@ impl<'a> Unifier<'a> { } } - fn occurs_check(&self, generic: TypeInfo, other: &TypeInfo, span: &Span) -> bool { - OccursCheck::new(self.engines) - .check(generic, other, span) - .value - .unwrap_or(true) + fn occurs_check(&self, generic: TypeInfo, other: &TypeInfo) -> bool { + OccursCheck::new(self.engines).check(generic, other) } fn unify_strs(