From 4f8264ac1467b30fc16e008aff1cd88e703bcf72 Mon Sep 17 00:00:00 2001 From: Emily Herbert <17410721+emilyaherbert@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:37:31 -0500 Subject: [PATCH] Use the scoped copy pattern in type checking TypeBinding. --- sway-core/src/decl_engine/ref.rs | 19 ++++ .../semantic_analysis/type_check_context.rs | 21 +++- sway-core/src/type_system/binding.rs | 59 ++++------ sway-core/src/type_system/engine.rs | 104 ++++++++++++------ sway-core/src/type_system/substitute.rs | 2 +- .../language/tuple_access/Forc.lock | 5 - .../language/tuple_access/Forc.toml | 5 +- .../language/tuple_access/src/main.sw | 12 +- 8 files changed, 142 insertions(+), 85 deletions(-) diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index bb9637822ae..56bc79d0534 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -89,6 +89,10 @@ impl DeclRef { &self.subst_list } + pub(crate) fn subst_list_mut(&mut self) -> &mut TypeSubstList { + &mut self.subst_list + } + pub fn decl_span(&self) -> &Span { &self.decl_span } @@ -172,3 +176,18 @@ impl ReplaceFunctionImplementingType for DeclRefFunction { decl_engine.replace(self.id, decl); } } + +impl CreateCopy>> for DeclRef> { + fn scoped_copy(&self, engines: Engines<'_>) -> Self { + DeclRef { + name: self.name.clone(), + id: self.id, + subst_list: self.subst_list.scoped_copy(engines), + decl_span: self.decl_span.clone(), + } + } + + fn unscoped_copy(&self) -> Self { + self.clone() + } +} diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 9035e7aa77d..1cdd0fca38a 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -1,5 +1,5 @@ use crate::{ - decl_engine::DeclEngine, + decl_engine::{DeclEngine, DeclId, DeclRef}, engine_threading::*, language::{parsed::TreeType, Purity}, namespace::Path, @@ -237,6 +237,25 @@ impl<'a> TypeCheckContext<'a> { // Provide some convenience functions around the inner context. + pub(crate) fn combine_type_subst_list_and_args( + &mut self, + decl_ref: &mut DeclRef>, + type_args: &mut [TypeArgument], + enforce_type_args: EnforceTypeArguments, + call_site_span: &Span, + ) -> CompileResult<()> { + let mod_path = self.namespace.mod_path.clone(); + self.type_engine.combine_type_subst_list_and_args( + self.namespace, + self.decl_engine, + &mod_path, + decl_ref, + type_args, + enforce_type_args, + call_site_span, + ) + } + /// Short-hand for calling the `monomorphize` function in the type engine pub(crate) fn monomorphize( &mut self, diff --git a/sway-core/src/type_system/binding.rs b/sway-core/src/type_system/binding.rs index 20bbdf7c3f9..5795ae7efda 100644 --- a/sway-core/src/type_system/binding.rs +++ b/sway-core/src/type_system/binding.rs @@ -240,20 +240,19 @@ impl TypeCheckTypeBinding for TypeBinding { errors ); // Check to see if this is a fn declaration. - let fn_ref = check!( + let mut fn_ref = check!( unknown_decl.to_fn_ref(), return err(warnings, errors), warnings, errors - ); - // Get a new copy from the declaration engine. - let mut new_copy = decl_engine.get_function(fn_ref.id()); + ) + .scoped_copy(engines); match self.type_arguments { - // Monomorphize the copy, in place. TypeArgs::Regular(_) => { + // Monomorphize the copy, in place. check!( - ctx.monomorphize( - &mut new_copy, + ctx.combine_type_subst_list_and_args( + &mut fn_ref, self.type_arguments.to_vec_mut(), EnforceTypeArguments::No, &self.span @@ -264,7 +263,7 @@ impl TypeCheckTypeBinding for TypeBinding { ); } TypeArgs::Prefix(_) => { - // Resolve the type arguments without monomorphizing. + // Resolve the type arguments without using the fn. for type_argument in self.type_arguments.to_vec_mut().iter_mut() { check!( ctx.resolve_type( @@ -280,9 +279,7 @@ impl TypeCheckTypeBinding for TypeBinding { } } } - // Insert the new copy into the declaration engine. - let new_fn_ref = ctx.decl_engine.insert(new_copy, todo!()); - ok((new_fn_ref, None), warnings, errors) + ok((fn_ref, None), warnings, errors) } } @@ -306,18 +303,16 @@ impl TypeCheckTypeBinding for TypeBinding { errors ); // Check to see if this is a struct declaration. - let struct_ref = check!( + let mut struct_ref = check!( unknown_decl.to_struct_ref(engines), return err(warnings, errors), warnings, errors - ); - // Get a new copy from the declaration engine. - let mut new_copy = decl_engine.get_struct(struct_ref.id()); - // Monomorphize the copy, in place. + ) + .scoped_copy(engines); check!( - ctx.monomorphize( - &mut new_copy, + ctx.combine_type_subst_list_and_args( + &mut struct_ref, self.type_arguments.to_vec_mut(), EnforceTypeArguments::No, &self.span @@ -326,13 +321,11 @@ impl TypeCheckTypeBinding for TypeBinding { warnings, errors ); - // Insert the new copy into the declaration engine. - let new_struct_ref = ctx.decl_engine.insert(new_copy, todo!()); // Take any trait items that apply to the old type and copy them to the new type. - let type_id = type_engine.insert(decl_engine, TypeInfo::Struct(new_struct_ref.clone())); + let type_id = type_engine.insert(decl_engine, TypeInfo::Struct(struct_ref.clone())); ctx.namespace .insert_trait_implementation_for_type(engines, type_id); - ok((new_struct_ref, Some(type_id)), warnings, errors) + ok((struct_ref, Some(type_id)), warnings, errors) } } @@ -356,18 +349,16 @@ impl TypeCheckTypeBinding for TypeBinding { errors ); // Check to see if this is a enum declaration. - let enum_ref = check!( + let mut enum_ref = check!( unknown_decl.to_enum_ref(engines), return err(warnings, errors), warnings, errors - ); - // Get a new copy from the declaration engine. - let mut new_copy = decl_engine.get_enum(enum_ref.id()); - // Monomorphize the copy, in place. + ) + .scoped_copy(engines); check!( - ctx.monomorphize( - &mut new_copy, + ctx.combine_type_subst_list_and_args( + &mut enum_ref, self.type_arguments.to_vec_mut(), EnforceTypeArguments::No, &self.span @@ -376,13 +367,11 @@ impl TypeCheckTypeBinding for TypeBinding { warnings, errors ); - // Insert the new copy into the declaration engine. - let new_enum_ref = ctx.decl_engine.insert(new_copy, todo!()); // Take any trait items that apply to the old type and copy them to the new type. - let type_id = type_engine.insert(decl_engine, TypeInfo::Enum(new_enum_ref.clone())); + let type_id = type_engine.insert(decl_engine, TypeInfo::Enum(enum_ref.clone())); ctx.namespace .insert_trait_implementation_for_type(engines, type_id); - ok((new_enum_ref, Some(type_id)), warnings, errors) + ok((enum_ref, Some(type_id)), warnings, errors) } } @@ -393,9 +382,7 @@ impl TypeCheckTypeBinding for TypeBinding { ) -> CompileResult<(DeclRef>, Option)> { let mut warnings = vec![]; let mut errors = vec![]; - let engines = ctx.engines(); - // Grab the declaration. let unknown_decl = check!( ctx.namespace @@ -405,7 +392,6 @@ impl TypeCheckTypeBinding for TypeBinding { warnings, errors ); - // Check to see if this is a const declaration. let const_ref = check!( unknown_decl.to_const_ref(), @@ -413,7 +399,6 @@ impl TypeCheckTypeBinding for TypeBinding { warnings, errors ); - ok((const_ref, None), warnings, errors) } } diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 5cfca50fc4f..5e07e480eba 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -305,6 +305,47 @@ impl TypeEngine { } } + #[allow(clippy::too_many_arguments)] + pub(crate) fn combine_type_subst_list_and_args( + &self, + namespace: &mut Namespace, + decl_engine: &DeclEngine, + mod_path: &Path, + decl_ref: &mut DeclRef>, + type_args: &mut [TypeArgument], + enforce_type_args: EnforceTypeArguments, + call_site_span: &Span, + ) -> CompileResult<()> { + let mut warnings = vec![]; + let mut errors = vec![]; + check!( + self.resolve_type_args( + namespace, + decl_engine, + mod_path, + type_args, + enforce_type_args + ), + return err(warnings, errors), + warnings, + errors + ); + check!( + self.compare_type_subst_list_and_args( + decl_ref.subst_list(), + type_args, + enforce_type_args, + decl_ref.name(), + call_site_span + ), + return err(warnings, errors), + warnings, + errors + ); + decl_ref.subst_list_mut().apply_type_args(type_args); + ok((), warnings, errors) + } + /// Resolve the type of the given [TypeId], replacing any instances of /// [TypeInfo::Custom] with either a monomorphized struct, monomorphized /// enum, or a reference to a type parameter. @@ -313,7 +354,7 @@ impl TypeEngine { &self, decl_engine: &DeclEngine, type_id: TypeId, - span: &Span, + call_site_span: &Span, enforce_type_args: EnforceTypeArguments, type_info_prefix: Option<&Path>, namespace: &mut Namespace, @@ -329,19 +370,6 @@ impl TypeEngine { type_arguments, } => { let mut type_args = type_arguments.unwrap_or_default(); - check!( - self.resolve_type_args( - namespace, - decl_engine, - mod_path, - &mut type_args, - enforce_type_args - ), - return err(warnings, errors), - warnings, - errors - ); - match namespace .root() .resolve_call_path_with_visibility_check(engines, module_path, &call_path) @@ -354,21 +382,26 @@ impl TypeEngine { type_subst_list, decl_span, }) => { + let mut struct_ref = DeclRef::new( + name, + decl_id, + type_subst_list.scoped_copy(engines), + decl_span, + ); check!( - self.compare_type_subst_list_and_args( - type_subst_list.inner(), - &type_args, + self.combine_type_subst_list_and_args( + namespace, + decl_engine, + mod_path, + &mut struct_ref, + &mut type_args, enforce_type_args, - &name, - span + call_site_span ), return err(warnings, errors), warnings, errors ); - let mut type_subst_list = type_subst_list.scoped_copy(engines); - type_subst_list.apply_type_args(type_args); - let struct_ref = DeclRef::new(name, decl_id, type_subst_list, decl_span); let type_id = self.insert(decl_engine, TypeInfo::Struct(struct_ref)); namespace.insert_trait_implementation_for_type(engines, type_id); type_id @@ -379,22 +412,27 @@ impl TypeEngine { type_subst_list, decl_span, }) => { + let mut enum_ref = DeclRef::new( + name, + decl_id, + type_subst_list.scoped_copy(engines), + decl_span, + ); check!( - self.compare_type_subst_list_and_args( - type_subst_list.inner(), - &type_args, + self.combine_type_subst_list_and_args( + namespace, + decl_engine, + mod_path, + &mut enum_ref, + &mut type_args, enforce_type_args, - &name, - span + call_site_span ), return err(warnings, errors), warnings, errors ); - let mut type_subst_list = type_subst_list.scoped_copy(engines); - type_subst_list.apply_type_args(type_args); - let struct_ref = DeclRef::new(name, decl_id, type_subst_list, decl_span); - let type_id = self.insert(decl_engine, TypeInfo::Enum(struct_ref)); + let type_id = self.insert(decl_engine, TypeInfo::Enum(enum_ref)); namespace.insert_trait_implementation_for_type(engines, type_id); type_id } @@ -427,7 +465,7 @@ impl TypeEngine { self.resolve( decl_engine, elem_ty.type_id, - span, + call_site_span, enforce_type_args, None, namespace, @@ -445,7 +483,7 @@ impl TypeEngine { self.resolve( decl_engine, type_argument.type_id, - span, + call_site_span, enforce_type_args, None, namespace, diff --git a/sway-core/src/type_system/substitute.rs b/sway-core/src/type_system/substitute.rs index 4cce5e2be29..3e4b43dfdb5 100644 --- a/sway-core/src/type_system/substitute.rs +++ b/sway-core/src/type_system/substitute.rs @@ -57,7 +57,7 @@ impl TypeSubstList { self.list.get(index) } - pub(crate) fn apply_type_args(&mut self, type_args: Vec) { + pub(crate) fn apply_type_args(&mut self, type_args: &[TypeArgument]) { self.list .iter_mut() .zip(type_args.iter()) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.lock index 47305157dd5..dd4d8c02361 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.lock @@ -1,8 +1,3 @@ -[[package]] -name = 'core' -source = 'path+from-root-A4EDABC95499A7B6' - [[package]] name = 'tuple_access' source = 'member' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.toml index 31bb0e1a8ab..074122c9ee6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/Forc.toml @@ -3,6 +3,7 @@ authors = ["Fuel Labs "] license = "Apache-2.0" name = "tuple_access" entry = "main.sw" +implicit-std = false -[dependencies] -core = { path = "../../../../../../../sway-lib-core" } +#[dependencies] +#core = { path = "../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw index 79bb2f2f505..f1a8b1786d9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/tuple_access/src/main.sw @@ -4,16 +4,16 @@ fn gimme_a_pair() -> (u32, u64) { (1u32, 2u64) } -fn test(a: T, b: E) { - let (_x, _y): (T, E) = (a, b); -} +// fn test(a: T, b: E) { +// let (x, y): (T, E) = (a, b); +// } fn main() -> u32 { let (_foo, _bar) = gimme_a_pair(); let (_x, _y): (u32, bool) = (10, true); //let (x, y): (u32, _) = (42, true); // this generates a parsing error - test(true, false); - test (42, 42); - let (a, (_b, (_c, _d) ) ): (u64, (u32, (bool, str[2]) ) ) = (42u64, (42u32, (true, "ok") ) ); + // test(true, false); + // test (42, 42); + let (a, (b, (c, d) ) ): (u64, (u32, (bool, str[2]) ) ) = (42u64, (42u32, (true, "ok") ) ); a }