From a3dae0924b158e0d642f346e2be083fd1d178446 Mon Sep 17 00:00:00 2001 From: Emily Herbert <17410721+emilyaherbert@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:40:10 -0500 Subject: [PATCH] Move monomorphization conceptually inside of the type engine (#2093) * Do not rely on TypeMapping when type checking declarations. * Prevent leaking types in impls. * Prevent unconstrained type parameters. * WIP * clippy * WIP * Use TypeId in TypeMapping and in TraitMap. * Add semantic type constraints. * Update test case. * fix * Use TypeId inside of resolve_type_with_self and resolve_type_without_self. * clippy * X * Remove self_type from monomorphization. * Add conceptual distinction between replacing TypeInfo::Self and monomorphization. * Bug is fixed. * Add forc.lock. * update * Move test to inside of the SDK. * Fix test cases. * Add lock files. * Fix test. * Move the stuff. * Move monomorphization conceptually inside of the type engine. * Remove commented out test. --- .../semantic_analysis/ast_node/declaration.rs | 2 - .../ast_node/declaration/enum.rs | 11 +- .../ast_node/declaration/function.rs | 16 +- .../function/function_parameter.rs | 4 +- .../ast_node/declaration/monomorphize.rs | 176 ------------------ .../ast_node/declaration/struct.rs | 10 +- .../ast_node/expression/intrinsic_function.rs | 2 +- .../match_expression/typed/typed_scrutinee.rs | 26 ++- .../ast_node/expression/typed_expression.rs | 16 +- .../typed_expression/enum_instantiation.rs | 8 +- .../typed_expression/function_application.rs | 8 +- .../src/semantic_analysis/ast_node/mod.rs | 1 - .../semantic_analysis/namespace/namespace.rs | 36 +--- .../src/semantic_analysis/namespace/root.rs | 22 ++- .../semantic_analysis/type_check_context.rs | 37 ++-- sway-core/src/type_engine/engine.rs | 153 ++++++++++++++- 16 files changed, 228 insertions(+), 300 deletions(-) delete mode 100644 sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs diff --git a/sway-core/src/semantic_analysis/ast_node/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration.rs index c07144e0fe9..80ba1a40d35 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration.rs @@ -2,7 +2,6 @@ mod abi; mod r#enum; mod function; mod impl_trait; -mod monomorphize; mod storage; mod r#struct; mod r#trait; @@ -11,7 +10,6 @@ mod variable; pub use abi::*; pub use function::*; pub use impl_trait::*; -pub(crate) use monomorphize::*; pub use r#enum::*; pub use r#struct::*; pub use r#trait::*; 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 5affad13ed9..c1351efc472 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -1,11 +1,10 @@ use crate::{ error::*, - namespace::*, parse_tree::*, semantic_analysis::*, type_engine::{ - insert_type, look_up_type_id, CopyTypes, CreateTypeId, ReplaceSelfType, TypeId, - TypeMapping, TypeParameter, + insert_type, look_up_type_id, CopyTypes, CreateTypeId, EnforceTypeArguments, + MonomorphizeHelper, ReplaceSelfType, TypeId, TypeMapping, TypeParameter, }, types::{JsonAbiString, ToJsonAbi}, TypeInfo, @@ -63,8 +62,6 @@ impl Spanned for TypedEnumDeclaration { } impl MonomorphizeHelper for TypedEnumDeclaration { - type Output = TypedEnumDeclaration; - fn type_parameters(&self) -> &[TypeParameter] { &self.type_parameters } @@ -72,10 +69,6 @@ impl MonomorphizeHelper for TypedEnumDeclaration { fn name(&self) -> &Ident { &self.name } - - fn monomorphize_inner(self, type_mapping: &TypeMapping, namespace: &mut Items) -> Self::Output { - monomorphize_inner(self, type_mapping, namespace) - } } impl TypedEnumDeclaration { 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 51975261075..3a6aeeef018 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -1,9 +1,7 @@ mod function_parameter; pub use function_parameter::*; -use crate::{ - error::*, namespace::*, parse_tree::*, semantic_analysis::*, style::*, type_engine::*, types::*, -}; +use crate::{error::*, parse_tree::*, semantic_analysis::*, style::*, type_engine::*, types::*}; use fuels_types::{Function, Property}; use sha2::{Digest, Sha256}; use sway_types::{Ident, Span, Spanned}; @@ -74,8 +72,6 @@ impl Spanned for TypedFunctionDeclaration { } impl MonomorphizeHelper for TypedFunctionDeclaration { - type Output = TypedFunctionDeclaration; - fn type_parameters(&self) -> &[TypeParameter] { &self.type_parameters } @@ -83,16 +79,6 @@ impl MonomorphizeHelper for TypedFunctionDeclaration { fn name(&self) -> &Ident { &self.name } - - fn monomorphize_inner( - self, - type_mapping: &TypeMapping, - _namespace: &mut Items, - ) -> Self::Output { - let mut new_decl = self; - new_decl.copy_types(type_mapping); - new_decl - } } impl ToJsonAbi for TypedFunctionDeclaration { 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 1b773f1413f..048adb0a161 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 @@ -1,8 +1,8 @@ use crate::{ error::ok, semantic_analysis::{ - EnforceTypeArguments, IsConstant, TypeCheckContext, TypedExpression, - TypedExpressionVariant, TypedVariableDeclaration, VariableMutability, + IsConstant, TypeCheckContext, TypedExpression, TypedExpressionVariant, + TypedVariableDeclaration, VariableMutability, }, type_engine::*, CompileResult, FunctionParameter, Ident, TypedDeclaration, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs deleted file mode 100644 index 8bb95a756ec..00000000000 --- a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs +++ /dev/null @@ -1,176 +0,0 @@ -use sway_types::{Ident, Span, Spanned}; - -use crate::{error::*, namespace::*, type_engine::*, CompileError, CompileResult, TypeInfo}; - -use super::CreateTypeId; - -/// This type is used to denote if, during monomorphization, the compiler -/// should enforce that type arguments be provided. An example of that -/// might be this: -/// -/// ```ignore -/// struct Point { -/// x: u64, -/// y: u64 -/// } -/// -/// fn add(p1: Point, p2: Point) -> Point { -/// Point { -/// x: p1.x + p2.x, -/// y: p1.y + p2.y -/// } -/// } -/// ``` -/// -/// `EnforeTypeArguments` would require that the type annotations -/// for `p1` and `p2` contain `<...>`. This is to avoid ambiguous definitions: -/// -/// ```ignore -/// fn add(p1: Point, p2: Point) -> Point { -/// Point { -/// x: p1.x + p2.x, -/// y: p1.y + p2.y -/// } -/// } -/// ``` -#[derive(Clone, Copy)] -pub(crate) enum EnforceTypeArguments { - Yes, - No, -} - -pub(crate) trait Monomorphize { - type Output; - - fn monomorphize( - self, - type_arguments: Vec, - enforce_type_arguments: EnforceTypeArguments, - call_site_span: Option<&Span>, - namespace: &mut Root, - module_path: &Path, - ) -> CompileResult; -} - -impl Monomorphize for T -where - T: MonomorphizeHelper + Spanned, -{ - type Output = T; - - fn monomorphize( - self, - mut type_arguments: Vec, - enforce_type_arguments: EnforceTypeArguments, - call_site_span: Option<&Span>, - namespace: &mut Root, - module_path: &Path, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - match (self.type_parameters().is_empty(), type_arguments.is_empty()) { - (true, true) => ok(self, warnings, errors), - (false, true) => { - if let EnforceTypeArguments::Yes = enforce_type_arguments { - let name_span = self.name().span(); - errors.push(CompileError::NeedsTypeArguments { - name: self.name().clone(), - span: call_site_span.unwrap_or(&name_span).clone(), - }); - return err(warnings, errors); - } - let type_mapping = insert_type_parameters(self.type_parameters()); - let module = check!( - namespace.check_submodule_mut(module_path), - return err(warnings, errors), - warnings, - errors - ); - let new_decl = self.monomorphize_inner(&type_mapping, module); - ok(new_decl, warnings, errors) - } - (true, false) => { - let type_arguments_span = type_arguments - .iter() - .map(|x| x.span.clone()) - .reduce(Span::join) - .unwrap_or_else(|| self.span()); - errors.push(CompileError::DoesNotTakeTypeArguments { - name: self.name().clone(), - span: type_arguments_span, - }); - err(warnings, errors) - } - (false, false) => { - for type_argument in type_arguments.iter_mut() { - type_argument.type_id = check!( - namespace.resolve_type( - type_argument.type_id, - &type_argument.span, - enforce_type_arguments, - module_path - ), - insert_type(TypeInfo::ErrorRecovery), - warnings, - errors - ); - } - let type_arguments_span = type_arguments - .iter() - .map(|x| x.span.clone()) - .reduce(Span::join) - .unwrap_or_else(|| self.span()); - if self.type_parameters().len() != type_arguments.len() { - errors.push(CompileError::IncorrectNumberOfTypeArguments { - given: type_arguments.len(), - expected: self.type_parameters().len(), - span: type_arguments_span, - }); - return err(warnings, errors); - } - let type_mapping = insert_type_parameters(self.type_parameters()); - for ((_, interim_type), type_argument) in - type_mapping.iter().zip(type_arguments.iter()) - { - let (mut new_warnings, new_errors) = unify( - *interim_type, - type_argument.type_id, - &type_argument.span, - "Type argument is not assignable to generic type parameter.", - ); - warnings.append(&mut new_warnings); - errors.append(&mut new_errors.into_iter().map(|x| x.into()).collect()); - } - let module = check!( - namespace.check_submodule_mut(module_path), - return err(warnings, errors), - warnings, - errors - ); - let new_decl = self.monomorphize_inner(&type_mapping, module); - ok(new_decl, warnings, errors) - } - } - } -} - -pub(crate) trait MonomorphizeHelper { - type Output; - - fn type_parameters(&self) -> &[TypeParameter]; - fn name(&self) -> &Ident; - fn monomorphize_inner(self, type_mapping: &TypeMapping, namespace: &mut Items) -> Self::Output; -} - -pub(crate) fn monomorphize_inner( - decl: T, - type_mapping: &TypeMapping, - _namespace: &mut Items, -) -> T -where - T: CopyTypes + CreateTypeId, -{ - let mut new_decl = decl; - new_decl.copy_types(type_mapping); - new_decl -} 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 940bc4989c5..0e56fd372f9 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -1,6 +1,4 @@ -use crate::{ - error::*, namespace::*, parse_tree::*, semantic_analysis::*, type_engine::*, types::*, -}; +use crate::{error::*, parse_tree::*, semantic_analysis::*, type_engine::*, types::*}; use fuels_types::Property; use std::hash::{Hash, Hasher}; use sway_types::{Ident, Span, Spanned}; @@ -54,8 +52,6 @@ impl Spanned for TypedStructDeclaration { } impl MonomorphizeHelper for TypedStructDeclaration { - type Output = TypedStructDeclaration; - fn type_parameters(&self) -> &[TypeParameter] { &self.type_parameters } @@ -63,10 +59,6 @@ impl MonomorphizeHelper for TypedStructDeclaration { fn name(&self) -> &Ident { &self.name } - - fn monomorphize_inner(self, type_mapping: &TypeMapping, namespace: &mut Items) -> Self::Output { - monomorphize_inner(self, type_mapping, namespace) - } } impl TypedStructDeclaration { 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 716bfe251a2..510ade465e2 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 @@ -4,7 +4,7 @@ use sway_types::Span; use crate::{ error::{err, ok}, - semantic_analysis::{EnforceTypeArguments, TypeCheckContext}, + semantic_analysis::TypeCheckContext, type_engine::*, types::DeterministicallyAborts, CompileError, CompileResult, IntrinsicFunctionKind, 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 d8e136eba59..cddbaa66b5c 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 @@ -2,8 +2,8 @@ use sway_types::{Ident, Span, Spanned}; use crate::{ error::{err, ok}, - semantic_analysis::{declaration::EnforceTypeArguments, TypeCheckContext, TypedEnumVariant}, - type_engine::{insert_type, CreateTypeId, TypeArgument, TypeId}, + semantic_analysis::{TypeCheckContext, TypedEnumVariant}, + type_engine::{insert_type, CreateTypeId, EnforceTypeArguments, TypeArgument, TypeId}, CompileError, CompileResult, Literal, Scrutinee, StructScrutineeField, TypeInfo, }; @@ -70,15 +70,20 @@ impl TypedScrutinee { warnings, errors ); - let struct_decl = check!( + let mut struct_decl = check!( unknown_decl.expect_struct().cloned(), return err(warnings, errors), warnings, errors ); // monomorphize the struct definition - let struct_decl = check!( - ctx.monomorphize(struct_decl, vec!(), EnforceTypeArguments::No, None), + check!( + ctx.monomorphize( + &mut struct_decl, + vec!(), + EnforceTypeArguments::No, + &struct_name.span() + ), return err(warnings, errors), warnings, errors @@ -164,15 +169,20 @@ impl TypedScrutinee { warnings, errors ); - let enum_decl = check!( + let mut enum_decl = check!( unknown_decl.expect_enum().cloned(), return err(warnings, errors), warnings, errors ); // monomorphize the enum definition - let enum_decl = check!( - ctx.monomorphize(enum_decl, vec!(), EnforceTypeArguments::No, None), + check!( + ctx.monomorphize( + &mut enum_decl, + vec!(), + EnforceTypeArguments::No, + &enum_name.span() + ), return err(warnings, errors), warnings, errors 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 e343c01585e..fc07f43e3b3 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 @@ -976,17 +976,21 @@ impl TypedExpression { warnings, errors ); - let struct_decl = check!( - unknown_decl.expect_struct(), + let mut struct_decl = check!( + unknown_decl.expect_struct().cloned(), return err(warnings, errors), warnings, errors - ) - .clone(); + ); // monomorphize the struct definition - let mut struct_decl = check!( - ctx.monomorphize(struct_decl, type_arguments, EnforceTypeArguments::No, None), + check!( + ctx.monomorphize( + &mut struct_decl, + type_arguments, + EnforceTypeArguments::No, + &call_path.span() + ), return err(warnings, errors), warnings, errors 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 a3b05678932..e91fef07608 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 @@ -7,7 +7,7 @@ use sway_types::{Ident, Spanned}; #[allow(clippy::too_many_arguments)] pub(crate) fn instantiate_enum( mut ctx: TypeCheckContext, - enum_decl: TypedEnumDeclaration, + mut enum_decl: TypedEnumDeclaration, enum_field_name: Ident, args: Vec, type_arguments: Vec, @@ -16,12 +16,12 @@ pub(crate) fn instantiate_enum( let mut errors = vec![]; // monomorphize the enum definition with the type arguments - let enum_decl = check!( + check!( ctx.monomorphize( - enum_decl, + &mut enum_decl, type_arguments, EnforceTypeArguments::No, - Some(&enum_field_name.span()) + &enum_field_name.span() ), return err(warnings, errors), warnings, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index c976b8baaa7..5a2adccf410 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -8,7 +8,7 @@ use sway_types::{state::StateIndex, Spanned}; #[allow(clippy::too_many_arguments)] pub(crate) fn instantiate_function_application( mut ctx: TypeCheckContext, - function_decl: TypedFunctionDeclaration, + mut function_decl: TypedFunctionDeclaration, call_path: CallPath, type_arguments: Vec, arguments: Vec, @@ -17,12 +17,12 @@ pub(crate) fn instantiate_function_application( let mut errors = vec![]; // monomorphize the function declaration - let function_decl = check!( + check!( ctx.monomorphize( - function_decl, + &mut function_decl, type_arguments, EnforceTypeArguments::No, - Some(&call_path.span()) + &call_path.span() ), return err(warnings, errors), warnings, diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 9bd30126728..5f58d938bc6 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -473,7 +473,6 @@ impl TypedAstNode { span.clone(), )); } - let decl = TypedStorageDeclaration::new(fields_buf, span); // insert the storage declaration into the symbols // if there already was one, return an error that duplicate storage diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 4c83348aee5..187e260659d 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -1,15 +1,11 @@ use crate::{ - semantic_analysis::{ - ast_node::TypedExpression, - declaration::{EnforceTypeArguments, Monomorphize, MonomorphizeHelper}, - }, - type_engine::*, - CallPath, CompileResult, Ident, TypedDeclaration, TypedFunctionDeclaration, + semantic_analysis::ast_node::TypedExpression, type_engine::*, CallPath, CompileResult, Ident, + TypedDeclaration, TypedFunctionDeclaration, }; use super::{module::Module, root::Root, submodule_namespace::SubmoduleNamespace, Path, PathBuf}; -use sway_types::{span::Span, Spanned}; +use sway_types::span::Span; use std::collections::VecDeque; @@ -119,32 +115,6 @@ impl Namespace { .resolve_type(type_id, span, EnforceTypeArguments::Yes, &self.mod_path) } - /// Short-hand for calling `monomorphize` from the `Monomorphize` trait, on `root` with the `mod_path`. - pub(crate) fn monomorphize( - &mut self, - decl: T, - mut type_arguments: Vec, - enforce_type_arguments: EnforceTypeArguments, - self_type: Option, - call_site_span: Option<&Span>, - ) -> CompileResult - where - T: MonomorphizeHelper + Spanned, - { - if let Some(self_type) = self_type { - for type_argument in type_arguments.iter_mut() { - type_argument.replace_self_type(self_type); - } - } - decl.monomorphize( - type_arguments, - enforce_type_arguments, - call_site_span, - &mut self.root, - &self.mod_path, - ) - } - /// Short-hand for calling [Root::find_method_for_type] on `root` with the `mod_path`. pub(crate) fn find_method_for_type( &mut self, diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 2ae9a0e1bcc..dd9581c042d 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -83,12 +83,13 @@ impl Root { .ok(&mut warnings, &mut errors) .cloned() { - Some(TypedDeclaration::StructDeclaration(decl)) => { - let new_decl = check!( - decl.monomorphize( + Some(TypedDeclaration::StructDeclaration(mut decl)) => { + check!( + monomorphize( + &mut decl, type_arguments, enforce_type_arguments, - Some(span), + span, self, mod_path // NOTE: Once `TypeInfo::Custom` takes a `CallPath`, this will need to change ), @@ -96,14 +97,15 @@ impl Root { warnings, errors ); - new_decl.create_type_id() + decl.create_type_id() } - Some(TypedDeclaration::EnumDeclaration(decl)) => { - let new_decl = check!( - decl.monomorphize( + Some(TypedDeclaration::EnumDeclaration(mut decl)) => { + check!( + monomorphize( + &mut decl, type_arguments, enforce_type_arguments, - Some(span), + span, self, mod_path // NOTE: Once `TypeInfo::Custom` takes a `CallPath`, this will need to change ), @@ -111,7 +113,7 @@ impl Root { warnings, errors ); - new_decl.create_type_id() + decl.create_type_id() } Some(TypedDeclaration::GenericTypeForFunctionScope { name, type_id }) => { insert_type(TypeInfo::Ref(type_id, name.span())) diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 658fb0d08ec..88130d509e4 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -1,14 +1,13 @@ use crate::{ parse_tree::declaration::Purity, - semantic_analysis::{ - ast_node::Mode, - declaration::{EnforceTypeArguments, MonomorphizeHelper}, - Namespace, + semantic_analysis::{ast_node::Mode, Namespace}, + type_engine::{ + insert_type, monomorphize, unify_with_self, CopyTypes, EnforceTypeArguments, + MonomorphizeHelper, TypeArgument, TypeId, TypeInfo, }, - type_engine::{insert_type, unify_with_self, TypeArgument, TypeId, TypeInfo}, CompileResult, CompileWarning, TypeError, }; -use sway_types::{span::Span, Ident, Spanned}; +use sway_types::{span::Span, Ident}; /// Contextual state tracked and accumulated throughout type-checking. pub struct TypeCheckContext<'ns> { @@ -174,24 +173,24 @@ impl<'ns> TypeCheckContext<'ns> { // Provide some convenience functions around the inner context. - /// Short-hand for calling the `monomorphize` method on `Namespace` with the context's known - /// `self_type`. + /// Short-hand for calling the `monomorphize` function in the type engine pub(crate) fn monomorphize( &mut self, - decl: T, - type_args: Vec, - enforce_type_args: EnforceTypeArguments, - call_site_span: Option<&Span>, - ) -> CompileResult + value: &mut T, + type_arguments: Vec, + enforce_type_arguments: EnforceTypeArguments, + call_site_span: &Span, + ) -> CompileResult<()> where - T: MonomorphizeHelper + Spanned, + T: MonomorphizeHelper + CopyTypes, { - self.namespace.monomorphize( - decl, - type_args, - enforce_type_args, - Some(self.self_type), + monomorphize( + value, + type_arguments, + enforce_type_arguments, call_site_span, + &mut self.namespace.root, + &self.namespace.mod_path, ) } diff --git a/sway-core/src/type_engine/engine.rs b/sway-core/src/type_engine/engine.rs index c7f089ba5ae..bbd30a4ab10 100644 --- a/sway-core/src/type_engine/engine.rs +++ b/sway-core/src/type_engine/engine.rs @@ -1,9 +1,10 @@ use super::*; use crate::concurrent_slab::ConcurrentSlab; +use crate::namespace::{Path, Root}; use crate::type_engine::AbiName; use lazy_static::lazy_static; use sway_types::span::Span; -use sway_types::Spanned; +use sway_types::{Ident, Spanned}; lazy_static! { static ref TYPE_ENGINE: Engine = Engine::default(); @@ -30,6 +31,95 @@ impl Engine { } } + fn monomorphize( + &self, + value: &mut T, + mut type_arguments: Vec, + enforce_type_arguments: EnforceTypeArguments, + call_site_span: &Span, + namespace: &mut Root, + module_path: &Path, + ) -> CompileResult<()> + where + T: MonomorphizeHelper + CopyTypes, + { + let mut warnings = vec![]; + let mut errors = vec![]; + match ( + value.type_parameters().is_empty(), + type_arguments.is_empty(), + ) { + (true, true) => ok((), warnings, errors), + (false, true) => { + if let EnforceTypeArguments::Yes = enforce_type_arguments { + errors.push(CompileError::NeedsTypeArguments { + name: value.name().clone(), + span: call_site_span.clone(), + }); + return err(warnings, errors); + } + let type_mapping = insert_type_parameters(value.type_parameters()); + value.copy_types(&type_mapping); + ok((), warnings, errors) + } + (true, false) => { + let type_arguments_span = type_arguments + .iter() + .map(|x| x.span.clone()) + .reduce(Span::join) + .unwrap_or_else(|| value.name().span()); + errors.push(CompileError::DoesNotTakeTypeArguments { + name: value.name().clone(), + span: type_arguments_span, + }); + err(warnings, errors) + } + (false, false) => { + let type_arguments_span = type_arguments + .iter() + .map(|x| x.span.clone()) + .reduce(Span::join) + .unwrap_or_else(|| value.name().span()); + if value.type_parameters().len() != type_arguments.len() { + errors.push(CompileError::IncorrectNumberOfTypeArguments { + given: type_arguments.len(), + expected: value.type_parameters().len(), + span: type_arguments_span, + }); + return err(warnings, errors); + } + for type_argument in type_arguments.iter_mut() { + type_argument.type_id = check!( + namespace.resolve_type( + type_argument.type_id, + &type_argument.span, + enforce_type_arguments, + module_path + ), + insert_type(TypeInfo::ErrorRecovery), + warnings, + errors + ); + } + let type_mapping = insert_type_parameters(value.type_parameters()); + for ((_, interim_type), type_argument) in + type_mapping.iter().zip(type_arguments.iter()) + { + let (mut new_warnings, new_errors) = unify( + *interim_type, + type_argument.type_id, + &type_argument.span, + "Type argument is not assignable to generic type parameter.", + ); + warnings.append(&mut new_warnings); + errors.append(&mut new_errors.into_iter().map(|x| x.into()).collect()); + } + value.copy_types(&type_mapping); + ok((), warnings, errors) + } + } + } + /// Make the types of two type terms equivalent (or produce an error if /// there is a conflict between them). // @@ -380,6 +470,27 @@ pub(crate) fn look_up_type_id_raw(id: TypeId) -> TypeInfo { TYPE_ENGINE.look_up_type_id_raw(id) } +pub(crate) fn monomorphize( + value: &mut T, + type_arguments: Vec, + enforce_type_arguments: EnforceTypeArguments, + call_site_span: &Span, + namespace: &mut Root, + module_path: &Path, +) -> CompileResult<()> +where + T: MonomorphizeHelper + CopyTypes, +{ + TYPE_ENGINE.monomorphize( + value, + type_arguments, + enforce_type_arguments, + call_site_span, + namespace, + module_path, + ) +} + pub fn unify_with_self( a: TypeId, b: TypeId, @@ -427,3 +538,43 @@ enum NumericCastCompatResult { Compatible, CastableWithWarning(Warning), } + +pub(crate) trait MonomorphizeHelper { + fn name(&self) -> &Ident; + fn type_parameters(&self) -> &[TypeParameter]; +} + +/// This type is used to denote if, during monomorphization, the compiler +/// should enforce that type arguments be provided. An example of that +/// might be this: +/// +/// ```ignore +/// struct Point { +/// x: u64, +/// y: u64 +/// } +/// +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +/// +/// `EnforeTypeArguments` would require that the type annotations +/// for `p1` and `p2` contain `<...>`. This is to avoid ambiguous definitions: +/// +/// ```ignore +/// fn add(p1: Point, p2: Point) -> Point { +/// Point { +/// x: p1.x + p2.x, +/// y: p1.y + p2.y +/// } +/// } +/// ``` +#[derive(Clone, Copy)] +pub(crate) enum EnforceTypeArguments { + Yes, + No, +}