diff --git a/Cargo.lock b/Cargo.lock index 77dac587f1a..8e12a491723 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6173,6 +6173,7 @@ dependencies = [ "num-bigint", "num-traits", "serde", + "sway-utils", "thiserror", ] diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index 4e51e4bcd13..0797f99ac8b 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -1,9 +1,7 @@ +use crate::{decl_engine::*, engine_threading::*, type_system::*}; use std::{fmt, sync::RwLock}; - use sway_types::{Named, Spanned}; -use crate::{decl_engine::*, engine_threading::*, type_system::*}; - #[derive(Debug)] pub(crate) struct ConcurrentSlab { inner: RwLock>, @@ -70,16 +68,21 @@ where let inner = self.inner.read().unwrap(); inner[index].clone() } + + pub fn retain(&self, predicate: impl Fn(&T) -> bool) { + let mut inner = self.inner.write().unwrap(); + inner.retain(predicate); + } } -impl ConcurrentSlab { +impl ConcurrentSlab { pub fn replace( &self, index: TypeId, - prev_value: &TypeInfo, - new_value: TypeInfo, + prev_value: &TypeSourceInfo, + new_value: TypeSourceInfo, engines: &Engines, - ) -> Option { + ) -> Option { let index = index.index(); // The comparison below ends up calling functions in the slab, which // can lead to deadlocks if we used a single read/write lock. @@ -89,7 +92,10 @@ impl ConcurrentSlab { { let inner = self.inner.read().unwrap(); let actual_prev_value = &inner[index]; - if !actual_prev_value.eq(prev_value, engines) { + if !actual_prev_value + .type_info + .eq(&prev_value.type_info, engines) + { return Some(actual_prev_value.clone()); } } diff --git a/sway-core/src/decl_engine/engine.rs b/sway-core/src/decl_engine/engine.rs index 1d726f80abf..da1ca670e95 100644 --- a/sway-core/src/decl_engine/engine.rs +++ b/sway-core/src/decl_engine/engine.rs @@ -4,7 +4,7 @@ use std::{ sync::RwLock, }; -use sway_types::{Named, Spanned}; +use sway_types::{ModuleId, Named, Spanned}; use crate::{ concurrent_slab::{ConcurrentSlab, ListDisplay}, @@ -147,6 +147,35 @@ decl_engine_index!(constant_slab, ty::TyConstantDecl); decl_engine_index!(enum_slab, ty::TyEnumDecl); decl_engine_index!(type_alias_slab, ty::TyTypeAliasDecl); +macro_rules! decl_engine_clear_module { + ($($slab:ident, $decl:ty);* $(;)?) => { + impl DeclEngine { + pub fn clear_module(&mut self, module_id: &ModuleId) { + $( + self.$slab.retain(|ty| match ty.span().source_id() { + Some(source_id) => &source_id.module_id() != module_id, + None => false, + }); + )* + } + } + }; +} + +decl_engine_clear_module!( + function_slab, ty::TyFunctionDecl; + trait_slab, ty::TyTraitDecl; + trait_fn_slab, ty::TyTraitFn; + trait_type_slab, ty::TyTraitType; + impl_trait_slab, ty::TyImplTrait; + struct_slab, ty::TyStructDecl; + storage_slab, ty::TyStorageDecl; + abi_slab, ty::TyAbiDecl; + constant_slab, ty::TyConstantDecl; + enum_slab, ty::TyEnumDecl; + type_alias_slab, ty::TyTypeAliasDecl; +); + impl DeclEngine { /// Given a [DeclRef] `index`, finds all the parents of `index` and all the /// recursive parents of those parents, and so on. Does not perform diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index d080abe9a53..a68158923aa 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -1,13 +1,11 @@ +use crate::{decl_engine::DeclEngine, query_engine::QueryEngine, type_system::TypeEngine}; use std::{ cmp::Ordering, fmt, hash::{BuildHasher, Hash, Hasher}, }; - use sway_types::SourceEngine; -use crate::{decl_engine::DeclEngine, query_engine::QueryEngine, type_system::TypeEngine}; - #[derive(Debug, Default)] pub struct Engines { type_engine: TypeEngine, @@ -47,6 +45,13 @@ impl Engines { &self.source_engine } + /// Removes all data associated with `module_id` from the declaration and type engines. + /// It is intended to be used during garbage collection to remove any data that is no longer needed. + pub fn clear_module(&mut self, module_id: &sway_types::ModuleId) { + self.type_engine.clear_module(module_id); + self.decl_engine.clear_module(module_id); + } + /// Helps out some `thing: T` by adding `self` as context. pub fn help_out(&self, thing: T) -> WithEngines<'_, T> { WithEngines { diff --git a/sway-core/src/language/ty/declaration/abi.rs b/sway-core/src/language/ty/declaration/abi.rs index 4a571883d41..91840b50130 100644 --- a/sway-core/src/language/ty/declaration/abi.rs +++ b/sway-core/src/language/ty/declaration/abi.rs @@ -72,7 +72,7 @@ impl CreateTypeId for TyAbiDecl { abi_name: AbiName::Known(self.name.clone().into()), address: None, }; - type_engine.insert(engines, ty) + type_engine.insert(engines, ty, self.name.span().source_id()) } } diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 8c59763e86d..cb90302cf91 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -784,6 +784,7 @@ impl TyDecl { }) => type_engine.insert( engines, TypeInfo::Struct(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), + name.span().source_id(), ), TyDecl::EnumDecl(EnumDecl { name, @@ -793,6 +794,7 @@ impl TyDecl { }) => type_engine.insert( engines, TypeInfo::Enum(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), + name.span().source_id(), ), TyDecl::StorageDecl(StorageDecl { decl_id, .. }) => { let storage_decl = decl_engine.get_storage(decl_id); @@ -801,6 +803,7 @@ impl TyDecl { TypeInfo::Storage { fields: storage_decl.fields_as_typed_struct_fields(), }, + storage_decl.span().source_id(), ) } TyDecl::TypeAliasDecl(TypeAliasDecl { decl_id, .. }) => { diff --git a/sway-core/src/language/ty/declaration/type_alias.rs b/sway-core/src/language/ty/declaration/type_alias.rs index ee4b4e69006..99d7a6782e5 100644 --- a/sway-core/src/language/ty/declaration/type_alias.rs +++ b/sway-core/src/language/ty/declaration/type_alias.rs @@ -67,6 +67,7 @@ impl CreateTypeId for TyTypeAliasDecl { name: self.name.clone(), ty: self.ty.clone(), }, + self.name.span().source_id(), ) } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 27d9ca7d4fd..7f83f8aae8c 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -414,7 +414,7 @@ impl TyExpression { let type_engine = engines.te(); TyExpression { expression: TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err)), + return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None), span, } } diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index bd39669df97..e3a2e5f8381 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -100,14 +100,15 @@ impl ty::TyCodeBlock { return ctx.engines().te().insert( engines, TypeInfo::Enum(DeclRef::new(name.clone(), decl_id, decl_span.clone())), + name.span().source_id(), ); } - ctx.engines.te().insert(engines, TypeInfo::Unknown) + ctx.engines.te().insert(engines, TypeInfo::Unknown, None) } else { ctx.engines .te() - .insert(engines, TypeInfo::Tuple(Vec::new())) + .insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) } }); (block_type, span) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs index f10d7ec4526..a2b288fa232 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -41,7 +41,7 @@ impl ty::TyConstantDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); // this subst is required to replace associated types, namely TypeInfo::TraitType. type_ascription.type_id.subst(&ctx.type_subst(), engines); @@ -121,7 +121,7 @@ impl ty::TyConstantDecl { call_path, span, attributes: Default::default(), - return_type: type_engine.insert(engines, TypeInfo::Unknown), + return_type: type_engine.insert(engines, TypeInfo::Unknown, None), type_ascription, is_configurable: false, value: None, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index 24c8c68cbb1..51ebbf4bc2f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -42,7 +42,7 @@ impl TyDecl { None, ) .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) }); let mut ctx = ctx .with_type_annotation(type_ascription.type_id) @@ -106,7 +106,7 @@ impl TyDecl { parsed::Declaration::FunctionDeclaration(fn_decl) => { let span = fn_decl.span.clone(); let mut ctx = - ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let fn_decl = match ty::TyFunctionDecl::type_check( handler, ctx.by_ref(), @@ -350,7 +350,7 @@ impl TyDecl { let new_ty = ctx .resolve_type(handler, ty.type_id, &span, EnforceTypeArguments::Yes, None) .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) }); // create the type alias decl using the resolved type above diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 5689c31ed73..843a6e5d805 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -1,10 +1,9 @@ -use sway_error::handler::{ErrorEmitted, Handler}; - use crate::{ language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, }; +use sway_error::handler::{ErrorEmitted, Handler}; impl ty::TyEnumDecl { pub fn type_check( @@ -74,7 +73,7 @@ impl ty::TyEnumVariant { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); Ok(ty::TyEnumVariant { name: variant.name.clone(), type_argument, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index d06ac1c14b0..d9b8d8109bf 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -115,7 +115,7 @@ impl ty::TyFunctionDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let (visibility, is_contract_call) = if is_method { if is_in_impl_self { @@ -345,6 +345,7 @@ fn test_function_selector_behavior() { .insert( &engines, TypeInfo::StringArray(Length::new(5, Span::dummy())), + None, ) .into(), }, @@ -354,12 +355,15 @@ fn test_function_selector_behavior() { is_mutable: false, mutability_span: Span::dummy(), type_argument: TypeArgument { - type_id: engines - .te() - .insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo)), + type_id: engines.te().insert( + &engines, + TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), + None, + ), initial_type_id: engines.te().insert( &engines, TypeInfo::StringArray(Length::new(5, Span::dummy())), + None, ), span: Span::dummy(), call_path_tree: None, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs index 833d067a755..b18850ba3f4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs @@ -35,7 +35,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); type_argument.type_id.check_type_parameter_bounds( handler, @@ -89,7 +89,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let typed_parameter = ty::TyFunctionParameter { name, 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 5a26b4539cc..ab4de79a118 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 @@ -115,7 +115,7 @@ impl TyImplTrait { // Update the context let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_self_type(Some(implementing_for.type_id)); let impl_trait = match ctx @@ -362,7 +362,7 @@ impl TyImplTrait { let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); // type check the items inside of the impl block let mut new_items = vec![]; @@ -778,14 +778,23 @@ fn type_check_trait_implementation( name: Ident::new_with_override("Self".into(), Span::dummy()), trait_constraints: VecSet(vec![]), }, + None, ), }; trait_type_mapping.extend(TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert(engines, old_type_decl_info1)], + vec![type_engine.insert( + engines, + old_type_decl_info1, + type_decl.name.span().source_id(), + )], vec![type_decl.ty.clone().unwrap().type_id], )); trait_type_mapping.extend(TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert(engines, old_type_decl_info2)], + vec![type_engine.insert( + engines, + old_type_decl_info2, + type_decl.name.span().source_id(), + )], vec![type_decl.ty.clone().unwrap().type_id], )); } @@ -965,7 +974,7 @@ fn type_check_impl_method( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let interface_name = || -> InterfaceName { if is_contract { @@ -1188,7 +1197,7 @@ fn type_check_const_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let interface_name = || -> InterfaceName { if is_contract { @@ -1270,7 +1279,7 @@ fn type_check_type_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let interface_name = || -> InterfaceName { if is_contract { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 83afaa00298..587295806b2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -1,10 +1,9 @@ -use sway_error::handler::{ErrorEmitted, Handler}; - use crate::{ language::{parsed::*, ty, CallPath}, semantic_analysis::{type_check_context::EnforceTypeArguments, *}, type_system::*, }; +use sway_error::handler::{ErrorEmitted, Handler}; impl ty::TyStructDecl { pub(crate) fn type_check( @@ -70,7 +69,9 @@ impl ty::TyStructField { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| { + type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) + }); let field = ty::TyStructField { name: field.name, span: field.span, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index af8c6188068..bd40e9dfcf2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -60,7 +60,7 @@ impl ty::TyTraitFn { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let trait_fn = ty::TyTraitFn { name, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs index 399f7df0b87..103c721321e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs @@ -42,7 +42,9 @@ impl ty::TyTraitType { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| { + type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) + }); Some(ty) } else { None @@ -74,9 +76,11 @@ impl ty::TyTraitType { name, attributes, ty: ty_opt, - implementing_type: engines - .te() - .insert(engines, TypeInfo::new_self_type(Span::dummy())), + implementing_type: engines.te().insert( + engines, + TypeInfo::new_self_type(Span::dummy()), + None, + ), span, } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index d7fbe90b8cc..7ee79ccc77e 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -109,7 +109,7 @@ fn type_check_not( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown); + let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); let mut ctx = ctx.with_help_text("").with_type_annotation(return_type); @@ -161,16 +161,19 @@ fn type_check_size_of_val( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![exp], type_arguments: vec![], - span, + span: span.clone(), }; - let return_type = - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + span.source_id(), + ); Ok((intrinsic_function, return_type)) } @@ -207,7 +210,7 @@ fn type_check_size_of_type( .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -216,7 +219,7 @@ fn type_check_size_of_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -228,8 +231,11 @@ fn type_check_size_of_type( }], span, }; - let return_type = - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + ); Ok((intrinsic_function, return_type)) } @@ -259,7 +265,7 @@ fn type_check_is_reference_type( .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -268,7 +274,7 @@ fn type_check_is_reference_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -282,7 +288,7 @@ fn type_check_is_reference_type( }; Ok(( intrinsic_function, - type_engine.insert(engines, TypeInfo::Boolean), + type_engine.insert(engines, TypeInfo::Boolean, None), )) } @@ -312,7 +318,7 @@ fn type_check_assert_is_str_array( .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -321,7 +327,7 @@ fn type_check_assert_is_str_array( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -335,7 +341,7 @@ fn type_check_assert_is_str_array( }; Ok(( intrinsic_function, - type_engine.insert(engines, TypeInfo::Tuple(vec![])), + type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), )) } @@ -366,9 +372,11 @@ fn type_check_to_str_array( let span = arg.span.clone(); - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::Unknown, + None, + )); let new_type = ty::TyExpression::type_check(handler, ctx.by_ref(), arg)?; Ok(( @@ -378,7 +386,7 @@ fn type_check_to_str_array( type_arguments: vec![], span, }, - type_engine.insert(engines, t), + type_engine.insert(engines, t, None), )) } _ => Err(handler.emit_err(CompileError::ExpectedStringLiteral { span: arg.span })), @@ -413,9 +421,9 @@ fn type_check_cmp( span, })); } - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = + ctx.by_ref() + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let lhs = arguments[0].clone(); let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -450,7 +458,7 @@ fn type_check_cmp( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Boolean), + type_engine.insert(engines, TypeInfo::Boolean, None), )) } @@ -488,15 +496,19 @@ fn type_check_gtf( } // Type check the first argument which is the index - let mut ctx = ctx.by_ref().with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let index = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; // Type check the second argument which is the tx field ID - let mut ctx = ctx.by_ref().with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let tx_field_id = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; let targ = type_arguments[0].clone(); @@ -504,7 +516,7 @@ fn type_check_gtf( .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -513,7 +525,7 @@ fn type_check_gtf( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); Ok(( ty::TyIntrinsicFunctionKind { @@ -553,7 +565,7 @@ fn type_check_addr_of( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let copy_type_info = type_engine .to_typeinfo(exp.return_type, &span) @@ -573,7 +585,7 @@ fn type_check_addr_of( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::RawUntypedPtr); + let return_type = type_engine.insert(engines, TypeInfo::RawUntypedPtr, None); Ok((intrinsic_function, return_type)) } @@ -602,7 +614,7 @@ fn type_check_state_clear( // `key` argument let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -617,9 +629,11 @@ fn type_check_state_clear( } // `slots` argument - let mut ctx = ctx.with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; @@ -630,7 +644,7 @@ fn type_check_state_clear( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean); + let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); Ok((intrinsic_function, return_type)) } @@ -656,7 +670,7 @@ fn type_check_state_load_word( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let key_ty = type_engine .to_typeinfo(exp.return_type, &span) @@ -675,8 +689,11 @@ fn type_check_state_load_word( type_arguments: vec![], span, }; - let return_type = - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + ); Ok((intrinsic_function, return_type)) } @@ -711,7 +728,7 @@ fn type_check_state_store_word( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -724,18 +741,21 @@ fn type_check_state_store_word( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; - let ctx = ctx.with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let ctx = ctx.with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let type_argument = type_arguments.get(0).map(|targ| { - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = + ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -744,7 +764,7 @@ fn type_check_state_store_word( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); TypeArgument { type_id, initial_type_id, @@ -758,7 +778,7 @@ fn type_check_state_store_word( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean); + let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); Ok((intrinsic_function, return_type)) } @@ -800,7 +820,7 @@ fn type_check_state_quad( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -813,20 +833,23 @@ fn type_check_state_quad( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; - let mut ctx = ctx.with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[2].clone())?; let type_argument = type_arguments.get(0).map(|targ| { - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = + ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -835,7 +858,7 @@ fn type_check_state_quad( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); TypeArgument { type_id, initial_type_id, @@ -849,7 +872,7 @@ fn type_check_state_quad( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean); + let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); Ok((intrinsic_function, return_type)) } @@ -876,7 +899,7 @@ fn type_check_log( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -884,7 +907,7 @@ fn type_check_log( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Tuple(vec![])); + let return_type = type_engine.insert(engines, TypeInfo::Tuple(vec![]), None); Ok((intrinsic_function, return_type)) } @@ -941,7 +964,7 @@ fn type_check_arith_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Numeric); + let return_type = type_engine.insert(engines, TypeInfo::Numeric, None); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -989,7 +1012,7 @@ fn type_check_bitwise_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown); + let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -1054,7 +1077,7 @@ fn type_check_shift_binary_op( })); } - let return_type = engines.te().insert(engines, TypeInfo::Unknown); + let return_type = engines.te().insert(engines, TypeInfo::Unknown, None); let lhs = arguments[0].clone(); let lhs = ty::TyExpression::type_check( handler, @@ -1069,7 +1092,7 @@ fn type_check_shift_binary_op( handler, ctx.by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric)), + .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric, None)), rhs, )?; @@ -1126,9 +1149,11 @@ fn type_check_revert( } // Type check the argument which is the revert code - let mut ctx = ctx.by_ref().with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let revert_code = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; Ok(( @@ -1138,8 +1163,8 @@ fn type_check_revert( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Unknown), // TODO: change this to the `Never` type when - // available + type_engine.insert(engines, TypeInfo::Unknown, None), // TODO: change this to the `Never` type when + // available )) } @@ -1180,7 +1205,7 @@ fn type_check_ptr_ops( .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -1189,11 +1214,11 @@ fn type_check_ptr_ops( EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let mut ctx = + ctx.by_ref() + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let lhs = arguments[0].clone(); let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -1215,15 +1240,17 @@ fn type_check_ptr_ops( let ctx = ctx .by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + .with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; Ok(( ty::TyIntrinsicFunctionKind { kind, - arguments: vec![lhs, rhs], + arguments: vec![lhs.clone(), rhs], type_arguments: vec![TypeArgument { type_id, initial_type_id, @@ -1232,7 +1259,7 @@ fn type_check_ptr_ops( }], span, }, - type_engine.insert(engines, lhs_ty), + type_engine.insert(engines, lhs_ty, lhs.span.source_id()), )) } @@ -1272,12 +1299,12 @@ fn type_check_smo( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) .unwrap_or_else(TypeInfo::ErrorRecovery); - let initial_type_id = type_engine.insert(engines, initial_type_info); + let initial_type_id = type_engine.insert(engines, initial_type_info, targ.span.source_id()); let type_id = ctx .resolve_type( handler, @@ -1286,7 +1313,7 @@ fn type_check_smo( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); TypeArgument { type_id, initial_type_id, @@ -1296,9 +1323,9 @@ fn type_check_smo( }); // Type check the first argument which is the recipient address, so it has to be a `b256`. - let mut ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256)); + let mut ctx = + ctx.by_ref() + .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); let recipient = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; // Type check the second argument which is the data, which can be anything. If a type @@ -1306,21 +1333,25 @@ fn type_check_smo( let mut ctx = ctx.by_ref().with_type_annotation( type_argument .clone() - .map_or(type_engine.insert(engines, TypeInfo::Unknown), |ta| { + .map_or(type_engine.insert(engines, TypeInfo::Unknown, None), |ta| { ta.type_id }), ); let data = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; // Type check the third argument which is the output index, so it has to be a `u64`. - let mut ctx = ctx.by_ref().with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); // Type check the fourth argument which is the amount of coins to send, so it has to be a `u64`. - let mut ctx = ctx.by_ref().with_type_annotation( - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - ); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + )); let coins = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[2].clone())?; Ok(( @@ -1330,6 +1361,6 @@ fn type_check_smo( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }, - type_engine.insert(engines, TypeInfo::Tuple(vec![])), + type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), )) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs index 81f4bc23d05..b5468d91e8c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs @@ -23,10 +23,13 @@ pub(super) struct Instantiate { impl Instantiate { pub(super) fn new(engines: &Engines, span: Span) -> Self { let type_engine = engines.te(); - let u64_type = - type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); - let boolean_type = type_engine.insert(engines, TypeInfo::Boolean); - let revert_type = type_engine.insert(engines, TypeInfo::Unknown); // TODO: Change this to the `Never` type once available. + let u64_type = type_engine.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, + ); + let boolean_type = type_engine.insert(engines, TypeInfo::Boolean, None); + let revert_type = type_engine.insert(engines, TypeInfo::Unknown, None); // TODO: Change this to the `Never` type once available. Self { span, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index 9e68114a10e..ad128430a33 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -494,6 +494,7 @@ fn match_enum( return_type: type_engine.insert( ctx.engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, ), span: exp.span.clone(), }, @@ -502,6 +503,7 @@ fn match_enum( return_type: type_engine.insert( ctx.engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + None, ), span: exp.span.clone(), }, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index d6c22f9f49d..51521d76283 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -105,9 +105,11 @@ impl ty::TyMatchBranch { // type check the branch result let typed_result = { - let ctx = branch_ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + let ctx = branch_ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::Unknown, + None, + )); ty::TyExpression::type_check(handler, ctx, result)? }; @@ -594,7 +596,11 @@ fn instantiate_branch_condition_result_var_declarations_and_matched_or_variant_i call_path_tree: None, }) .collect(); - let tuple_type = type_engine.insert(ctx.engines, TypeInfo::Tuple(tuple_field_types)); + let tuple_type = type_engine.insert( + ctx.engines, + TypeInfo::Tuple(tuple_field_types), + instantiate.dummy_span().source_id(), + ); let variable_names = carry_over_vars[0] .iter() .map(|(ident, _)| ident.clone()) diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index 955de894518..bc8f80203cf 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -28,7 +28,7 @@ impl TyScrutinee { let engines = ctx.engines(); match scrutinee { Scrutinee::Or { elems, span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown); + let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); let mut typed_elems = Vec::with_capacity(elems.len()); for scrutinee in elems { @@ -46,7 +46,7 @@ impl TyScrutinee { Ok(typed_scrutinee) } Scrutinee::CatchAll { span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown); + let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); let dummy_type_param = TypeParameter { type_id, initial_type_id: type_id, @@ -57,7 +57,11 @@ impl TyScrutinee { }; let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::CatchAll, - type_id: type_engine.insert(engines, TypeInfo::Placeholder(dummy_type_param)), + type_id: type_engine.insert( + engines, + TypeInfo::Placeholder(dummy_type_param), + span.source_id(), + ), span, }; Ok(typed_scrutinee) @@ -65,7 +69,7 @@ impl TyScrutinee { Scrutinee::Literal { value, span } => { let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Literal(value.clone()), - type_id: type_engine.insert(engines, value.to_typeinfo()), + type_id: type_engine.insert(engines, value.to_typeinfo(), span.source_id()), span, }; Ok(typed_scrutinee) @@ -194,7 +198,7 @@ fn type_check_variable( // Variable isn't a constant, so so we turn it into a [ty::TyScrutinee::Variable]. _ => ty::TyScrutinee { variant: ty::TyScrutineeVariant::Variable(name), - type_id: type_engine.insert(ctx.engines(), TypeInfo::Unknown), + type_id: type_engine.insert(ctx.engines(), TypeInfo::Unknown, None), span, }, }; @@ -280,7 +284,11 @@ fn type_check_struct( let struct_ref = decl_engine.insert(struct_decl); let typed_scrutinee = ty::TyScrutinee { - type_id: type_engine.insert(ctx.engines(), TypeInfo::Struct(struct_ref.clone())), + type_id: type_engine.insert( + ctx.engines(), + TypeInfo::Struct(struct_ref.clone()), + struct_ref.span().source_id(), + ), span, variant: ty::TyScrutineeVariant::StructScrutinee { struct_ref, @@ -386,7 +394,11 @@ fn type_check_enum( value: Box::new(typed_value), instantiation_call_path: call_path, }, - type_id: type_engine.insert(engines, TypeInfo::Enum(enum_ref)), + type_id: type_engine.insert( + engines, + TypeInfo::Enum(enum_ref.clone()), + enum_ref.span().source_id(), + ), span, }; @@ -424,6 +436,7 @@ fn type_check_tuple( }) .collect(), ), + span.source_id(), ); let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Tuple(typed_elems), 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 f73a61c5fda..eaa4c9e1b4e 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 @@ -201,9 +201,11 @@ impl ty::TyExpression { ) } ExpressionKind::LazyOperator(LazyOperatorExpression { op, lhs, rhs }) => { - let ctx = ctx - .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)); + let ctx = ctx.by_ref().with_type_annotation(type_engine.insert( + engines, + TypeInfo::Boolean, + None, + )); Self::type_check_lazy_operator(handler, ctx, op, *lhs, *rhs, span) } ExpressionKind::CodeBlock(contents) => { @@ -321,7 +323,7 @@ impl ty::TyExpression { ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_help_text(""); Self::type_check_array_index(handler, ctx, *prefix, *index, span) } @@ -331,7 +333,7 @@ impl ty::TyExpression { }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_help_text(""); Self::type_check_storage_access( handler, @@ -358,7 +360,7 @@ impl ty::TyExpression { ExpressionKind::Break => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Break, - return_type: type_engine.insert(engines, TypeInfo::Unknown), + return_type: type_engine.insert(engines, TypeInfo::Unknown, None), span, }; Ok(expr) @@ -366,7 +368,7 @@ impl ty::TyExpression { ExpressionKind::Continue => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Continue, - return_type: type_engine.insert(engines, TypeInfo::Unknown), + return_type: type_engine.insert(engines, TypeInfo::Unknown, None), span, }; Ok(expr) @@ -385,7 +387,7 @@ impl ty::TyExpression { // is the responsibility of the function declaration to type check // all return statements contained within it. .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_help_text( "Returned value must match up with the function return type \ annotation.", @@ -395,7 +397,7 @@ impl ty::TyExpression { .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span, engines)); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), - return_type: type_engine.insert(engines, TypeInfo::Unknown), + return_type: type_engine.insert(engines, TypeInfo::Unknown, None), // FIXME: This should be Yes? span, }; @@ -419,7 +421,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); // Literals of type Numeric can now be resolved if typed_expression.return_type is // an UnsignedInteger or a Numeric @@ -456,7 +458,7 @@ impl ty::TyExpression { Literal::Boolean(_) => TypeInfo::Boolean, Literal::B256(_) => TypeInfo::B256, }; - let id = type_engine.insert(engines, return_type); + let id = type_engine.insert(engines, return_type, span.source_id()); ty::TyExpression { expression: ty::TyExpressionVariant::Literal(lit), return_type: id, @@ -597,7 +599,7 @@ impl ty::TyExpression { } Err(_err) => ( ty::TyCodeBlock::default(), - type_engine.insert(engines, TypeInfo::Tuple(Vec::new())), + type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), ), }; @@ -629,7 +631,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("The condition of an if expression must be a boolean expression.") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)); ty::TyExpression::type_check(handler, ctx, condition.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, condition.span(), engines)) }; @@ -637,7 +639,11 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert( + engines, + TypeInfo::Unknown, + then.span().source_id(), + )); ty::TyExpression::type_check(handler, ctx, then.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, then.span(), engines)) }; @@ -645,7 +651,11 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert( + engines, + TypeInfo::Unknown, + expr.span().source_id(), + )); ty::TyExpression::type_check(handler, ctx, expr.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, expr.span(), engines)) }); @@ -668,7 +678,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); ty::TyExpression::type_check(handler, ctx, value.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, value.span(), engines)) }; @@ -856,34 +866,34 @@ impl ty::TyExpression { let return_type = ctx .resolve_type( handler, - type_engine.insert(engines, asm.return_type.clone()), + type_engine.insert(engines, asm.return_type.clone(), asm_span.source_id()), &asm_span, EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); // type check the initializers - let typed_registers = - asm.registers - .clone() - .into_iter() - .map( - |AsmRegisterDeclaration { name, initializer }| ty::TyAsmRegisterDeclaration { - name, - initializer: initializer.map(|initializer| { - let ctx = ctx.by_ref().with_help_text("").with_type_annotation( - type_engine.insert(engines, TypeInfo::Unknown), - ); - - ty::TyExpression::type_check(handler, ctx, initializer.clone()) - .unwrap_or_else(|err| { - ty::TyExpression::error(err, initializer.span(), engines) - }) - }), - }, - ) - .collect(); + let typed_registers = asm + .registers + .clone() + .into_iter() + .map( + |AsmRegisterDeclaration { name, initializer }| ty::TyAsmRegisterDeclaration { + name, + initializer: initializer.map(|initializer| { + let ctx = ctx.by_ref().with_help_text("").with_type_annotation( + type_engine.insert(engines, TypeInfo::Unknown, None), + ); + + ty::TyExpression::type_check(handler, ctx, initializer.clone()) + .unwrap_or_else(|err| { + ty::TyExpression::error(err, initializer.span(), engines) + }) + }), + }, + ) + .collect(); let exp = ty::TyExpression { expression: ty::TyExpressionVariant::AsmExpression { @@ -910,7 +920,7 @@ impl ty::TyExpression { let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let parent = ty::TyExpression::type_check(handler, ctx, prefix)?; let exp = instantiate_struct_field_access(handler, engines, parent, field_to_access, span)?; Ok(exp) @@ -938,7 +948,7 @@ impl ty::TyExpression { .as_ref() .map(|field_type_ids| field_type_ids[i].clone()) .unwrap_or_else(|| { - let initial_type_id = type_engine.insert(engines, TypeInfo::Unknown); + let initial_type_id = type_engine.insert(engines, TypeInfo::Unknown, None); TypeArgument { type_id: initial_type_id, initial_type_id, @@ -965,10 +975,11 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: typed_fields, }, - return_type: ctx - .engines - .te() - .insert(engines, TypeInfo::Tuple(typed_field_types)), + return_type: ctx.engines.te().insert( + engines, + TypeInfo::Tuple(typed_field_types), + span.source_id(), + ), span, }; Ok(exp) @@ -1046,7 +1057,11 @@ impl ty::TyExpression { // Update `access_type` to be the type of the monomorphized struct after inserting it // into the type engine let storage_key_struct_decl_ref = ctx.engines().de().insert(storage_key_struct_decl); - access_type = type_engine.insert(engines, TypeInfo::Struct(storage_key_struct_decl_ref)); + access_type = type_engine.insert( + engines, + TypeInfo::Struct(storage_key_struct_decl_ref.clone()), + storage_key_struct_decl_ref.span().source_id(), + ); // take any trait items that apply to `StorageKey` and copy them to the // monomorphized type @@ -1072,7 +1087,7 @@ impl ty::TyExpression { let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let parent = ty::TyExpression::type_check(handler, ctx, prefix)?; let exp = instantiate_tuple_index_access(handler, engines, parent, index, index_span, span)?; @@ -1539,7 +1554,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("An address that is being ABI cast must be of type b256") - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); ty::TyExpression::type_check(handler, ctx, address) .unwrap_or_else(|err| ty::TyExpression::error(err, err_span, engines)) }; @@ -1585,6 +1600,7 @@ impl ty::TyExpression { abi_name: AbiName::Deferred, address: None, }, + span.source_id(), ), expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, span, @@ -1613,6 +1629,7 @@ impl ty::TyExpression { abi_name: AbiName::Known(abi_name.clone()), address: Some(Box::new(address_expr.clone())), }, + abi_name.span().source_id(), ); // Retrieve the interface surface for this abi. @@ -1690,7 +1707,7 @@ impl ty::TyExpression { let engines = ctx.engines(); if contents.is_empty() { - let unknown_type = type_engine.insert(engines, TypeInfo::Unknown); + let unknown_type = type_engine.insert(engines, TypeInfo::Unknown, None); return Ok(ty::TyExpression { expression: ty::TyExpressionVariant::Array { elem_type: unknown_type, @@ -1707,6 +1724,7 @@ impl ty::TyExpression { }, Length::new(0, Span::dummy()), ), + None, ), span, }); @@ -1725,7 +1743,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, initial_type.clone())); + .with_type_annotation(type_engine.insert(engines, initial_type.clone(), None)); Self::type_check(handler, ctx, expr) .unwrap_or_else(|err| ty::TyExpression::error(err, span, engines)) }) @@ -1750,6 +1768,7 @@ impl ty::TyExpression { }, Length::new(array_count, Span::dummy()), ), + None, ), // Maybe? span, }) @@ -1769,7 +1788,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); ty::TyExpression::type_check(handler, ctx, prefix.clone())? }; @@ -1788,7 +1807,7 @@ impl ty::TyExpression { let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, type_info_u64)); + .with_type_annotation(type_engine.insert(engines, type_info_u64, None)); let index_te = ty::TyExpression::type_check(handler, ctx, index)?; Ok(ty::TyExpression { @@ -1861,12 +1880,12 @@ impl ty::TyExpression { let typed_condition = { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)) .with_help_text("A while loop's loop condition must be a boolean expression."); ty::TyExpression::type_check(handler, ctx, condition)? }; - let unit_ty = type_engine.insert(engines, TypeInfo::Tuple(Vec::new())); + let unit_ty = type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None); let mut ctx = ctx.with_type_annotation(unit_ty).with_help_text( "A while loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ @@ -1899,7 +1918,7 @@ impl ty::TyExpression { let engines = ctx.engines(); let mut ctx = ctx - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_help_text(""); // ensure that the lhs is a supported expression kind match lhs { @@ -1985,7 +2004,7 @@ impl ty::TyExpression { rhs, }, )), - return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new())), + return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), span, }) } @@ -2057,7 +2076,7 @@ impl ty::TyExpression { num.to_string().parse().map(Literal::Numeric).map_err(|e| { Literal::handle_parse_int_error(engines, e, TypeInfo::Numeric, span.clone()) }), - type_engine.insert(engines, TypeInfo::Numeric), + type_engine.insert(engines, TypeInfo::Numeric, None), ), _ => unreachable!("Unexpected type for integer literals"), }, @@ -2113,13 +2132,14 @@ mod tests { &engines, TypeInfo::Array( TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean), + type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), span: Span::dummy(), call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean), + initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), }, Length::new(2, Span::dummy()), ), + None, ), ) } @@ -2256,13 +2276,14 @@ mod tests { &engines, TypeInfo::Array( TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean), + type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), span: Span::dummy(), call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean), + initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), }, Length::new(0, Span::dummy()), ), + None, ), ); let (errors, warnings) = handler.consume(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index 10f58a90cbf..f7d1926308e 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -56,7 +56,11 @@ pub(crate) fn instantiate_enum( type_engine.get(enum_variant.type_argument.type_id), ) { ([], ty) if ty.is_unit() => Ok(ty::TyExpression { - return_type: type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone())), + return_type: type_engine.insert( + engines, + TypeInfo::Enum(enum_ref.clone()), + enum_ref.span().source_id(), + ), expression: ty::TyExpressionVariant::EnumInstantiation { tag: enum_variant.tag, contents: None, @@ -92,7 +96,11 @@ pub(crate) fn instantiate_enum( // we now know that the instantiator type matches the declared type, via the above tpe // check - let type_id = type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone())); + let type_id = type_engine.insert( + engines, + TypeInfo::Enum(enum_ref.clone()), + enum_ref.span().source_id(), + ); type_id.check_type_parameter_bounds( handler, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index c7ba5429e3e..604decadec5 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -28,7 +28,7 @@ pub(crate) fn instantiate_if_expression( let ty_to_check = if r#else.is_some() { ctx.type_annotation() } else { - type_engine.insert(engines, TypeInfo::Tuple(vec![])) + type_engine.insert(engines, TypeInfo::Tuple(vec![]), then.span.source_id()) }; type_engine.unify( handler, @@ -63,10 +63,9 @@ pub(crate) fn instantiate_if_expression( Box::new(r#else) }); - let r#else_ret_ty = r#else - .as_ref() - .map(|x| x.return_type) - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Tuple(Vec::new()))); + let r#else_ret_ty = r#else.as_ref().map(|x| x.return_type).unwrap_or_else(|| { + type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) + }); // if there is a type annotation, then the else branch must exist if !else_deterministically_aborts && !then_deterministically_aborts { // delay emitting the errors until we decide if this is a missing else branch or some other set of errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index bb8483403e0..7f0d14cf427 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -41,7 +41,7 @@ pub(crate) fn type_check_method_application( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); args_buf.push_back( ty::TyExpression::type_check(handler, ctx, arg.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, span.clone(), engines)), @@ -117,6 +117,7 @@ pub(crate) fn type_check_method_application( } else { TypeInfo::B256 }, + param.name.span().source_id(), ); let ctx = ctx .by_ref() @@ -429,7 +430,9 @@ pub(crate) fn resolve_method_name( // type check the call path let type_id = call_path_binding .type_check_with_type_info(handler, &mut ctx) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| { + type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) + }); // find the module that the symbol is in let type_info_prefix = ctx @@ -474,7 +477,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments .get(0) .map(|x| x.return_type) - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown)); + .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); // find the method let decl_ref = ctx.find_method_for_type( @@ -498,7 +501,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments .get(0) .map(|x| x.return_type) - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown)); + .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); // find the method let decl_ref = ctx.find_method_for_type( 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 41199cf602d..9a197706ed6 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 @@ -58,12 +58,12 @@ pub(crate) fn struct_instantiation( })); } (_, true) => TypeInfo::Custom { - qualified_call_path: suffix.into(), + qualified_call_path: suffix.clone().into(), type_arguments: None, root_type_id: None, }, (_, false) => TypeInfo::Custom { - qualified_call_path: suffix.into(), + qualified_call_path: suffix.clone().into(), type_arguments: Some(type_arguments), root_type_id: None, }, @@ -79,12 +79,12 @@ pub(crate) fn struct_instantiation( let type_id = ctx .resolve_type( handler, - type_engine.insert(engines, type_info), + type_engine.insert(engines, type_info, suffix.span().source_id()), &inner_span, EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); // extract the struct name and fields from the type info let type_info = type_engine.get(type_id); @@ -186,7 +186,11 @@ fn type_check_field_arguments( name: struct_field.name.clone(), value: ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err)), + return_type: type_engine.insert( + engines, + TypeInfo::ErrorRecovery(err), + None, + ), span: span.clone(), }, }); diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index bfe5ed4db3b..28db7d698e9 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -143,7 +143,7 @@ impl ty::TyAstNode { } AstNodeContent::Expression(expr) => { let ctx = ctx - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_help_text(""); let inner = ty::TyExpression::type_check(handler, ctx, expr.clone()) .unwrap_or_else(|err| ty::TyExpression::error(err, expr.span(), engines)); diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 671a5b7e36f..083c1c04419 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -212,7 +212,9 @@ impl Root { handler, engines, symbol, - engines.te().insert(engines, type_info), + engines + .te() + .insert(engines, type_info, symbol.span().source_id()), as_trait, self_type, ) @@ -233,7 +235,9 @@ impl Root { handler, engines, symbol, - engines.te().insert(engines, type_info), + engines + .te() + .insert(engines, type_info, symbol.span().source_id()), as_trait, self_type, ) diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index c6328fb8c12..5ce28033b7e 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -199,6 +199,7 @@ impl TraitMap { }, root_type_id: None, }, + trait_name.suffix.span().source_id(), ); for TraitEntry { key: @@ -233,6 +234,7 @@ impl TraitMap { }, root_type_id: None, }, + map_trait_name_suffix.span().source_id(), ); let unify_checker = UnifyCheck::non_generic_constraint_subset(engines); @@ -1030,6 +1032,7 @@ impl TraitMap { }, root_type_id: None, }, + suffix.name.span().source_id(), ); Some((suffix.name.clone(), map_trait_type_id)) } else { @@ -1056,6 +1059,7 @@ impl TraitMap { }, root_type_id: None, }, + constraint_trait_name.span().source_id(), ); (c.trait_name.suffix.clone(), constraint_type_id) }) diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 57b6ee2638a..d4a61570db8 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -104,7 +104,7 @@ impl<'a> TypeCheckContext<'a> { Self { namespace, engines, - type_annotation: engines.te().insert(engines, TypeInfo::Unknown), + type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), unify_generic: false, self_type: None, type_subst: TypeSubstMap::new(), @@ -450,13 +450,14 @@ impl<'a> TypeCheckContext<'a> { .unwrap_or_else(|err| { self.engines .te() - .insert(self.engines, TypeInfo::ErrorRecovery(err)) + .insert(self.engines, TypeInfo::ErrorRecovery(err), None) }); - let type_id = self - .engines - .te() - .insert(self.engines, TypeInfo::Array(elem_ty, n)); + let type_id = self.engines.te().insert( + self.engines, + TypeInfo::Array(elem_ty.clone(), n), + elem_ty.span.source_id(), + ); // take any trait methods that apply to this type and copy them to the new type self.insert_trait_implementation_for_type(type_id); @@ -475,16 +476,19 @@ impl<'a> TypeCheckContext<'a> { mod_path, ) .unwrap_or_else(|err| { - self.engines - .te() - .insert(self.engines, TypeInfo::ErrorRecovery(err)) + self.engines.te().insert( + self.engines, + TypeInfo::ErrorRecovery(err), + None, + ) }); } - let type_id = self - .engines - .te() - .insert(self.engines, TypeInfo::Tuple(type_arguments)); + let type_id = self.engines.te().insert( + self.engines, + TypeInfo::Tuple(type_arguments), + span.source_id(), + ); // take any trait methods that apply to this type and copy them to the new type self.insert_trait_implementation_for_type(type_id); @@ -741,7 +745,11 @@ impl<'a> TypeCheckContext<'a> { let new_decl_ref = decl_engine.insert(new_copy); // create the type id from the copy - let type_id = type_engine.insert(self.engines, TypeInfo::Struct(new_decl_ref)); + let type_id = type_engine.insert( + self.engines, + TypeInfo::Struct(new_decl_ref.clone()), + new_decl_ref.span().source_id(), + ); // take any trait methods that apply to this type and copy them to the new type self.insert_trait_implementation_for_type(type_id); @@ -770,7 +778,11 @@ impl<'a> TypeCheckContext<'a> { let new_decl_ref = decl_engine.insert(new_copy); // create the type id from the copy - let type_id = type_engine.insert(self.engines, TypeInfo::Enum(new_decl_ref)); + let type_id = type_engine.insert( + self.engines, + TypeInfo::Enum(new_decl_ref.clone()), + new_decl_ref.span().source_id(), + ); // take any trait methods that apply to this type and copy them to the new type self.insert_trait_implementation_for_type(type_id); @@ -809,9 +821,10 @@ impl<'a> TypeCheckContext<'a> { type_engine.insert( self.engines, TypeInfo::TraitType { - name, + name: name.clone(), trait_type_id: implementing_type, }, + name.span().source_id(), ) } else { return Err(handler.emit_err(CompileError::Internal( @@ -825,7 +838,7 @@ impl<'a> TypeCheckContext<'a> { name: call_path.call_path.to_string(), span: call_path.call_path.span(), }); - type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err)) + type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None) } }) } @@ -868,7 +881,9 @@ impl<'a> TypeCheckContext<'a> { None, item_prefix, ) - .unwrap_or_else(|err| type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| { + type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None) + }); // grab the module where the type itself is declared let type_module = self @@ -1447,9 +1462,11 @@ impl<'a> TypeCheckContext<'a> { mod_path, ) .unwrap_or_else(|err| { - self.engines - .te() - .insert(self.engines, TypeInfo::ErrorRecovery(err)) + self.engines.te().insert( + self.engines, + TypeInfo::ErrorRecovery(err), + None, + ) }); } let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments( 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 489fa6d02ad..1fd7cb11610 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 @@ -483,7 +483,11 @@ fn item_fn_to_function_declaration( let return_type = match item_fn.fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Tuple(Vec::new())); + let type_id = engines.te().insert( + engines, + TypeInfo::Tuple(Vec::new()), + item_fn.fn_signature.span().source_id(), + ); TypeArgument { type_id, initial_type_id: type_id, @@ -896,7 +900,7 @@ pub(crate) fn item_const_to_constant_declaration( return Err(errors); } } - engines.te().insert(engines, TypeInfo::Unknown).into() + engines.te().insert(engines, TypeInfo::Unknown, None).into() } }; @@ -1136,6 +1140,7 @@ fn generic_params_opt_to_type_parameters_with_parent( type_arguments: None, root_type_id: None, }, + ident.span().source_id(), ); TypeParameter { type_id: custom_type, @@ -1279,9 +1284,11 @@ fn fn_args_to_function_parameters( (Some(reference), None) => reference.span(), (Some(reference), Some(mutable)) => Span::join(reference.span(), mutable.span()), }; - let type_id = engines - .te() - .insert(engines, TypeInfo::new_self_type(self_token.span())); + let type_id = engines.te().insert( + engines, + TypeInfo::new_self_type(self_token.span()), + self_token.span().source_id(), + ); let mut function_parameters = vec![FunctionParameter { name: Ident::new(self_token.span()), is_reference: ref_self.is_some(), @@ -1452,8 +1459,11 @@ fn ty_to_type_argument( let type_engine = engines.te(); let span = ty.span(); let call_path_tree = ty_to_call_path_tree(context, handler, engines, ty.clone())?; - let initial_type_id = - type_engine.insert(engines, ty_to_type_info(context, handler, engines, ty)?); + let initial_type_id = type_engine.insert( + engines, + ty_to_type_info(context, handler, engines, ty.clone())?, + ty.span().source_id(), + ); let type_argument = TypeArgument { type_id: initial_type_id, @@ -1474,7 +1484,11 @@ fn fn_signature_to_trait_fn( let return_type = match &fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Tuple(Vec::new())); + let type_id = engines.te().insert( + engines, + TypeInfo::Tuple(Vec::new()), + fn_signature.span().source_id(), + ); TypeArgument { type_id, initial_type_id: type_id, @@ -2776,7 +2790,7 @@ fn match_expr_to_expression( content: AstNodeContent::Declaration(Declaration::VariableDeclaration( VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown); + let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); TypeArgument { type_id, initial_type_id: type_id, @@ -2852,6 +2866,7 @@ fn path_root_opt_to_bool_and_qualified_path_root( as_trait: engines.te().insert( engines, path_type_to_type_info(context, handler, engines, *path_type.clone())?, + path_type.span().source_id(), ), as_trait_span: path_type.span(), }) @@ -3295,7 +3310,7 @@ fn statement_let_to_ast_nodes( let type_ascription = match ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown); + let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); TypeArgument { type_id, initial_type_id: type_id, @@ -3346,7 +3361,7 @@ fn statement_let_to_ast_nodes( let type_ascription = match &ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown); + let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); TypeArgument { type_id, initial_type_id: type_id, @@ -3438,7 +3453,7 @@ fn statement_let_to_ast_nodes( let type_ascription = match &ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown); + let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); TypeArgument { type_id, initial_type_id: type_id, @@ -3474,7 +3489,7 @@ fn statement_let_to_ast_nodes( .into_iter() .map(|_| { let initial_type_id = - engines.te().insert(engines, TypeInfo::Unknown); + engines.te().insert(engines, TypeInfo::Unknown, None); let dummy_type_param = TypeParameter { type_id: initial_type_id, initial_type_id, @@ -3486,9 +3501,11 @@ fn statement_let_to_ast_nodes( trait_constraints_span: Span::dummy(), is_from_parent: false, }; - let initial_type_id = engines - .te() - .insert(engines, TypeInfo::Placeholder(dummy_type_param)); + let initial_type_id = engines.te().insert( + engines, + TypeInfo::Placeholder(dummy_type_param), + None, + ); TypeArgument { type_id: initial_type_id, initial_type_id, @@ -3498,6 +3515,7 @@ fn statement_let_to_ast_nodes( }) .collect(), ), + tuple_name.span().source_id(), ); TypeArgument { type_id, @@ -3770,7 +3788,7 @@ fn ty_to_type_parameter( let name_ident = match ty { Ty::Path(path_type) => path_type_to_ident(context, handler, path_type)?, Ty::Infer { underscore_token } => { - let unknown_type = type_engine.insert(engines, TypeInfo::Unknown); + let unknown_type = type_engine.insert(engines, TypeInfo::Unknown, None); return Ok(TypeParameter { type_id: unknown_type, initial_type_id: unknown_type, @@ -3794,6 +3812,7 @@ fn ty_to_type_parameter( type_arguments: None, root_type_id: None, }, + name_ident.span().source_id(), ); Ok(TypeParameter { type_id: custom_type, @@ -4053,7 +4072,11 @@ fn path_type_to_type_info( let mut root_type_id = None; if name.as_str() == "Self" { call_path.call_path.prefixes.remove(0); - root_type_id = Some(engines.te().insert(engines, type_info)); + root_type_id = Some(engines.te().insert( + engines, + type_info, + name.span().source_id(), + )); } TypeInfo::Custom { qualified_call_path: call_path, diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index a83799d757d..4ff7e451c4d 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -186,12 +186,12 @@ impl TypeBinding> { let type_id = ctx .resolve_type( handler, - type_engine.insert(engines, type_info), + type_engine.insert(engines, type_info, type_info_span.source_id()), &type_info_span, EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); Ok(type_id) } @@ -258,7 +258,7 @@ impl TypeCheckTypeBinding for TypeBinding { None, ) .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) }); } } @@ -305,7 +305,11 @@ impl TypeCheckTypeBinding for TypeBinding { )?; // Insert the new copy into the declaration engine. let new_struct_ref = ctx.engines.de().insert(new_copy); - let type_id = type_engine.insert(engines, TypeInfo::Struct(new_struct_ref.clone())); + let type_id = type_engine.insert( + engines, + TypeInfo::Struct(new_struct_ref.clone()), + new_struct_ref.span().source_id(), + ); Ok((new_struct_ref, Some(type_id), None)) } } @@ -352,7 +356,11 @@ impl TypeCheckTypeBinding for TypeBinding { )?; // Insert the new copy into the declaration engine. let new_enum_ref = ctx.engines.de().insert(new_copy); - let type_id = type_engine.insert(engines, TypeInfo::Enum(new_enum_ref.clone())); + let type_id = type_engine.insert( + engines, + TypeInfo::Enum(new_enum_ref.clone()), + new_enum_ref.span().source_id(), + ); Ok((new_enum_ref, Some(type_id), Some(unknown_decl))) } } diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index 215c5432791..3f0f72232ea 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -151,7 +151,7 @@ impl TraitConstraint { .unwrap_or_else(|err| { ctx.engines .te() - .insert(ctx.engines(), TypeInfo::ErrorRecovery(err)) + .insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) }); } diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index be6cf9d5571..7581ecb1d3f 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -139,6 +139,7 @@ impl TypeParameter { name: name.clone(), trait_constraints: VecSet(vec![]), }, + span.source_id(), ); TypeParameter { type_id, @@ -279,6 +280,7 @@ impl TypeParameter { name: name_ident.clone(), trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), }, + name_ident.span().source_id(), ); let type_parameter = TypeParameter { @@ -323,9 +325,12 @@ impl TypeParameter { type_engine.replace( type_parameter.type_id, engines, - TypeInfo::UnknownGeneric { - name: type_parameter.name_ident.clone(), - trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), + TypeSourceInfo { + type_info: TypeInfo::UnknownGeneric { + name: type_parameter.name_ident.clone(), + trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), + }, + source_id: type_parameter.name_ident.span().source_id().cloned(), }, ); diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 2a44782627e..07901de3772 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -1,31 +1,43 @@ -use core::fmt::Write; -use hashbrown::hash_map::RawEntryMut; -use hashbrown::HashMap; -use std::sync::RwLock; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::integer_bits::IntegerBits; - -use crate::concurrent_slab::ListDisplay; use crate::{ - concurrent_slab::ConcurrentSlab, decl_engine::*, engine_threading::*, + concurrent_slab::{ConcurrentSlab, ListDisplay}, + decl_engine::*, + engine_threading::*, type_system::priv_prelude::*, }; - -use sway_error::{error::CompileError, type_error::TypeError}; -use sway_types::span::Span; +use core::fmt::Write; +use hashbrown::{hash_map::RawEntryMut, HashMap}; +use std::sync::RwLock; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, + type_error::TypeError, +}; +use sway_types::{integer_bits::IntegerBits, span::Span, ModuleId, SourceId}; use super::unify::unifier::UnifyKind; #[derive(Debug, Default)] pub struct TypeEngine { - pub(super) slab: ConcurrentSlab, - id_map: RwLock>, + pub(super) slab: ConcurrentSlab, + id_map: RwLock>, } impl TypeEngine { /// Inserts a [TypeInfo] into the [TypeEngine] and returns a [TypeId] /// referring to that [TypeInfo]. - pub(crate) fn insert(&self, engines: &Engines, ty: TypeInfo) -> TypeId { + pub(crate) fn insert( + &self, + engines: &Engines, + ty: TypeInfo, + source_id: Option<&SourceId>, + ) -> TypeId { + let source_id = source_id + .map(Clone::clone) + .or_else(|| info_to_source_id(&ty)); + let ty = TypeSourceInfo { + type_info: ty, + source_id, + }; let mut id_map = self.id_map.write().unwrap(); let hash_builder = id_map.hasher().clone(); @@ -36,7 +48,7 @@ impl TypeEngine { .from_hash(ty_hash, |x| x.eq(&ty, engines)); match raw_entry { RawEntryMut::Occupied(o) => return *o.get(), - RawEntryMut::Vacant(_) if ty.can_change(engines.de()) => { + RawEntryMut::Vacant(_) if ty.type_info.can_change(engines.de()) => { TypeId::new(self.slab.insert(ty)) } RawEntryMut::Vacant(v) => { @@ -47,14 +59,22 @@ impl TypeEngine { } } - pub fn replace(&self, id: TypeId, engines: &Engines, new_value: TypeInfo) { + /// Removes all data associated with `module_id` from the type engine. + pub fn clear_module(&mut self, module_id: &ModuleId) { + self.slab.retain(|ty| match &ty.source_id { + Some(source_id) => &source_id.module_id() != module_id, + None => false, + }); + } + + pub fn replace(&self, id: TypeId, engines: &Engines, new_value: TypeSourceInfo) { let prev_value = self.slab.get(id.index()); self.slab.replace(id, &prev_value, new_value, engines); } /// Performs a lookup of `id` into the [TypeEngine]. pub fn get(&self, id: TypeId) -> TypeInfo { - self.slab.get(id.index()) + self.slab.get(id.index()).type_info } /// Performs a lookup of `id` into the [TypeEngine] recursing when finding a @@ -62,7 +82,7 @@ impl TypeEngine { pub fn get_unaliased(&self, id: TypeId) -> TypeInfo { // A slight infinite loop concern if we somehow have self-referential aliases, but that // shouldn't be possible. - match self.slab.get(id.index()) { + match self.slab.get(id.index()).type_info { TypeInfo::Alias { ty, .. } => self.get_unaliased(ty.type_id), ty_info => ty_info, } @@ -311,7 +331,11 @@ impl TypeEngine { handler, engines, type_id, - self.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + self.insert( + engines, + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + span.source_id(), + ), span, "", None, @@ -329,10 +353,29 @@ impl TypeEngine { self.slab.with_slice(|elems| { let list = elems .iter() - .map(|type_info| format!("{:?}", engines.help_out(type_info))); + .map(|ty| format!("{:?}", engines.help_out(&ty.type_info))); let list = ListDisplay { list }; write!(builder, "TypeEngine {{\n{list}\n}}").unwrap(); }); builder } } + +/// Maps specific `TypeInfo` variants to a reserved `SourceId`, returning `None` for non-mapped types. +fn info_to_source_id(ty: &TypeInfo) -> Option { + match ty { + TypeInfo::Unknown + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Numeric + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::StringSlice + | TypeInfo::Contract + | TypeInfo::StringArray(_) + | TypeInfo::Array(_, _) => Some(SourceId::reserved()), + TypeInfo::Tuple(v) if v.is_empty() => Some(SourceId::reserved()), + _ => None, + } +} diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 5b3104ee472..8596e61e7f5 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -9,7 +9,7 @@ use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; -use sway_types::{integer_bits::IntegerBits, span::Span, Spanned}; +use sway_types::{integer_bits::IntegerBits, span::Span, SourceId, Spanned}; use std::{ cmp::Ordering, @@ -67,6 +67,28 @@ impl PartialEqWithEngines for VecSet { } } +/// Encapsulates type information and its optional source identifier. +#[derive(Debug, Default, Clone)] +pub struct TypeSourceInfo { + pub(crate) type_info: TypeInfo, + /// The source id that created this type. + pub(crate) source_id: Option, +} + +impl HashWithEngines for TypeSourceInfo { + fn hash(&self, state: &mut H, engines: &Engines) { + self.type_info.hash(state, engines); + self.source_id.hash(state); + } +} + +impl EqWithEngines for TypeSourceInfo {} +impl PartialEqWithEngines for TypeSourceInfo { + fn eq(&self, other: &Self, engines: &Engines) -> bool { + self.type_info.eq(&other.type_info, engines) && self.source_id == other.source_id + } +} + /// Type information without an associated value, used for type inferencing and definition. #[derive(Debug, Clone, Default)] pub enum TypeInfo { diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index e351e76981a..0e64bc99173 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -40,6 +40,7 @@ fn generic_enum_resolution() { name: generic_name.clone(), trait_constraints: VecSet(Vec::new()), }, + None, ); let placeholder_type = engines.te().insert( &engines, @@ -51,6 +52,7 @@ fn generic_enum_resolution() { trait_constraints_span: sp.clone(), is_from_parent: false, }), + None, ); let placeholder_type_param = TypeParameter { type_id: placeholder_type, @@ -81,14 +83,16 @@ fn generic_enum_resolution() { visibility: crate::language::Visibility::Public, attributes: AttributesMap::default(), }); - let ty_1 = engines.te().insert(&engines, TypeInfo::Enum(decl_ref_1)); + let ty_1 = engines + .te() + .insert(&engines, TypeInfo::Enum(decl_ref_1), None); /* Result { a: bool } */ - let boolean_type = engines.te().insert(&engines, TypeInfo::Boolean); + let boolean_type = engines.te().insert(&engines, TypeInfo::Boolean, None); let variant_types = vec![ty::TyEnumVariant { name: a_name, tag: 0, @@ -117,7 +121,9 @@ fn generic_enum_resolution() { visibility: crate::language::Visibility::Public, attributes: AttributesMap::default(), }); - let ty_2 = engines.te().insert(&engines, TypeInfo::Enum(decl_ref_2)); + let ty_2 = engines + .te() + .insert(&engines, TypeInfo::Enum(decl_ref_2), None); // Unify them together... let h = Handler::default(); @@ -144,10 +150,12 @@ fn basic_numeric_unknown() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric); - let id2 = engines - .te() - .insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); + let id = engines.te().insert(&engines, TypeInfo::Numeric, None); + let id2 = engines.te().insert( + &engines, + TypeInfo::UnsignedInteger(IntegerBits::Eight), + None, + ); // Unify them together... let h = Handler::default(); @@ -168,10 +176,12 @@ fn unify_numerics() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric); - let id2 = engines - .te() - .insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); + let id = engines.te().insert(&engines, TypeInfo::Numeric, None); + let id2 = engines.te().insert( + &engines, + TypeInfo::UnsignedInteger(IntegerBits::Eight), + None, + ); // Unify them together... let h = Handler::default(); @@ -193,8 +203,12 @@ fn unify_numerics_2() { let sp = Span::dummy(); // numerics - let id = type_engine.insert(&engines, TypeInfo::Numeric); - let id2 = type_engine.insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); + let id = type_engine.insert(&engines, TypeInfo::Numeric, None); + let id2 = type_engine.insert( + &engines, + TypeInfo::UnsignedInteger(IntegerBits::Eight), + None, + ); // Unify them together... let h = Handler::default(); diff --git a/sway-core/src/type_system/priv_prelude.rs b/sway-core/src/type_system/priv_prelude.rs index a00dd8bcf01..6656e251004 100644 --- a/sway-core/src/type_system/priv_prelude.rs +++ b/sway-core/src/type_system/priv_prelude.rs @@ -17,5 +17,5 @@ pub use super::{ }, engine::TypeEngine, id::TypeId, - info::{AbiName, TypeInfo}, + info::{AbiName, TypeInfo, TypeSourceInfo}, }; diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index e6d6fc2ec9f..74bcc028dd1 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -1,10 +1,10 @@ -use std::{collections::BTreeMap, fmt}; - use crate::{ decl_engine::{DeclEngine, DeclEngineInsert}, engine_threading::*, type_system::priv_prelude::*, }; +use std::{collections::BTreeMap, fmt}; +use sway_types::Spanned; type SourceType = TypeId; type DestinationType = TypeId; @@ -77,7 +77,11 @@ impl TypeSubstMap { .map(|x| { ( x.type_id, - type_engine.insert(engines, TypeInfo::Placeholder(x.clone())), + type_engine.insert( + engines, + TypeInfo::Placeholder(x.clone()), + x.name_ident.span().source_id(), + ), ) }) .collect(); @@ -348,7 +352,11 @@ impl TypeSubstMap { } if need_to_create_new { let new_decl_ref = decl_engine.insert(decl); - Some(type_engine.insert(engines, TypeInfo::Struct(new_decl_ref))) + Some(type_engine.insert( + engines, + TypeInfo::Struct(new_decl_ref.clone()), + new_decl_ref.decl_span().source_id(), + )) } else { None } @@ -372,7 +380,11 @@ impl TypeSubstMap { } if need_to_create_new { let new_decl_ref = decl_engine.insert(decl); - Some(type_engine.insert(engines, TypeInfo::Enum(new_decl_ref))) + Some(type_engine.insert( + engines, + TypeInfo::Enum(new_decl_ref.clone()), + new_decl_ref.decl_span().source_id(), + )) } else { None } @@ -380,42 +392,54 @@ impl TypeSubstMap { TypeInfo::Array(mut elem_ty, count) => { self.find_match(elem_ty.type_id, engines).map(|type_id| { elem_ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Array(elem_ty, count)) + type_engine.insert( + engines, + TypeInfo::Array(elem_ty.clone(), count), + elem_ty.span.source_id(), + ) }) } TypeInfo::Tuple(fields) => { let mut need_to_create_new = false; + let mut source_id = None; let fields = fields .into_iter() .map(|mut field| { if let Some(type_id) = self.find_match(field.type_id, engines) { need_to_create_new = true; + source_id = field.span.source_id().cloned(); field.type_id = type_id; } field }) .collect::>(); if need_to_create_new { - Some(type_engine.insert(engines, TypeInfo::Tuple(fields))) + Some(type_engine.insert(engines, TypeInfo::Tuple(fields), source_id.as_ref())) } else { None } } TypeInfo::Storage { fields } => { let mut need_to_create_new = false; + let mut source_id = None; let fields = fields .into_iter() .map(|mut field| { if let Some(type_id) = self.find_match(field.type_argument.type_id, engines) { need_to_create_new = true; + source_id = field.span.source_id().cloned(); field.type_argument.type_id = type_id; } field }) .collect::>(); if need_to_create_new { - Some(type_engine.insert(engines, TypeInfo::Storage { fields })) + Some(type_engine.insert( + engines, + TypeInfo::Storage { fields }, + source_id.as_ref(), + )) } else { None } @@ -423,16 +447,23 @@ impl TypeSubstMap { TypeInfo::Alias { name, mut ty } => { self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Alias { name, ty }) + type_engine.insert( + engines, + TypeInfo::Alias { + name, + ty: ty.clone(), + }, + ty.span.source_id(), + ) }) } TypeInfo::Ptr(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Ptr(ty)) + type_engine.insert(engines, TypeInfo::Ptr(ty.clone()), ty.span.source_id()) }), TypeInfo::Slice(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Slice(ty)) + type_engine.insert(engines, TypeInfo::Slice(ty.clone()), ty.span.source_id()) }), TypeInfo::TraitType { .. } => iter_for_match(engines, self, &type_info), TypeInfo::Unknown diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 144f5538f99..c7483b74e27 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -60,12 +60,19 @@ impl<'a> Unifier<'a> { span: &Span, ) { let type_engine = self.engines.te(); + let source_id = span.source_id().cloned(); if type_engine .slab .replace( received, - received_type_info, - expected_type_info, + &TypeSourceInfo { + type_info: received_type_info.clone(), + source_id, + }, + TypeSourceInfo { + type_info: expected_type_info.clone(), + source_id, + }, self.engines, ) .is_some() @@ -85,12 +92,19 @@ impl<'a> Unifier<'a> { span: &Span, ) { let type_engine = self.engines.te(); + let source_id = span.source_id().cloned(); if type_engine .slab .replace( expected, - expected_type_info, - received_type_info, + &TypeSourceInfo { + type_info: expected_type_info.clone(), + source_id, + }, + TypeSourceInfo { + type_info: received_type_info.clone(), + source_id, + }, self.engines, ) .is_some() @@ -108,8 +122,8 @@ impl<'a> Unifier<'a> { } match ( - self.engines.te().slab.get(received.index()), - self.engines.te().slab.get(expected.index()), + self.engines.te().slab.get(received.index()).type_info, + self.engines.te().slab.get(expected.index()).type_info, ) { // If they have the same `TypeInfo`, then we either compare them for // correctness or perform further unification. @@ -260,7 +274,7 @@ impl<'a> Unifier<'a> { received, expected, r, - self.engines.te().slab.get(expected.index()), + self.engines.te().slab.get(expected.index()).type_info, span, ) } @@ -278,7 +292,7 @@ impl<'a> Unifier<'a> { handler, received, expected, - self.engines.te().slab.get(received.index()), + self.engines.te().slab.get(received.index()).type_info, e, span, ) diff --git a/sway-lsp/benches/lsp_benchmarks/compile.rs b/sway-lsp/benches/lsp_benchmarks/compile.rs index e951e4ff319..7a51734b9ef 100644 --- a/sway-lsp/benches/lsp_benchmarks/compile.rs +++ b/sway-lsp/benches/lsp_benchmarks/compile.rs @@ -3,6 +3,8 @@ use lsp_types::Url; use sway_core::Engines; use sway_lsp::core::session::{self, Session}; +const NUM_DID_CHANGE_ITERATIONS: usize = 20; + fn benchmarks(c: &mut Criterion) { // Load the test project let uri = Url::from_file_path(super::benchmark_dir().join("src/main.sw")).unwrap(); @@ -23,6 +25,15 @@ fn benchmarks(c: &mut Criterion) { let _ = black_box(session::traverse(results.clone(), &engines).unwrap()); }) }); + + c.bench_function("did_change_with_caching", |b| { + b.iter(|| { + let engines = Engines::default(); + for _ in 0..NUM_DID_CHANGE_ITERATIONS { + let _ = black_box(session::compile(&uri, &engines).unwrap()); + } + }) + }); } criterion_group! { diff --git a/sway-lsp/benches/lsp_benchmarks/mod.rs b/sway-lsp/benches/lsp_benchmarks/mod.rs index eb140de96b2..3ff47f476ca 100644 --- a/sway-lsp/benches/lsp_benchmarks/mod.rs +++ b/sway-lsp/benches/lsp_benchmarks/mod.rs @@ -4,6 +4,7 @@ pub mod token_map; use lsp_types::Url; use std::{path::PathBuf, sync::Arc}; +use sway_core::Engines; use sway_lsp::core::session::{self, Session}; pub fn compile_test_project() -> (Url, Arc) { @@ -12,7 +13,8 @@ pub fn compile_test_project() -> (Url, Arc) { let uri = Url::from_file_path(benchmark_dir().join("src/main.sw")).unwrap(); session.handle_open_file(&uri); // Compile the project and write the parse result to the session - let parse_result = session::parse_project(&uri).unwrap(); + let engines = Engines::default(); + let parse_result = session::parse_project(&uri, &engines).unwrap(); session.write_parse_result(parse_result); (uri, Arc::new(session)) } diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index fd0ffa6c110..64030948bda 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -44,8 +44,8 @@ use sway_core::{ BuildTarget, Engines, Namespace, Programs, }; use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning}; -use sway_types::{SourceEngine, Spanned}; -use sway_utils::helpers::get_sway_files; +use sway_types::{SourceEngine, SourceId, Spanned}; +use sway_utils::{helpers::get_sway_files, PerformanceData}; use tokio::sync::Semaphore; pub type Documents = DashMap; @@ -64,10 +64,10 @@ pub struct CompiledProgram { pub struct ParseResult { pub(crate) diagnostics: (Vec, Vec), pub(crate) token_map: TokenMap, - pub(crate) engines: Engines, pub(crate) lexed: LexedProgram, pub(crate) parsed: ParseProgram, pub(crate) typed: ty::TyProgram, + pub(crate) metrics: DashMap, } /// A `Session` is used to store information about a single member in a workspace. @@ -87,6 +87,7 @@ pub struct Session { pub parse_permits: Arc, // Cached diagnostic results that require a lock to access. Readers will wait for writers to complete. pub diagnostics: Arc>, + pub metrics: DashMap, } impl Default for Session { @@ -101,6 +102,7 @@ impl Session { token_map: TokenMap::new(), documents: DashMap::new(), runnables: DashMap::new(), + metrics: DashMap::new(), compiled_program: RwLock::new(Default::default()), engines: <_>::default(), sync: SyncWorkspace::new(), @@ -145,16 +147,31 @@ impl Session { self.diagnostics.read().clone() } + /// Clean up memory in the [TypeEngine] and [DeclEngine] for the user's workspace. + pub fn garbage_collect(&self) -> Result<(), LanguageServerError> { + let path = self.sync.temp_dir()?; + let module_id = { self.engines.read().se().get_module_id(&path) }; + if let Some(module_id) = module_id { + self.engines.write().clear_module(&module_id); + } + Ok(()) + } + /// Write the result of parsing to the session. /// This function should only be called after successfully parsing. pub fn write_parse_result(&self, res: ParseResult) { self.token_map.clear(); self.runnables.clear(); + self.metrics.clear(); - *self.engines.write() = res.engines; res.token_map.deref().iter().for_each(|item| { + let (i, t) = item.pair(); + self.token_map.insert(i.clone(), t.clone()); + }); + + res.metrics.iter().for_each(|item| { let (s, t) = item.pair(); - self.token_map.insert(s.clone(), t.clone()); + self.metrics.insert(*s, t.clone()); }); self.create_runnables( @@ -446,6 +463,7 @@ pub struct TraversalResult { pub diagnostics: (Vec, Vec), pub programs: Option<(LexedProgram, ParseProgram, ty::TyProgram)>, pub token_map: TokenMap, + pub metrics: DashMap, } pub fn traverse( @@ -453,6 +471,7 @@ pub fn traverse( engines: &Engines, ) -> Result { let token_map = TokenMap::new(); + let metrics_map = DashMap::new(); let mut diagnostics = (Vec::::new(), Vec::::new()); let mut programs = None; let results_len = results.len(); @@ -468,9 +487,14 @@ pub fn traverse( lexed, parsed, typed, - metrics: _, + metrics, } = value.unwrap(); + let source_id = lexed.root.tree.span().source_id().cloned(); + if let Some(source_id) = source_id { + metrics_map.insert(source_id, metrics.clone()); + } + // Get a reference to the typed program AST. let typed_program = typed .as_ref() @@ -514,26 +538,27 @@ pub fn traverse( diagnostics, programs, token_map, + metrics: metrics_map, }) } /// Parses the project and returns true if the compiler diagnostics are new and should be published. -pub fn parse_project(uri: &Url) -> Result { - let engines = Engines::default(); - let results = compile(uri, &engines)?; +pub fn parse_project(uri: &Url, engines: &Engines) -> Result { + let results = compile(uri, engines)?; let TraversalResult { diagnostics, programs, token_map, - } = traverse(results, &engines)?; + metrics, + } = traverse(results, engines)?; let (lexed, parsed, typed) = programs.expect("Programs should be populated at this point."); Ok(ParseResult { diagnostics, token_map, - engines, lexed, parsed, typed, + metrics, }) } @@ -600,7 +625,8 @@ mod tests { fn parse_project_returns_manifest_file_not_found() { let dir = get_absolute_path("sway-lsp/tests/fixtures"); let uri = get_url(&dir); - let result = parse_project(&uri).expect_err("expected ManifestFileNotFound"); + let engines = Engines::default(); + let result = parse_project(&uri, &engines).expect_err("expected ManifestFileNotFound"); assert!(matches!( result, LanguageServerError::DocumentError( diff --git a/sway-lsp/src/handlers/notification.rs b/sway-lsp/src/handlers/notification.rs index de74b9b7794..f39d21ce51c 100644 --- a/sway-lsp/src/handlers/notification.rs +++ b/sway-lsp/src/handlers/notification.rs @@ -20,7 +20,7 @@ pub async fn handle_did_open_text_document( // as the workspace is already compiled. if session.token_map().is_empty() { state - .parse_project(uri, params.text_document.uri, session.clone()) + .parse_project(uri, params.text_document.uri, None, session.clone()) .await; } Ok(()) @@ -36,7 +36,12 @@ pub async fn handle_did_change_text_document( .uri_and_session_from_workspace(¶ms.text_document.uri)?; session.write_changes_to_file(&uri, params.content_changes)?; state - .parse_project(uri, params.text_document.uri, session.clone()) + .parse_project( + uri, + params.text_document.uri, + Some(params.text_document.version), + session.clone(), + ) .await; Ok(()) } @@ -51,7 +56,7 @@ pub(crate) async fn handle_did_save_text_document( .uri_and_session_from_workspace(¶ms.text_document.uri)?; session.sync.resync()?; state - .parse_project(uri, params.text_document.uri, session.clone()) + .parse_project(uri, params.text_document.uri, None, session.clone()) .await; Ok(()) } diff --git a/sway-lsp/src/handlers/request.rs b/sway-lsp/src/handlers/request.rs index 59f46d6ad45..fef0432b7e6 100644 --- a/sway-lsp/src/handlers/request.rs +++ b/sway-lsp/src/handlers/request.rs @@ -16,6 +16,7 @@ use std::{ path::{Path, PathBuf}, }; use sway_types::{Ident, Spanned}; +use sway_utils::PerformanceData; use tower_lsp::jsonrpc::Result; use tracing::metadata::LevelFilter; @@ -447,3 +448,32 @@ pub fn handle_visualize( _ => Ok(None), } } + +/// This method is triggered by the test suite to request the latest compilation metrics. +pub(crate) fn metrics( + state: &ServerState, + params: lsp_ext::MetricsParams, +) -> Result>> { + match state + .sessions + .uri_and_session_from_workspace(¶ms.text_document.uri) + { + Ok((_, session)) => { + let engines = session.engines.read(); + let mut metrics = vec![]; + for kv in session.metrics.iter() { + let path = engines + .se() + .get_path(kv.key()) + .to_string_lossy() + .to_string(); + metrics.push((path, kv.value().clone())); + } + Ok(Some(metrics)) + } + Err(err) => { + tracing::error!("{}", err.to_string()); + Ok(None) + } + } +} diff --git a/sway-lsp/src/lib.rs b/sway-lsp/src/lib.rs index 4b7eddeddde..1d8cbec56e2 100644 --- a/sway-lsp/src/lib.rs +++ b/sway-lsp/src/lib.rs @@ -28,6 +28,7 @@ pub async fn start() { .custom_method("sway/show_ast", ServerState::show_ast) .custom_method("sway/visualize", ServerState::visualize) .custom_method("sway/on_enter", ServerState::on_enter) + .custom_method("sway/metrics", ServerState::metrics) .finish(); Server::new(tokio::io::stdin(), tokio::io::stdout(), socket) .serve(service) diff --git a/sway-lsp/src/lsp_ext.rs b/sway-lsp/src/lsp_ext.rs index e13627a4ed7..7ef742bdf83 100644 --- a/sway-lsp/src/lsp_ext.rs +++ b/sway-lsp/src/lsp_ext.rs @@ -25,3 +25,9 @@ pub struct VisualizeParams { pub text_document: TextDocumentIdentifier, pub graph_kind: String, } + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MetricsParams { + pub text_document: TextDocumentIdentifier, +} diff --git a/sway-lsp/src/server.rs b/sway-lsp/src/server.rs index 9cde8406e66..e2413f704b3 100644 --- a/sway-lsp/src/server.rs +++ b/sway-lsp/src/server.rs @@ -4,7 +4,7 @@ use crate::{ core::document, handlers::{notification, request}, - lsp_ext::{OnEnterParams, ShowAstParams, VisualizeParams}, + lsp_ext::{MetricsParams, OnEnterParams, ShowAstParams, VisualizeParams}, server_state::ServerState, }; use lsp_types::{ @@ -17,6 +17,7 @@ use lsp_types::{ PrepareRenameResponse, RenameParams, SemanticTokensParams, SemanticTokensResult, TextDocumentIdentifier, TextDocumentPositionParams, TextEdit, WorkspaceEdit, }; +use sway_utils::PerformanceData; use tower_lsp::{jsonrpc::Result, LanguageServer}; #[tower_lsp::async_trait] @@ -140,4 +141,11 @@ impl ServerState { pub async fn visualize(&self, params: VisualizeParams) -> Result> { request::handle_visualize(self, params) } + + pub async fn metrics( + &self, + params: MetricsParams, + ) -> Result>> { + request::metrics(self, params) + } } diff --git a/sway-lsp/src/server_state.rs b/sway-lsp/src/server_state.rs index a9d8700be40..f2a96ab789d 100644 --- a/sway-lsp/src/server_state.rs +++ b/sway-lsp/src/server_state.rs @@ -81,8 +81,14 @@ impl ServerState { diagnostics_to_publish } - pub(crate) async fn parse_project(&self, uri: Url, workspace_uri: Url, session: Arc) { - match run_blocking_parse_project(uri.clone(), session.clone()).await { + pub(crate) async fn parse_project( + &self, + uri: Url, + workspace_uri: Url, + version: Option, + session: Arc, + ) { + match run_blocking_parse_project(uri.clone(), version, session.clone()).await { Ok(_) => { // Note: Even if the computed diagnostics vec is empty, we still have to push the empty Vec // in order to clear former diagnostics. Newly pushed diagnostics always replace previously pushed diagnostics. @@ -108,6 +114,7 @@ impl ServerState { /// Runs parse_project in a blocking thread, because parsing is not async. async fn run_blocking_parse_project( uri: Url, + version: Option, session: Arc, ) -> Result<(), LanguageServerError> { // Acquire a permit to parse the project. If there are none available, return false. This way, @@ -118,7 +125,16 @@ async fn run_blocking_parse_project( tokio::task::spawn_blocking(move || { // Lock the diagnostics result to prevent multiple threads from parsing the project at the same time. let mut diagnostics = session.diagnostics.write(); - let parse_result = session::parse_project(&uri)?; + + if let Some(version) = version { + // Garbage collection is fairly expsensive so we only clear on every 10th keystroke. + if version % 10 == 0 { + if let Err(err) = session.garbage_collect() { + tracing::error!("Unable to perform garbage collection: {}", err.to_string()); + } + } + } + let parse_result = session::parse_project(&uri, &session.engines.read())?; let (errors, warnings) = parse_result.diagnostics.clone(); session.write_parse_result(parse_result); *diagnostics = get_diagnostics(&warnings, &errors, session.engines.read().se()); diff --git a/sway-lsp/tests/integration/lsp.rs b/sway-lsp/tests/integration/lsp.rs index 3b1be3daeb0..74f18d983cb 100644 --- a/sway-lsp/tests/integration/lsp.rs +++ b/sway-lsp/tests/integration/lsp.rs @@ -12,6 +12,7 @@ use sway_lsp::{ lsp_ext::{ShowAstParams, VisualizeParams}, server_state::ServerState, }; +use sway_utils::PerformanceData; use tower::{Service, ServiceExt}; use tower_lsp::{ jsonrpc::{Id, Request, Response}, @@ -162,6 +163,30 @@ pub(crate) async fn visualize_request(server: &ServerState, uri: &Url, graph_kin assert!(!re.find(response.as_str()).unwrap().is_empty()); } +pub(crate) async fn metrics_request( + service: &mut LspService, + uri: &Url, +) -> Vec<(String, PerformanceData)> { + let params = json!({ + "textDocument": { + "uri": uri, + }, + }); + let request = build_request_with_id("sway/metrics", params, 1); + let result = call_request(service, request.clone()) + .await + .unwrap() + .unwrap(); + let value = result.result().unwrap().as_array(); + let mut res = vec![]; + for v in value.unwrap().iter() { + let path = v.get(0).unwrap().as_str().unwrap(); + let metric = serde_json::from_value(v.get(1).unwrap().clone()).unwrap(); + res.push((path.to_string(), metric)); + } + res +} + pub(crate) fn semantic_tokens_request(server: &ServerState, uri: &Url) { let params = SemanticTokensParams { text_document: TextDocumentIdentifier { uri: uri.clone() }, diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index cc59fc773c1..73a56343967 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -95,6 +95,43 @@ async fn did_change() { shutdown_and_exit(&mut service).await; } +#[tokio::test] +async fn did_cache_test() { + let (mut service, _) = LspService::build(ServerState::new) + .custom_method("sway/metrics", ServerState::metrics) + .finish(); + let uri = init_and_open(&mut service, doc_comments_dir().join("src/main.sw")).await; + let _ = lsp::did_change_request(&mut service, &uri).await; + let metrics = lsp::metrics_request(&mut service, &uri).await; + assert!(metrics.len() >= 2); + for (path, metrics) in metrics { + if path.contains("sway-lib-core") || path.contains("sway-lib-std") { + assert!(metrics.reused_modules >= 1); + } + } + shutdown_and_exit(&mut service).await; +} + +// #[tokio::test] +#[allow(dead_code)] +async fn did_change_stress_test() { + let (mut service, _) = LspService::build(ServerState::new) + .custom_method("sway/metrics", ServerState::metrics) + .finish(); + let uri = init_and_open(&mut service, doc_comments_dir().join("src/main.sw")).await; + let times = 20; + for _ in 0..times { + let _ = lsp::did_change_request(&mut service, &uri).await; + let metrics = lsp::metrics_request(&mut service, &uri).await; + for (path, metrics) in metrics { + if path.contains("sway-lib-core") || path.contains("sway-lib-std") { + assert!(metrics.reused_modules >= 1); + } + } + } + shutdown_and_exit(&mut service).await; +} + #[tokio::test] async fn lsp_syncs_with_workspace_edits() { let (mut service, _) = LspService::new(ServerState::new); diff --git a/sway-types/Cargo.toml b/sway-types/Cargo.toml index b74354e3211..8bd48040985 100644 --- a/sway-types/Cargo.toml +++ b/sway-types/Cargo.toml @@ -16,6 +16,7 @@ lazy_static = "1.4" num-bigint = "0.4.3" num-traits = "0.2.16" serde = { version = "1.0", features = ["derive"] } +sway-utils = { version = "0.47.0", path = "../sway-utils" } thiserror = "1" [features] diff --git a/sway-types/src/lib.rs b/sway-types/src/lib.rs index 4e6b9d6a42d..30ceeaf2378 100644 --- a/sway-types/src/lib.rs +++ b/sway-types/src/lib.rs @@ -89,11 +89,51 @@ impl Instruction { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +pub struct ModuleId { + id: u16, +} + +impl ModuleId { + pub fn new(id: u16) -> Self { + Self { id } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] pub struct SourceId { id: u32, } +impl SourceId { + const RESERVED: u16 = 0; + const SOURCE_ID_BITS: u32 = 20; + const SOURCE_ID_MASK: u32 = (1 << Self::SOURCE_ID_BITS) - 1; + + /// Create a combined ID from module and source IDs. + pub fn new(module_id: u16, source_id: u32) -> Self { + SourceId { + id: ((module_id as u32) << Self::SOURCE_ID_BITS) | source_id, + } + } + + /// Create a reserved source_id. This is assigned to internal types + /// that should not be cleared during garbage collection. + pub fn reserved() -> Self { + Self::new(Self::RESERVED, Self::RESERVED as u32) + } + + /// The module_id that this source_id was created from. + pub fn module_id(&self) -> ModuleId { + ModuleId::new((self.id >> Self::SOURCE_ID_BITS) as u16) + } + + /// Id of the source file without the module_id component. + pub fn source_id(&self) -> u32 { + self.id & Self::SOURCE_ID_MASK + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] pub struct Source { /// Absolute path to the source file diff --git a/sway-types/src/source_engine.rs b/sway-types/src/source_engine.rs index ab4eb4d15e6..324220921a8 100644 --- a/sway-types/src/source_engine.rs +++ b/sway-types/src/source_engine.rs @@ -1,6 +1,9 @@ -use std::{collections::HashMap, path::PathBuf, sync::RwLock}; - -use crate::SourceId; +use crate::{ModuleId, SourceId}; +use std::{ + collections::{BTreeSet, HashMap}, + path::PathBuf, + sync::RwLock, +}; /// The Source Engine manages a relationship between file paths and their corresponding /// integer-based source IDs. Additionally, it maintains a reserve - a map that traces @@ -13,9 +16,12 @@ use crate::SourceId; /// a straightforward non-mutable reference, ensuring safe concurrent access. #[derive(Debug, Default)] pub struct SourceEngine { - next_id: RwLock, - source_map: RwLock>, - path_map: RwLock>, + next_source_id: RwLock, + path_to_source_map: RwLock>, + source_to_path_map: RwLock>, + next_module_id: RwLock, + path_to_module_map: RwLock>, + module_to_sources_map: RwLock>>, } impl SourceEngine { @@ -24,36 +30,55 @@ impl SourceEngine { /// existing ID. If not, a new ID will be created. pub fn get_source_id(&self, path: &PathBuf) -> SourceId { { - let source_map = self.source_map.read().unwrap(); + let source_map = self.path_to_source_map.read().unwrap(); if source_map.contains_key(path) { return source_map.get(path).cloned().unwrap(); } } - let source_id = SourceId { - id: *self.next_id.read().unwrap(), + let manifest_path = sway_utils::find_parent_manifest_dir(path).unwrap_or(path.clone()); + let module_id = { + let mut module_map = self.path_to_module_map.write().unwrap(); + *module_map.entry(manifest_path.clone()).or_insert_with(|| { + let mut next_id = self.next_module_id.write().unwrap(); + *next_id += 1; + ModuleId::new(*next_id) + }) }; + + let source_id = SourceId::new(module_id.id, *self.next_source_id.read().unwrap()); { - let mut next_id = self.next_id.write().unwrap(); + let mut next_id = self.next_source_id.write().unwrap(); *next_id += 1; - let mut source_map = self.source_map.write().unwrap(); + let mut source_map = self.path_to_source_map.write().unwrap(); source_map.insert(path.clone(), source_id); - let mut path_map = self.path_map.write().unwrap(); + let mut path_map = self.source_to_path_map.write().unwrap(); path_map.insert(source_id, path.clone()); } + let mut module_map = self.module_to_sources_map.write().unwrap(); + module_map + .entry(module_id) + .or_insert_with(BTreeSet::new) + .insert(source_id); + source_id } /// This function provides the file path corresponding to a specified source ID. pub fn get_path(&self, source_id: &SourceId) -> PathBuf { - self.path_map + self.source_to_path_map .read() .unwrap() .get(source_id) .unwrap() .clone() } + + /// This function provides the module ID corresponding to a specified file path. + pub fn get_module_id(&self, path: &PathBuf) -> Option { + self.path_to_module_map.read().unwrap().get(path).cloned() + } }