From 28d3500e702337fde0d7e6975d6e0a40aa49ad1d Mon Sep 17 00:00:00 2001 From: Joshua Batty Date: Fri, 10 Nov 2023 19:13:03 +1100 Subject: [PATCH] Add AST module caching support for LSP (#5251) ## Description This PR supersedes #4988 and builds on backend work done by @tritao in #4733. A new `ModuleId` is created for each compiled module. The `SourceId` type now also stores the `ModuleId` that was used to create it. This allows us to perform garbage collection on types in the Declaration and Type engines that refer the provided module. ```rust if let Some(module_id) = engines.se().get_module_id(&path) { engines.clear_module(&module_id); } ``` This method isn't super cheap to call. My tests had this averaging at 54ms. We are currently performing garbage collection on every key stroke in LSP. We should look to have another metric such as only clearing once every 20 keystrokes or so in the future. I ran benchmarking on recompiling the `doc_comments` example 20 times to simulate rapid keystrokes during coding. Here are the results. | Without Caching | With Caching | |---------------------|------------------| | 89.489 s | 4.6236 s | A speed up of 1835.49% is certainly great, yet 4.6 seconds still sounds like an eternity. Still have lots of room to improve but this should improve our current system dramatically. closes #4994 Co-authored-by: Joao Matos --- Cargo.lock | 1 + sway-core/src/concurrent_slab.rs | 22 +- sway-core/src/decl_engine/engine.rs | 31 ++- sway-core/src/engine_threading.rs | 11 +- sway-core/src/language/ty/declaration/abi.rs | 2 +- .../language/ty/declaration/declaration.rs | 3 + .../src/language/ty/declaration/type_alias.rs | 1 + .../src/language/ty/expression/expression.rs | 2 +- .../semantic_analysis/ast_node/code_block.rs | 5 +- .../ast_node/declaration/constant.rs | 4 +- .../ast_node/declaration/declaration.rs | 6 +- .../ast_node/declaration/enum.rs | 5 +- .../ast_node/declaration/function.rs | 12 +- .../function/function_parameter.rs | 4 +- .../ast_node/declaration/impl_trait.rs | 23 +- .../ast_node/declaration/struct.rs | 7 +- .../ast_node/declaration/trait_fn.rs | 2 +- .../ast_node/declaration/trait_type.rs | 12 +- .../ast_node/expression/intrinsic_function.rs | 219 ++++++++++-------- .../match_expression/typed/instantiate.rs | 11 +- .../match_expression/typed/matcher.rs | 2 + .../typed/typed_match_branch.rs | 14 +- .../match_expression/typed/typed_scrutinee.rs | 27 ++- .../ast_node/expression/typed_expression.rs | 141 ++++++----- .../typed_expression/enum_instantiation.rs | 12 +- .../typed_expression/if_expression.rs | 9 +- .../typed_expression/method_application.rs | 11 +- .../typed_expression/struct_instantiation.rs | 14 +- .../src/semantic_analysis/ast_node/mod.rs | 2 +- .../src/semantic_analysis/namespace/root.rs | 8 +- .../semantic_analysis/namespace/trait_map.rs | 4 + .../semantic_analysis/type_check_context.rs | 59 +++-- .../to_parsed_lang/convert_parse_tree.rs | 59 +++-- .../src/type_system/ast_elements/binding.rs | 18 +- .../ast_elements/trait_constraint.rs | 2 +- .../ast_elements/type_parameter.rs | 11 +- sway-core/src/type_system/engine.rs | 85 +++++-- sway-core/src/type_system/info.rs | 24 +- sway-core/src/type_system/mod.rs | 40 ++-- sway-core/src/type_system/priv_prelude.rs | 2 +- .../src/type_system/substitute/subst_map.rs | 53 ++++- sway-core/src/type_system/unify/unifier.rs | 30 ++- sway-lsp/benches/lsp_benchmarks/compile.rs | 11 + sway-lsp/benches/lsp_benchmarks/mod.rs | 4 +- sway-lsp/src/core/session.rs | 50 +++- sway-lsp/src/handlers/notification.rs | 11 +- sway-lsp/src/handlers/request.rs | 30 +++ sway-lsp/src/lib.rs | 1 + sway-lsp/src/lsp_ext.rs | 6 + sway-lsp/src/server.rs | 10 +- sway-lsp/src/server_state.rs | 22 +- sway-lsp/tests/integration/lsp.rs | 25 ++ sway-lsp/tests/lib.rs | 37 +++ sway-types/Cargo.toml | 1 + sway-types/src/lib.rs | 40 ++++ sway-types/src/source_engine.rs | 51 ++-- 56 files changed, 940 insertions(+), 369 deletions(-) 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() + } }