From bf6fdc379bcd52c371da687ccbca051ff8f3d0bb Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Fri, 10 Jun 2022 16:07:26 -0500 Subject: [PATCH 01/17] Do not rely on TypeMapping when type checking declarations. --- .../parse_tree/declaration/type_parameter.rs | 40 ++++-- .../semantic_analysis/ast_node/declaration.rs | 6 +- .../ast_node/declaration/enum.rs | 64 +++------ .../ast_node/declaration/function.rs | 124 +++++------------- .../function/function_parameter.rs | 55 +++++++- .../ast_node/declaration/impl_trait.rs | 16 ++- .../ast_node/declaration/struct.rs | 56 +++----- .../src/semantic_analysis/namespace/root.rs | 7 +- sway-lsp/src/core/traverse_typed_tree.rs | 2 +- 9 files changed, 180 insertions(+), 190 deletions(-) diff --git a/sway-core/src/parse_tree/declaration/type_parameter.rs b/sway-core/src/parse_tree/declaration/type_parameter.rs index 7928ee74981..22f9e87af81 100644 --- a/sway-core/src/parse_tree/declaration/type_parameter.rs +++ b/sway-core/src/parse_tree/declaration/type_parameter.rs @@ -2,10 +2,7 @@ use crate::{error::*, parse_tree::*, semantic_analysis::*, type_engine::*}; use sway_types::{ident::Ident, span::Span, Spanned}; -use std::{ - convert::From, - hash::{Hash, Hasher}, -}; +use std::hash::{Hash, Hasher}; #[derive(Debug, Clone, Eq)] pub struct TypeParameter { @@ -36,14 +33,6 @@ impl PartialEq for TypeParameter { } } -impl From<&TypeParameter> for TypedDeclaration { - fn from(n: &TypeParameter) -> Self { - TypedDeclaration::GenericTypeForFunctionScope { - name: n.name_ident.clone(), - } - } -} - impl CopyTypes for TypeParameter { fn copy_types(&mut self, type_mapping: &TypeMapping) { self.type_id = match look_up_type_id(self.type_id).matches_type_parameter(type_mapping) { @@ -95,6 +84,33 @@ impl ReplaceSelfType for TypeParameter { } } +impl TypeParameter { + pub(crate) fn type_check( + type_parameter: TypeParameter, + namespace: &mut Namespace, + ) -> CompileResult { + let mut warnings = vec![]; + let mut errors = vec![]; + // TODO: add check here to see if the type parameter has a valid name and does not have type parameters + let type_id = insert_type(TypeInfo::UnknownGeneric { + name: type_parameter.name_ident.clone(), + }); + let type_parameter_decl = TypedDeclaration::GenericTypeForFunctionScope { + name: type_parameter.name_ident.clone(), + type_id, + }; + namespace + .insert_symbol(type_parameter.name_ident.clone(), type_parameter_decl) + .ok(&mut warnings, &mut errors); + let type_parameter = TypeParameter { + name_ident: type_parameter.name_ident, + type_id, + trait_constraints: type_parameter.trait_constraints, + }; + ok(type_parameter, warnings, errors) + } +} + #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub(crate) struct TraitConstraint { pub(crate) call_path: CallPath, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration.rs index 5650d78dbf9..c2925349c6b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration.rs @@ -34,7 +34,7 @@ pub enum TypedDeclaration { AbiDeclaration(TypedAbiDeclaration), // If type parameters are defined for a function, they are put in the namespace just for // the body of that function. - GenericTypeForFunctionScope { name: Ident }, + GenericTypeForFunctionScope { name: Ident, type_id: TypeId }, ErrorRecovery, StorageDeclaration(TypedStorageDeclaration), StorageReassignment(TypeCheckedStorageReassignment), @@ -383,8 +383,8 @@ impl TypedDeclaration { TypedDeclaration::StorageDeclaration(decl) => insert_type(TypeInfo::Storage { fields: decl.fields_as_typed_struct_fields(), }), - TypedDeclaration::GenericTypeForFunctionScope { name } => { - insert_type(TypeInfo::UnknownGeneric { name: name.clone() }) + TypedDeclaration::GenericTypeForFunctionScope { name, type_id } => { + insert_type(TypeInfo::Ref(*type_id, name.span())) } decl => { return err( 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 9373240fbab..60fabaefff0 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -3,10 +3,7 @@ use crate::{ namespace::*, parse_tree::*, semantic_analysis::*, - type_engine::{ - insert_type, insert_type_parameters, look_up_type_id, CopyTypes, ReplaceSelfType, TypeId, - TypeMapping, UpdateTypes, - }, + type_engine::{insert_type, look_up_type_id, CopyTypes, ReplaceSelfType, TypeId, TypeMapping}, types::{JsonAbiString, ToJsonAbi}, TypeInfo, }; @@ -89,7 +86,7 @@ impl TypedEnumDeclaration { let EnumDeclaration { name, - mut type_parameters, + type_parameters, variants, span, visibility, @@ -98,28 +95,16 @@ impl TypedEnumDeclaration { // create a namespace for the decl, used to create a scope for generics let mut namespace = namespace.clone(); - // insert type parameters as Unknown types - let type_mapping = insert_type_parameters(&type_parameters); - - // update the types in the type parameters - for type_parameter in type_parameters.iter_mut() { - check!( - type_parameter.update_types(&type_mapping, &mut namespace, self_type), + // type check the type parameters + // insert them into the namespace + let mut new_type_parameters = vec![]; + for type_parameter in type_parameters.into_iter() { + new_type_parameters.push(check!( + TypeParameter::type_check(type_parameter, &mut namespace), return err(warnings, errors), warnings, errors - ); - } - - // insert the generics into the decl namespace and - // check to see if the type parameters shadow one another - for type_parameter in type_parameters.iter() { - check!( - namespace.insert_symbol(type_parameter.name_ident.clone(), type_parameter.into()), - continue, - warnings, - errors - ); + )); } // type check the variants @@ -131,7 +116,6 @@ impl TypedEnumDeclaration { &mut namespace, self_type, variant.span, - &type_mapping ), continue, warnings, @@ -142,7 +126,7 @@ impl TypedEnumDeclaration { // create the enum decl let decl = TypedEnumDeclaration { name, - type_parameters, + type_parameters: new_type_parameters, variants: variants_buf, span, visibility, @@ -234,26 +218,20 @@ impl TypedEnumVariant { namespace: &mut Namespace, self_type: TypeId, span: Span, - type_mapping: &TypeMapping, ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let enum_variant_type = match variant.r#type.matches_type_parameter(type_mapping) { - Some(matching_id) => insert_type(TypeInfo::Ref(matching_id, span)), - None => { - check!( - namespace.resolve_type_with_self( - variant.r#type.clone(), - self_type, - &span, - EnforceTypeArguments::Yes - ), - insert_type(TypeInfo::ErrorRecovery), - warnings, - errors, - ) - } - }; + let enum_variant_type = check!( + namespace.resolve_type_with_self( + variant.r#type.clone(), + self_type, + &span, + EnforceTypeArguments::Yes + ), + insert_type(TypeInfo::ErrorRecovery), + warnings, + errors, + ); ok( TypedEnumVariant { name: variant.name.clone(), 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 9e3d7fe514c..6ebbbb2b15d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -58,11 +58,9 @@ impl CopyTypes for TypedFunctionDeclaration { self.type_parameters .iter_mut() .for_each(|x| x.copy_types(type_mapping)); - self.parameters .iter_mut() .for_each(|x| x.copy_types(type_mapping)); - self.return_type .update_type(type_mapping, &self.return_type_span); self.body.copy_types(type_mapping); @@ -139,10 +137,10 @@ impl TypedFunctionDeclaration { let FunctionDeclaration { name, body, - mut parameters, + parameters, span, return_type, - mut type_parameters, + type_parameters, return_type_span, visibility, purity, @@ -151,88 +149,51 @@ impl TypedFunctionDeclaration { is_snake_case(&name).ok(&mut warnings, &mut errors); opts.purity = purity; - // insert parameters and generic type declarations into namespace + // create a namespace for the function let mut namespace = namespace.clone(); - // insert type parameters as Unknown types - let type_mapping = insert_type_parameters(&type_parameters); - - // update the types in the type parameters - for type_parameter in type_parameters.iter_mut() { - check!( - type_parameter.update_types(&type_mapping, &mut namespace, self_type), + // type check the type parameters + // insert them into the namespace + let mut new_type_parameters = vec![]; + for type_parameter in type_parameters.into_iter() { + new_type_parameters.push(check!( + TypeParameter::type_check(type_parameter, &mut namespace), return err(warnings, errors), warnings, errors - ); + )); } - // check to see if the type parameters shadow one another - for type_parameter in type_parameters.iter() { - check!( - namespace.insert_symbol(type_parameter.name_ident.clone(), type_parameter.into()), + // type check the function parameters + // insert them into the namespace + let mut new_parameters = vec![]; + for parameter in parameters.into_iter() { + new_parameters.push(check!( + TypedFunctionParameter::type_check(parameter, &mut namespace, self_type), continue, warnings, errors - ); - } - - parameters.iter_mut().for_each(|parameter| { - parameter.type_id = - match look_up_type_id(parameter.type_id).matches_type_parameter(&type_mapping) { - Some(matching_id) => { - insert_type(TypeInfo::Ref(matching_id, parameter.type_span.clone())) - } - None => check!( - namespace.resolve_type_with_self( - look_up_type_id(parameter.type_id), - self_type, - ¶meter.type_span, - EnforceTypeArguments::Yes - ), - insert_type(TypeInfo::ErrorRecovery), - warnings, - errors, - ), - }; - }); - - for FunctionParameter { name, type_id, .. } in parameters.clone() { - namespace.insert_symbol( - name.clone(), - TypedDeclaration::VariableDeclaration(TypedVariableDeclaration { - name: name.clone(), - body: TypedExpression { - expression: TypedExpressionVariant::FunctionParameter, - return_type: type_id, - is_constant: IsConstant::No, - span: name.span().clone(), - }, - is_mutable: VariableMutability::Immutable, - const_decl_origin: false, - type_ascription: type_id, - }), - ); + )); } - let return_type = match return_type.matches_type_parameter(&type_mapping) { - Some(matching_id) => insert_type(TypeInfo::Ref(matching_id, return_type_span.clone())), - None => check!( - namespace.resolve_type_with_self( - return_type, - self_type, - &return_type_span, - EnforceTypeArguments::Yes - ), - insert_type(TypeInfo::ErrorRecovery), - warnings, - errors, + // type check the return type + let return_type = check!( + namespace.resolve_type_with_self( + return_type, + self_type, + &return_type_span, + EnforceTypeArguments::Yes ), - }; + insert_type(TypeInfo::ErrorRecovery), + warnings, + errors, + ); + // type check the function body + // // If there are no implicit block returns, then we do not want to type check them, so we // stifle the errors. If there _are_ implicit block returns, we want to type_check them. - let (mut body, _implicit_block_return) = check!( + let (body, _implicit_block_return) = check!( TypedCodeBlock::type_check(TypeCheckArguments { checkee: body, namespace: &mut namespace, @@ -250,29 +211,16 @@ impl TypedFunctionDeclaration { warnings, errors ); - body.copy_types(&type_mapping); - let parameters = parameters - .into_iter() - .map( - |FunctionParameter { - name, - type_id: r#type, - type_span, - }| TypedFunctionParameter { - name, - r#type, - type_span, - }, - ) - .collect::>(); - // handle the return statement(s) + // gather the return statements let return_statements: Vec<&TypedExpression> = body .contents .iter() .flat_map(|node| -> Vec<&TypedReturnStatement> { node.gather_return_statements() }) .map(|TypedReturnStatement { expr, .. }| expr) .collect(); + + // unify the types of the return statements with the function return type for stmt in return_statements { let (mut new_warnings, new_errors) = unify_with_self( stmt.return_type, @@ -288,10 +236,10 @@ impl TypedFunctionDeclaration { let function_decl = TypedFunctionDeclaration { name, body, - parameters, + parameters: new_parameters, span, return_type, - type_parameters, + type_parameters: new_type_parameters, return_type_span, visibility, // if this is for a contract, then it is a contract call 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 26d3ec04d38..2e5943de952 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,6 +1,14 @@ -use crate::{type_engine::*, Ident}; +use crate::{ + error::ok, + semantic_analysis::{ + EnforceTypeArguments, IsConstant, TypedExpression, TypedExpressionVariant, + TypedVariableDeclaration, VariableMutability, + }, + type_engine::*, + CompileResult, FunctionParameter, Ident, Namespace, TypedDeclaration, +}; -use sway_types::span::Span; +use sway_types::{span::Span, Spanned}; #[derive(Debug, Clone, Eq)] pub struct TypedFunctionParameter { @@ -23,3 +31,46 @@ impl CopyTypes for TypedFunctionParameter { self.r#type.update_type(type_mapping, &self.type_span); } } + +impl TypedFunctionParameter { + pub(crate) fn type_check( + parameter: FunctionParameter, + namespace: &mut Namespace, + self_type: TypeId, + ) -> CompileResult { + let mut warnings = vec![]; + let mut errors = vec![]; + let type_id = check!( + namespace.resolve_type_with_self( + look_up_type_id(parameter.type_id), + self_type, + ¶meter.type_span, + EnforceTypeArguments::Yes + ), + insert_type(TypeInfo::ErrorRecovery), + warnings, + errors, + ); + namespace.insert_symbol( + parameter.name.clone(), + TypedDeclaration::VariableDeclaration(TypedVariableDeclaration { + name: parameter.name.clone(), + body: TypedExpression { + expression: TypedExpressionVariant::FunctionParameter, + return_type: type_id, + is_constant: IsConstant::No, + span: parameter.name.span(), + }, + is_mutable: VariableMutability::Immutable, + const_decl_origin: false, + type_ascription: type_id, + }), + ); + let parameter = TypedFunctionParameter { + name: parameter.name, + r#type: type_id, + type_span: parameter.type_span, + }; + ok(parameter, warnings, errors) + } +} 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 f4f377788bc..8aa2d19f234 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 @@ -7,7 +7,8 @@ use crate::{ insert_type, look_up_type_id, resolve_type, unify_with_self, CopyTypes, TypeId, TypeMapping, }, CallPath, CompileError, CompileResult, FunctionDeclaration, FunctionParameter, ImplSelf, - ImplTrait, Namespace, Purity, TypeInfo, TypedDeclaration, TypedFunctionDeclaration, + ImplTrait, Namespace, Purity, TypeInfo, TypeParameter, TypedDeclaration, + TypedFunctionDeclaration, }; use super::TypedTraitFn; @@ -179,8 +180,17 @@ impl TypedImplTrait { // create the namespace for the impl let mut namespace = namespace.clone(); - for type_parameter in type_parameters.iter() { - namespace.insert_symbol(type_parameter.name_ident.clone(), type_parameter.into()); + + // type check the type parameters + // insert them into the namespace + let mut new_type_parameters = vec![]; + for type_parameter in type_parameters.into_iter() { + new_type_parameters.push(check!( + TypeParameter::type_check(type_parameter, &mut namespace), + return err(warnings, errors), + warnings, + errors + )); } let trait_name = CallPath { 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 79608660379..eb511afe161 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -81,7 +81,7 @@ impl TypedStructDeclaration { let StructDeclaration { name, fields, - mut type_parameters, + type_parameters, visibility, span, } = decl; @@ -89,35 +89,23 @@ impl TypedStructDeclaration { // create a namespace for the decl, used to create a scope for generics let mut namespace = namespace.clone(); - // insert type parameters as Unknown types - let type_mapping = insert_type_parameters(&type_parameters); - - // update the types in the type parameters - for type_parameter in type_parameters.iter_mut() { - check!( - type_parameter.update_types(&type_mapping, &mut namespace, self_type), + // type check the type parameters + // insert them into the namespace + let mut new_type_parameters = vec![]; + for type_parameter in type_parameters.into_iter() { + new_type_parameters.push(check!( + TypeParameter::type_check(type_parameter, &mut namespace), return err(warnings, errors), warnings, errors - ); - } - - // insert the generics into the decl namespace and - // check to see if the type parameters shadow one another - for type_parameter in type_parameters.iter() { - check!( - namespace.insert_symbol(type_parameter.name_ident.clone(), type_parameter.into()), - continue, - warnings, - errors - ); + )); } // type check the fields let mut new_fields = vec![]; for field in fields.into_iter() { new_fields.push(check!( - TypedStructField::type_check(field, &mut namespace, self_type, &type_mapping), + TypedStructField::type_check(field, &mut namespace, self_type), return err(warnings, errors), warnings, errors @@ -127,7 +115,7 @@ impl TypedStructDeclaration { // create the struct decl let decl = TypedStructDeclaration { name, - type_parameters, + type_parameters: new_type_parameters, fields: new_fields, visibility, span, @@ -217,24 +205,20 @@ impl TypedStructField { field: StructField, namespace: &mut Namespace, self_type: TypeId, - type_mapping: &TypeMapping, ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let r#type = match field.r#type.matches_type_parameter(type_mapping) { - Some(matching_id) => insert_type(TypeInfo::Ref(matching_id, field.type_span)), - None => check!( - namespace.resolve_type_with_self( - field.r#type, - self_type, - &field.type_span, - EnforceTypeArguments::Yes - ), - insert_type(TypeInfo::ErrorRecovery), - warnings, - errors, + let r#type = check!( + namespace.resolve_type_with_self( + field.r#type, + self_type, + &field.type_span, + EnforceTypeArguments::Yes ), - }; + insert_type(TypeInfo::ErrorRecovery), + warnings, + errors, + ); let field = TypedStructField { name: field.name, r#type, diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 0cad7a76166..d32aa8529b8 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -116,8 +116,8 @@ impl Root { ); new_decl.create_type_id() } - Some(TypedDeclaration::GenericTypeForFunctionScope { name, .. }) => { - insert_type(TypeInfo::UnknownGeneric { name }) + Some(TypedDeclaration::GenericTypeForFunctionScope { name, type_id }) => { + insert_type(TypeInfo::Ref(type_id, name.span())) } _ => { errors.push(CompileError::UnknownTypeName { @@ -216,6 +216,9 @@ impl Root { ); new_decl.create_type_id() } + Some(TypedDeclaration::GenericTypeForFunctionScope { name, type_id }) => { + insert_type(TypeInfo::Ref(type_id, name.span())) + } _ => insert_type(TypeInfo::Unknown), } } diff --git a/sway-lsp/src/core/traverse_typed_tree.rs b/sway-lsp/src/core/traverse_typed_tree.rs index 7ea503f1af2..c76bc67805d 100644 --- a/sway-lsp/src/core/traverse_typed_tree.rs +++ b/sway-lsp/src/core/traverse_typed_tree.rs @@ -158,7 +158,7 @@ fn handle_declaration(declaration: &TypedDeclaration, tokens: &mut TokenMap) { ); } } - TypedDeclaration::GenericTypeForFunctionScope { name } => { + TypedDeclaration::GenericTypeForFunctionScope { name, .. } => { tokens.insert( to_ident_key(name), TokenType::TypedDeclaration(declaration.clone()), From 681ce59f43a4d4d4c09834ecb4fb5fb2c5fc9152 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Fri, 10 Jun 2022 17:29:10 -0500 Subject: [PATCH 02/17] Prevent leaking types in impls. --- sway-core/src/convert_parse_tree.rs | 2 +- sway-core/src/error.rs | 6 +- .../src/parse_tree/declaration/impl_trait.rs | 2 +- .../parse_tree/declaration/type_parameter.rs | 6 + .../ast_node/declaration/function.rs | 25 -- .../ast_node/declaration/impl_trait.rs | 256 ++++++++---------- .../src/semantic_analysis/ast_node/mod.rs | 43 +-- sway-core/src/semantic_analysis/module.rs | 10 +- .../semantic_analysis/node_dependencies.rs | 2 +- sway-core/src/semantic_analysis/program.rs | 10 +- sway-lib-core/src/ops.sw | 20 +- 11 files changed, 164 insertions(+), 218 deletions(-) diff --git a/sway-core/src/convert_parse_tree.rs b/sway-core/src/convert_parse_tree.rs index 06ed48d8eb7..3de6f1f56d1 100644 --- a/sway-core/src/convert_parse_tree.rs +++ b/sway-core/src/convert_parse_tree.rs @@ -715,7 +715,7 @@ fn item_impl_to_declaration( trait_name: path_type_to_call_path(ec, path_type)?, type_implementing_for, type_implementing_for_span, - type_arguments: type_parameters, + type_parameters, functions, block_span, }; diff --git a/sway-core/src/error.rs b/sway-core/src/error.rs index d63ff08f059..9d32968ae08 100644 --- a/sway-core/src/error.rs +++ b/sway-core/src/error.rs @@ -791,12 +791,12 @@ pub enum CompileError { }, #[error("An ABI can only be implemented for the `Contract` type, so this implementation of an ABI for type \"{ty}\" is invalid.")] ImplAbiForNonContract { span: Span, ty: String }, - #[error("The trait function \"{fn_name}\" in trait \"{trait_name}\" expects {num_args} arguments, but the provided implementation only takes {provided_args} arguments.")] + #[error("The function \"{fn_name}\" in trait \"{trait_name}\" is defined with {num_parameters} parameters, but the provided implementation has {provided_parameters} parameters.")] IncorrectNumberOfInterfaceSurfaceFunctionParameters { fn_name: Ident, trait_name: Ident, - num_args: usize, - provided_args: usize, + num_parameters: usize, + provided_parameters: usize, span: Span, }, #[error("This parameter was declared as type {should_be}, but argument of type {provided} was provided.")] diff --git a/sway-core/src/parse_tree/declaration/impl_trait.rs b/sway-core/src/parse_tree/declaration/impl_trait.rs index 326c7976ce5..010177e347a 100644 --- a/sway-core/src/parse_tree/declaration/impl_trait.rs +++ b/sway-core/src/parse_tree/declaration/impl_trait.rs @@ -8,7 +8,7 @@ pub struct ImplTrait { pub trait_name: CallPath, pub(crate) type_implementing_for: TypeInfo, pub(crate) type_implementing_for_span: Span, - pub(crate) type_arguments: Vec, + pub(crate) type_parameters: Vec, pub functions: Vec, // the span of the whole impl trait and block pub(crate) block_span: Span, diff --git a/sway-core/src/parse_tree/declaration/type_parameter.rs b/sway-core/src/parse_tree/declaration/type_parameter.rs index 22f9e87af81..1c342dbe111 100644 --- a/sway-core/src/parse_tree/declaration/type_parameter.rs +++ b/sway-core/src/parse_tree/declaration/type_parameter.rs @@ -91,6 +91,12 @@ impl TypeParameter { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + if !type_parameter.trait_constraints.is_empty() { + errors.push(CompileError::WhereClauseNotYetSupported { + span: type_parameter.name_ident.span(), + }); + return err(warnings, errors); + } // TODO: add check here to see if the type parameter has a valid name and does not have type parameters let type_id = insert_type(TypeInfo::UnknownGeneric { name: type_parameter.name_ident.clone(), 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 6ebbbb2b15d..c73dde2ede9 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -262,31 +262,6 @@ impl TypedFunctionDeclaration { } } - pub(crate) fn replace_self_types(self, self_type: TypeId) -> Self { - TypedFunctionDeclaration { - parameters: self - .parameters - .iter() - .map(|x| { - let mut x = x.clone(); - x.r#type = match look_up_type_id(x.r#type) { - TypeInfo::SelfType => self_type, - _otherwise => x.r#type, - }; - x - }) - .collect(), - span: self.span.clone(), - return_type: match look_up_type_id(self.return_type) { - TypeInfo::SelfType => self_type, - _otherwise => self.return_type, - }, - type_parameters: self.type_parameters.clone(), - return_type_span: self.return_type_span.clone(), - ..self - } - } - pub fn to_fn_selector_value_untruncated(&self) -> CompileResult> { let mut errors = vec![]; let mut warnings = vec![]; 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 8aa2d19f234..c505b211bbe 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 @@ -6,9 +6,8 @@ use crate::{ type_engine::{ insert_type, look_up_type_id, resolve_type, unify_with_self, CopyTypes, TypeId, TypeMapping, }, - CallPath, CompileError, CompileResult, FunctionDeclaration, FunctionParameter, ImplSelf, - ImplTrait, Namespace, Purity, TypeInfo, TypeParameter, TypedDeclaration, - TypedFunctionDeclaration, + CallPath, CompileError, CompileResult, FunctionDeclaration, ImplSelf, ImplTrait, Namespace, + Purity, TypeInfo, TypeParameter, TypedDeclaration, TypedFunctionDeclaration, }; use super::TypedTraitFn; @@ -18,7 +17,7 @@ pub struct TypedImplTrait { pub trait_name: CallPath, pub(crate) span: Span, pub methods: Vec, - pub(crate) type_implementing_for: TypeInfo, + pub(crate) implementing_for_type_id: TypeId, } impl CopyTypes for TypedImplTrait { @@ -34,33 +33,43 @@ impl TypedImplTrait { impl_trait: ImplTrait, namespace: &mut Namespace, opts: TCOpts, - ) -> CompileResult { + ) -> CompileResult<(TypedImplTrait, TypeId)> { let mut errors = vec![]; let mut warnings = vec![]; + let ImplTrait { trait_name, - type_arguments, + type_parameters, functions, type_implementing_for, type_implementing_for_span, block_span, } = impl_trait; - let type_implementing_for = check!( + + // create a namespace for the impl + let mut namespace = namespace.clone(); + + // type check the type parameters + // insert them into the namespace + // TODO: eventually when we support generic traits, we will want to use this + let mut new_type_parameters = vec![]; + for type_parameter in type_parameters.into_iter() { + new_type_parameters.push(check!( + TypeParameter::type_check(type_parameter, &mut namespace), + return err(warnings, errors), + warnings, + errors + )); + } + + // type check the type that we are implementing for + let implementing_for_type_id = check!( namespace.resolve_type_without_self(type_implementing_for), return err(warnings, errors), warnings, errors ); - let type_implementing_for = look_up_type_id(type_implementing_for); - let type_implementing_for_id = insert_type(type_implementing_for.clone()); - for type_argument in type_arguments.iter() { - if !type_argument.trait_constraints.is_empty() { - errors.push(CompileError::WhereClauseNotYetSupported { - span: type_argument.name_ident.span(), - }); - break; - } - } + let impl_trait = match namespace .resolve_call_path(&trait_name) .ok(&mut warnings, &mut errors) @@ -70,14 +79,13 @@ impl TypedImplTrait { let functions_buf = check!( type_check_trait_implementation( &tr.interface_surface, - &functions, &tr.methods, + &functions, &trait_name, - namespace, - type_implementing_for_id, - &block_span, - type_implementing_for_id, + &mut namespace, + implementing_for_type_id, &type_implementing_for_span, + &block_span, Mode::NonAbi, opts, ), @@ -85,50 +93,45 @@ impl TypedImplTrait { warnings, errors ); - // type check all components of the impl trait functions - // add the methods to the namespace - - namespace.insert_trait_implementation( - trait_name.clone(), - match resolve_type(type_implementing_for_id, &type_implementing_for_span) { + let impl_trait = TypedImplTrait { + trait_name, + span: block_span, + methods: functions_buf, + implementing_for_type_id, + }; + let implementing_for_type_id = insert_type( + match resolve_type(implementing_for_type_id, &type_implementing_for_span) { Ok(o) => o, Err(e) => { errors.push(e.into()); return err(warnings, errors); } }, - functions_buf.clone(), ); - TypedImplTrait { - trait_name, - span: block_span, - methods: functions_buf, - type_implementing_for, - } + (impl_trait, implementing_for_type_id) } Some(TypedDeclaration::AbiDeclaration(abi)) => { // if you are comparing this with the `impl_trait` branch above, note that // there are no type arguments here because we don't support generic types // in contract ABIs yet (or ever?) due to the complexity of communicating // the ABI layout in the descriptor file. - if type_implementing_for != TypeInfo::Contract { + if look_up_type_id(implementing_for_type_id) != TypeInfo::Contract { errors.push(CompileError::ImplAbiForNonContract { span: type_implementing_for_span.clone(), - ty: type_implementing_for.to_string(), + ty: implementing_for_type_id.to_string(), }); } let functions_buf = check!( type_check_trait_implementation( &abi.interface_surface, - &functions, &abi.methods, + &functions, &trait_name, - namespace, - type_implementing_for_id, - &block_span, - type_implementing_for_id, + &mut namespace, + implementing_for_type_id, &type_implementing_for_span, + &block_span, Mode::ImplAbiFn, opts, ), @@ -136,20 +139,13 @@ impl TypedImplTrait { warnings, errors ); - // type check all components of the impl trait functions - // add the methods to the namespace - - namespace.insert_trait_implementation( - trait_name.clone(), - look_up_type_id(type_implementing_for_id), - functions_buf.clone(), - ); - TypedImplTrait { + let impl_trait = TypedImplTrait { trait_name, span: block_span, methods: functions_buf, - type_implementing_for, - } + implementing_for_type_id, + }; + (impl_trait, implementing_for_type_id) } Some(_) | None => { errors.push(CompileError::UnknownTrait { @@ -193,6 +189,7 @@ impl TypedImplTrait { )); } + // create the trait name let trait_name = CallPath { prefixes: vec![], suffix: match &type_implementing_for { @@ -202,46 +199,27 @@ impl TypedImplTrait { is_absolute: false, }; - // Resolve the Self type as it's most likely still 'Custom' and use the - // resolved type for self instead. + // type check the type that we are implementing for let implementing_for_type_id = check!( namespace.resolve_type_without_self(type_implementing_for), return err(warnings, errors), warnings, errors ); - let type_implementing_for = look_up_type_id(implementing_for_type_id); - let mut functions_buf: Vec = vec![]; - for mut fn_decl in functions.into_iter() { - // ensure this fn decl's parameters and signature lines up with the - // one in the trait - - // replace SelfType with type of implementor - // i.e. fn add(self, other: u64) -> Self becomes fn - // add(self: u64, other: u64) -> u64 - fn_decl.parameters.iter_mut().for_each( - |FunctionParameter { - ref mut type_id, .. - }| { - if look_up_type_id(*type_id) == TypeInfo::SelfType { - *type_id = implementing_for_type_id; - } - }, - ); - if fn_decl.return_type == TypeInfo::SelfType { - fn_decl.return_type = type_implementing_for.clone(); - } - let args = TypeCheckArguments { - checkee: fn_decl, - namespace: &mut namespace, - return_type_annotation: insert_type(TypeInfo::Unknown), - help_text: "", - self_type: implementing_for_type_id, - mode: Mode::NonAbi, - opts, - }; - functions_buf.push(check!( - TypedFunctionDeclaration::type_check(args), + + // type check the methods inside of the impl block + let mut methods = vec![]; + for fn_decl in functions.into_iter() { + methods.push(check!( + TypedFunctionDeclaration::type_check(TypeCheckArguments { + checkee: fn_decl, + namespace: &mut namespace, + return_type_annotation: insert_type(TypeInfo::Unknown), + help_text: "", + self_type: implementing_for_type_id, + mode: Mode::NonAbi, + opts, + }), continue, warnings, errors @@ -251,8 +229,8 @@ impl TypedImplTrait { let impl_trait = TypedImplTrait { trait_name, span: block_span, - methods: functions_buf, - type_implementing_for, + methods, + implementing_for_type_id, }; ok(impl_trait, warnings, errors) } @@ -260,42 +238,39 @@ impl TypedImplTrait { #[allow(clippy::too_many_arguments)] fn type_check_trait_implementation( - interface_surface: &[TypedTraitFn], + trait_interface_surface: &[TypedTraitFn], + trait_methods: &[FunctionDeclaration], functions: &[FunctionDeclaration], - methods: &[FunctionDeclaration], trait_name: &CallPath, namespace: &mut Namespace, - _self_type: TypeId, + self_type: TypeId, + self_type_span: &Span, block_span: &Span, - type_implementing_for: TypeId, - type_implementing_for_span: &Span, mode: Mode, opts: TCOpts, ) -> CompileResult> { - let mut functions_buf: Vec = vec![]; - let mut processed_fns = std::collections::HashSet::::new(); let mut errors = vec![]; let mut warnings = vec![]; - let self_type_id = type_implementing_for; + + let mut functions_buf: Vec = vec![]; + let mut processed_fns = std::collections::HashSet::::new(); + // this map keeps track of the remaining functions in the // interface surface that still need to be implemented for the // trait to be fully implemented - let mut function_checklist: std::collections::BTreeMap<&Ident, _> = interface_surface + let mut function_checklist: std::collections::BTreeMap<&Ident, _> = trait_interface_surface .iter() .map(|decl| (&decl.name, decl)) .collect(); for fn_decl in functions { - // replace SelfType with type of implementor - // i.e. fn add(self, other: u64) -> Self becomes fn - // add(self: u64, other: u64) -> u64 - + // type check the function declaration let fn_decl = check!( TypedFunctionDeclaration::type_check(TypeCheckArguments { checkee: fn_decl.clone(), namespace, return_type_annotation: insert_type(TypeInfo::Unknown), help_text: Default::default(), - self_type: type_implementing_for, + self_type, mode, opts, }), @@ -303,17 +278,17 @@ fn type_check_trait_implementation( warnings, errors ); - let fn_decl = fn_decl.replace_self_types(self_type_id); - // Ensure that there aren't multiple definitions of this function impl'd. + // Ensure that there aren't multiple definitions of this function impl'd if !processed_fns.insert(fn_decl.name.clone()) { errors.push(CompileError::MultipleDefinitionsOfFunction { name: fn_decl.name.clone(), }); return err(warnings, errors); } + // remove this function from the "checklist" - let trait_fn = match function_checklist.remove(&fn_decl.name) { + let fn_signature = match function_checklist.remove(&fn_decl.name) { Some(trait_fn) => trait_fn, None => { errors.push(CompileError::FunctionNotAPartOfInterfaceSurface { @@ -327,53 +302,50 @@ fn type_check_trait_implementation( // ensure this fn decl's parameters and signature lines up with the one // in the trait - let TypedTraitFn { - name: _, - purity, - parameters, - return_type, - return_type_span: _, - } = trait_fn; - - if fn_decl.parameters.len() != parameters.len() { + if fn_decl.parameters.len() != fn_signature.parameters.len() { errors.push( CompileError::IncorrectNumberOfInterfaceSurfaceFunctionParameters { span: fn_decl.parameters_span(), fn_name: fn_decl.name.clone(), trait_name: trait_name.suffix.clone(), - num_args: parameters.len(), - provided_args: fn_decl.parameters.len(), + num_parameters: fn_signature.parameters.len(), + provided_parameters: fn_decl.parameters.len(), }, ); + continue; } - for (trait_param, fn_decl_param) in parameters.iter().zip(&fn_decl.parameters) { + // unify the types from the parameters of the function declaration + // with the parameters of the function signature + for (fn_signature_param, fn_decl_param) in + fn_signature.parameters.iter().zip(&fn_decl.parameters) + { // TODO use trait constraints as part of the type here to // implement trait constraint solver */ let fn_decl_param_type = fn_decl_param.r#type; - let trait_param_type = trait_param.r#type; - + let fn_signature_param_type = fn_signature_param.r#type; let (mut new_warnings, new_errors) = unify_with_self( fn_decl_param_type, - trait_param_type, - self_type_id, - &trait_param.type_span, + fn_signature_param_type, + self_type, + &fn_signature_param.type_span, "", ); - warnings.append(&mut new_warnings); if !new_errors.is_empty() { errors.push(CompileError::MismatchedTypeInTrait { span: fn_decl_param.type_span.clone(), given: fn_decl_param_type.to_string(), - expected: trait_param_type.to_string(), + expected: fn_signature_param_type.to_string(), }); - break; + continue; } } - if fn_decl.purity != *purity { - errors.push(if *purity == Purity::Pure { + // check to see if the purity of the function declaration is the same + // as the purity of the function signature + if fn_decl.purity != fn_signature.purity { + errors.push(if fn_signature.purity == Purity::Pure { CompileError::TraitDeclPureImplImpure { fn_name: fn_decl.name.clone(), trait_name: trait_name.suffix.clone(), @@ -384,16 +356,18 @@ fn type_check_trait_implementation( CompileError::TraitImplPurityMismatch { fn_name: fn_decl.name.clone(), trait_name: trait_name.suffix.clone(), - attrs: purity.to_attribute_syntax(), + attrs: fn_signature.purity.to_attribute_syntax(), span: fn_decl.span.clone(), } }); } + // unify the return type of the function declaration + // with the return type of the function signature let (mut new_warnings, new_errors) = unify_with_self( - *return_type, fn_decl.return_type, - self_type_id, + fn_signature.return_type, + self_type, &fn_decl.return_type_span, "", ); @@ -401,10 +375,9 @@ fn type_check_trait_implementation( if !new_errors.is_empty() { errors.push(CompileError::MismatchedTypeInTrait { span: fn_decl.return_type_span.clone(), - expected: return_type.to_string(), + expected: fn_signature.return_type.to_string(), given: fn_decl.return_type.to_string(), }); - continue; } @@ -432,7 +405,7 @@ fn type_check_trait_implementation( suffix: trait_name.suffix.clone(), is_absolute: false, }, - match resolve_type(type_implementing_for, type_implementing_for_span) { + match resolve_type(self_type, self_type_span) { Ok(o) => o, Err(e) => { errors.push(e.into()); @@ -441,19 +414,19 @@ fn type_check_trait_implementation( }, functions_buf.clone(), ); - for method in methods { - // type check the method now that the interface - // it depends upon has been implemented - // use a local namespace which has the above interface inserted - // into it as a trait implementation for this + // type check the methods now that the interface + // they depends upon has been implemented + // use a local namespace which has the above interface inserted + // into it as a trait implementation for this + for method in trait_methods { let method = check!( TypedFunctionDeclaration::type_check(TypeCheckArguments { checkee: method.clone(), namespace: &mut impl_trait_namespace, return_type_annotation: insert_type(TypeInfo::Unknown), help_text: Default::default(), - self_type: type_implementing_for, + self_type, mode, opts, }), @@ -461,8 +434,7 @@ fn type_check_trait_implementation( warnings, errors ); - let fn_decl = method.replace_self_types(self_type_id); - functions_buf.push(fn_decl); + functions_buf.push(method); } // check that the implementation checklist is complete diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 37c23f7c22c..d62cb8dd336 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -350,14 +350,14 @@ impl TypedAstNode { typed_const_decl } Declaration::EnumDeclaration(decl) => { - let decl = check!( + let enum_decl = check!( TypedEnumDeclaration::type_check(decl, namespace, self_type), return err(warnings, errors), warnings, errors ); - let name = decl.name.clone(); - let decl = TypedDeclaration::EnumDeclaration(decl); + let name = enum_decl.name.clone(); + let decl = TypedDeclaration::EnumDeclaration(enum_decl); let _ = check!( namespace.insert_symbol(name, decl.clone()), return err(warnings, errors), @@ -367,16 +367,7 @@ impl TypedAstNode { decl } Declaration::FunctionDeclaration(fn_decl) => { - for type_parameter in fn_decl.type_parameters.iter() { - if !type_parameter.trait_constraints.is_empty() { - errors.push(CompileError::WhereClauseNotYetSupported { - span: type_parameter.name_ident.span(), - }); - break; - } - } - - let decl = check!( + let fn_decl = check!( TypedFunctionDeclaration::type_check(TypeCheckArguments { checkee: fn_decl.clone(), namespace, @@ -390,11 +381,10 @@ impl TypedAstNode { warnings, errors ); - namespace.insert_symbol( - decl.name.clone(), - TypedDeclaration::FunctionDeclaration(decl.clone()), - ); - TypedDeclaration::FunctionDeclaration(decl) + let name = fn_decl.name.clone(); + let decl = TypedDeclaration::FunctionDeclaration(fn_decl); + namespace.insert_symbol(name, decl.clone()); + decl } Declaration::TraitDeclaration(trait_decl) => { is_upper_camel_case(&trait_decl.name).ok(&mut warnings, &mut errors); @@ -435,23 +425,20 @@ impl TypedAstNode { ) } Declaration::ImplTrait(impl_trait) => { - let impl_trait = check!( + let (impl_trait, implementing_for_type_id) = check!( TypedImplTrait::type_check_impl_trait(impl_trait, namespace, opts), return err(warnings, errors), warnings, errors ); + namespace.insert_trait_implementation( + impl_trait.trait_name.clone(), + look_up_type_id(implementing_for_type_id), + impl_trait.methods.clone(), + ); TypedDeclaration::ImplTrait(impl_trait) } Declaration::ImplSelf(impl_self) => { - for type_parameter in impl_self.type_parameters.iter() { - if !type_parameter.trait_constraints.is_empty() { - errors.push(CompileError::WhereClauseNotYetSupported { - span: type_parameter.name_ident.span(), - }); - break; - } - } let impl_trait = check!( TypedImplTrait::type_check_impl_self(impl_self, namespace, opts), return err(warnings, errors), @@ -460,7 +447,7 @@ impl TypedAstNode { ); namespace.insert_trait_implementation( impl_trait.trait_name.clone(), - impl_trait.type_implementing_for.clone(), + look_up_type_id(impl_trait.implementing_for_type_id), impl_trait.methods.clone(), ); TypedDeclaration::ImplTrait(impl_trait) diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index c9a4e2a40ab..08307da5d4a 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -119,7 +119,7 @@ fn check_supertraits( if let TypedAstNodeContent::Declaration(TypedDeclaration::ImplTrait(TypedImplTrait { trait_name, span, - type_implementing_for, + implementing_for_type_id, .. })) = &node.content { @@ -133,7 +133,7 @@ fn check_supertraits( if let TypedAstNodeContent::Declaration(TypedDeclaration::ImplTrait( TypedImplTrait { trait_name: search_node_trait_name, - type_implementing_for: search_node_type_implementing_for, + implementing_for_type_id: search_node_type_implementing_for, .. }, )) = &search_node.content @@ -152,8 +152,8 @@ fn check_supertraits( namespace.resolve_call_path(&supertrait.name), ) { return (tr1.name == tr2.name) - && (type_implementing_for - == search_node_type_implementing_for); + && (look_up_type_id(*implementing_for_type_id) + == look_up_type_id(*search_node_type_implementing_for)); } } false @@ -163,7 +163,7 @@ fn check_supertraits( // user code with a single error. errors.push(CompileError::SupertraitImplMissing { supertrait_name: supertrait.name.clone(), - type_name: type_implementing_for.to_string(), + type_name: implementing_for_type_id.to_string(), span: span.clone(), }); errors.push(CompileError::SupertraitImplRequired { diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index af8d8ddcb85..c16c467a9ce 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -335,7 +335,7 @@ impl Dependencies { Declaration::ImplTrait(ImplTrait { trait_name, type_implementing_for, - type_arguments, + type_parameters: type_arguments, functions, .. }) => self diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index a75b0e85835..8ff4c30977b 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -98,9 +98,15 @@ impl TypedProgram { // itself. TypedAstNodeContent::Declaration(TypedDeclaration::ImplTrait(TypedImplTrait { methods, - type_implementing_for: TypeInfo::Contract, + implementing_for_type_id, .. - })) => abi_entries.extend(methods.clone()), + })) if matches!( + look_up_type_id(*implementing_for_type_id), + TypeInfo::Contract + ) => + { + abi_entries.extend(methods.clone()) + } // XXX we're excluding the above ABI methods, is that OK? TypedAstNodeContent::Declaration(decl) => { // Variable and constant declarations don't need a duplicate check. diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index 2ef738a86b0..6e4e0660a94 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -208,16 +208,6 @@ pub trait Eq { } } -trait OrdEq: Ord + Eq { -} { - fn ge(self, other: Self) -> bool { - self.gt(other) || self.eq(other) - } - fn le(self, other: Self) -> bool { - self.lt(other) || self.eq(other) - } -} - impl Eq for bool { fn eq(self, other: Self) -> bool { asm(r1: self, r2: other, r3) { @@ -474,6 +464,16 @@ impl BitwiseXor for b256 { } } +trait OrdEq: Ord + Eq { +} { + fn ge(self, other: Self) -> bool { + self.gt(other) || self.eq(other) + } + fn le(self, other: Self) -> bool { + self.lt(other) || self.eq(other) + } +} + impl OrdEq for u64 { } impl OrdEq for u32 { From 3f0e80c2675587cd6479ed46029709f28da39d95 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Fri, 10 Jun 2022 17:54:25 -0500 Subject: [PATCH 03/17] Prevent unconstrained type parameters. --- sway-core/src/error.rs | 3 + .../ast_node/declaration/impl_trait.rs | 87 ++++++++++++++++--- sway-core/src/type_engine/type_info.rs | 48 +++++++++- test/src/e2e_vm_tests/mod.rs | 1 + .../impl_with_bad_generic/.gitignore | 2 + .../impl_with_bad_generic/Forc.lock | 14 +++ .../impl_with_bad_generic/Forc.toml | 8 ++ .../impl_with_bad_generic/src/main.sw | 32 +++++++ 8 files changed, 182 insertions(+), 13 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/src/main.sw diff --git a/sway-core/src/error.rs b/sway-core/src/error.rs index 9d32968ae08..f40697708e1 100644 --- a/sway-core/src/error.rs +++ b/sway-core/src/error.rs @@ -702,6 +702,8 @@ pub enum CompileError { UnrecognizedOp { op_name: Ident, span: Span }, #[error("Cannot infer type for type parameter \"{ty}\". Insufficient type information provided. Try annotating its type.")] UnableToInferGeneric { ty: String, span: Span }, + #[error("The generic type parameter \"{ty}\" is unconstrained.")] + UnconstrainedGenericParameter { ty: String, span: Span }, #[error("The value \"{val}\" is too large to fit in this 6-bit immediate spot.")] Immediate06TooLarge { val: u64, span: Span }, #[error("The value \"{val}\" is too large to fit in this 12-bit immediate spot.")] @@ -1032,6 +1034,7 @@ impl Spanned for CompileError { UnknownEnumVariant { span, .. } => span.clone(), UnrecognizedOp { span, .. } => span.clone(), UnableToInferGeneric { span, .. } => span.clone(), + UnconstrainedGenericParameter { span, .. } => span.clone(), Immediate06TooLarge { span, .. } => span.clone(), Immediate12TooLarge { span, .. } => span.clone(), Immediate18TooLarge { span, .. } => span.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index c505b211bbe..214ab9f91f6 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 @@ -1,3 +1,5 @@ +use std::collections::{HashMap, HashSet}; + use sway_types::{Ident, Span, Spanned}; use crate::{ @@ -70,6 +72,18 @@ impl TypedImplTrait { errors ); + // check for unconstrained type parameters + check!( + check_for_unconstrained_type_parameters( + &new_type_parameters, + implementing_for_type_id, + &type_implementing_for_span + ), + return err(warnings, errors), + warnings, + errors + ); + let impl_trait = match namespace .resolve_call_path(&trait_name) .ok(&mut warnings, &mut errors) @@ -168,15 +182,25 @@ impl TypedImplTrait { let ImplSelf { type_implementing_for, + type_implementing_for_span, type_parameters, functions, block_span, - .. } = impl_self; // create the namespace for the impl let mut namespace = namespace.clone(); + // create the trait name + let trait_name = CallPath { + prefixes: vec![], + suffix: match &type_implementing_for { + TypeInfo::Custom { name, .. } => name.clone(), + _ => Ident::new_with_override("r#Self", type_implementing_for_span.clone()), + }, + is_absolute: false, + }; + // type check the type parameters // insert them into the namespace let mut new_type_parameters = vec![]; @@ -189,16 +213,6 @@ impl TypedImplTrait { )); } - // create the trait name - let trait_name = CallPath { - prefixes: vec![], - suffix: match &type_implementing_for { - TypeInfo::Custom { name, .. } => name.clone(), - _ => Ident::new_with_override("r#Self", block_span.clone()), - }, - is_absolute: false, - }; - // type check the type that we are implementing for let implementing_for_type_id = check!( namespace.resolve_type_without_self(type_implementing_for), @@ -207,6 +221,18 @@ impl TypedImplTrait { errors ); + // check for unconstrained type parameters + check!( + check_for_unconstrained_type_parameters( + &new_type_parameters, + implementing_for_type_id, + &type_implementing_for_span + ), + return err(warnings, errors), + warnings, + errors + ); + // type check the methods inside of the impl block let mut methods = vec![]; for fn_decl in functions.into_iter() { @@ -450,3 +476,42 @@ fn type_check_trait_implementation( } ok(functions_buf, warnings, errors) } + +fn check_for_unconstrained_type_parameters( + type_parameters: &[TypeParameter], + self_type: TypeId, + self_type_span: &Span, +) -> CompileResult<()> { + let mut warnings = vec![]; + let mut errors = vec![]; + + // check to see that all of the generics that are defined for + // the impl block are actually used in the signature of the block + let mut defined_generics: HashMap = HashMap::from_iter( + type_parameters + .iter() + .map(|x| (look_up_type_id(x.type_id), x.span())), + ); + let generics_in_use = check!( + look_up_type_id(self_type).extract_nested_generics(self_type_span), + HashSet::new(), + warnings, + errors + ); + // TODO: add a lookup in the trait constraints here and add it to + // generics_in_use + for generic in generics_in_use.into_iter() { + defined_generics.remove(&generic); + } + for (k, v) in defined_generics.into_iter() { + errors.push(CompileError::UnconstrainedGenericParameter { + ty: format!("{}", k), + span: v, + }); + } + if errors.is_empty() { + ok((), warnings, errors) + } else { + err(warnings, errors) + } +} diff --git a/sway-core/src/type_engine/type_info.rs b/sway-core/src/type_engine/type_info.rs index cbcad559adf..2e19ffde4cf 100644 --- a/sway-core/src/type_engine/type_info.rs +++ b/sway-core/src/type_engine/type_info.rs @@ -6,6 +6,7 @@ use sway_types::{span::Span, Spanned}; use derivative::Derivative; use std::{ + collections::HashSet, fmt, hash::{Hash, Hasher}, }; @@ -735,7 +736,20 @@ impl TypeInfo { let mut errors = vec![]; let mut all_nested_types = vec![self.clone()]; match self { - TypeInfo::Enum { variant_types, .. } => { + TypeInfo::Enum { + variant_types, + type_parameters, + .. + } => { + for type_parameter in type_parameters.iter() { + let mut nested_types = check!( + look_up_type_id(type_parameter.type_id).extract_nested_types(span), + return err(warnings, errors), + warnings, + errors + ); + all_nested_types.append(&mut nested_types); + } for variant_type in variant_types.iter() { let mut nested_types = check!( look_up_type_id(variant_type.r#type).extract_nested_types(span), @@ -746,7 +760,20 @@ impl TypeInfo { all_nested_types.append(&mut nested_types); } } - TypeInfo::Struct { fields, .. } => { + TypeInfo::Struct { + fields, + type_parameters, + .. + } => { + for type_parameter in type_parameters.iter() { + let mut nested_types = check!( + look_up_type_id(type_parameter.type_id).extract_nested_types(span), + return err(warnings, errors), + warnings, + errors + ); + all_nested_types.append(&mut nested_types); + } for field in fields.iter() { let mut nested_types = check!( look_up_type_id(field.r#type).extract_nested_types(span), @@ -819,6 +846,23 @@ impl TypeInfo { ok(all_nested_types, warnings, errors) } + pub(crate) fn extract_nested_generics(&self, span: &Span) -> CompileResult> { + let mut warnings = vec![]; + let mut errors = vec![]; + let nested_types = check!( + self.clone().extract_nested_types(span), + return err(warnings, errors), + warnings, + errors + ); + let generics = HashSet::from_iter( + nested_types + .into_iter() + .filter(|x| matches!(x, TypeInfo::UnknownGeneric { .. })), + ); + ok(generics, warnings, errors) + } + /// Given a `TypeInfo` `self` and a list of `Ident`'s `subfields`, /// iterate through the elements of `subfields` as `subfield`, /// and recursively apply `subfield` to `self`. diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index b750d73868b..5a7a7ae9a33 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -576,6 +576,7 @@ pub fn run(filter_regex: Option) { "should_fail/repeated_enum_variant", "should_fail/repeated_storage_field", "should_fail/repeated_struct_field", + "should_fail/impl_with_bad_generic", ]; number_of_tests_run += negative_project_names.iter().fold(0, |acc, name| { if filter(name) { diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/.gitignore b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.lock new file mode 100644 index 00000000000..97bf5e1ab87 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-52B9F714BAB9BDCA' +dependencies = [] + +[[package]] +name = 'impl_with_bad_generic' +source = 'root' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-52B9F714BAB9BDCA' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.toml new file mode 100644 index 00000000000..f6297b10b4b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "impl_with_bad_generic" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/src/main.sw new file mode 100644 index 00000000000..ff449e7ab6c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_bad_generic/src/main.sw @@ -0,0 +1,32 @@ +script; + +struct S { } + +impl S { + fn f(self, value: T) { + __size_of::(); + } +} + +enum Option { + Some: T, + None: () +} + +enum OtherOption { + Some: T, + None: () +} + +impl Option { + fn return_false(self, other: OtherOption) -> bool { + false + } +} + +fn main() { + (S{}).f(true); + let a = Option::Some(5u64); + let b = OtherOption::Some(Option::None(())); + let c = a.return_false(b); +} From fde6b33f110ef780de1c4d80cd9e61d12fa64597 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 11:40:06 -0500 Subject: [PATCH 04/17] WIP --- .../parse_tree/declaration/type_parameter.rs | 8 +- .../ast_node/declaration/monomorphize.rs | 25 +- .../src/semantic_analysis/namespace/items.rs | 13 +- .../semantic_analysis/namespace/trait_map.rs | 89 +++++- sway-core/src/type_engine/type_info.rs | 270 ++++++++++++++++++ test/src/e2e_vm_tests/mod.rs | 1 + .../.gitignore | 2 + .../Forc.lock | 14 + .../Forc.toml | 8 + .../src/main.sw | 40 +++ 10 files changed, 450 insertions(+), 20 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw diff --git a/sway-core/src/parse_tree/declaration/type_parameter.rs b/sway-core/src/parse_tree/declaration/type_parameter.rs index 1c342dbe111..cc58e635ee2 100644 --- a/sway-core/src/parse_tree/declaration/type_parameter.rs +++ b/sway-core/src/parse_tree/declaration/type_parameter.rs @@ -2,7 +2,7 @@ use crate::{error::*, parse_tree::*, semantic_analysis::*, type_engine::*}; use sway_types::{ident::Ident, span::Span, Spanned}; -use std::hash::{Hash, Hasher}; +use std::{hash::{Hash, Hasher}, fmt}; #[derive(Debug, Clone, Eq)] pub struct TypeParameter { @@ -84,6 +84,12 @@ impl ReplaceSelfType for TypeParameter { } } +impl fmt::Display for TypeParameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", self.name_ident, self.type_id) + } +} + impl TypeParameter { pub(crate) fn type_check( type_parameter: TypeParameter, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs index f983c1b6f8a..990a813ae3f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs @@ -64,7 +64,7 @@ where fn monomorphize( self, - type_arguments: Vec, + mut type_arguments: Vec, enforce_type_arguments: EnforceTypeArguments, self_type: Option, call_site_span: Option<&Span>, @@ -107,7 +107,6 @@ where err(warnings, errors) } (false, false) => { - let mut type_arguments = type_arguments; for type_argument in type_arguments.iter_mut() { let type_id = match self_type { Some(self_type) => namespace.resolve_type_with_self( @@ -170,6 +169,16 @@ where } } } + if self.name().as_str() == "DoubleIdentity" { + println!( + "\n\ntype_mapping:\n[{}]", + type_mapping + .iter() + .map(|(x, y)| format!("({}, {})", x.type_id, y)) + .collect::>() + .join(", ") + ); + } let module = check!( namespace.check_submodule_mut(module_path), return err(warnings, errors), @@ -177,6 +186,16 @@ where errors ); let new_decl = self.monomorphize_inner(&type_mapping, module); + if new_decl.name().as_str() == "DoubleIdentity" { + println!( + "\n\ndecl.type_parameters():\n[{}]", + new_decl.type_parameters() + .iter() + .map(|x| x.to_string()) + .collect::>() + .join(", ") + ); + } ok(new_decl, warnings, errors) } } @@ -195,11 +214,9 @@ pub(crate) fn monomorphize_inner(decl: T, type_mapping: &TypeMapping, namespa where T: CopyTypes + CreateTypeId, { - let old_type_id = decl.create_type_id(); let mut new_decl = decl; new_decl.copy_types(type_mapping); namespace.copy_methods_to_type( - look_up_type_id(old_type_id), look_up_type_id(new_decl.create_type_id()), type_mapping, ); diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index a5e5d45b4db..84e5de88eba 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -142,22 +142,19 @@ impl Items { self.implemented_traits .get_methods_for_type(look_up_type_id(r#type)) } - - // Given a TypeInfo old_type with a set of methods available to it, make those same methods - // available to TypeInfo new_type. This is useful in situations where old_type is being - // monomorphized to new_type and and we want `get_methods_for_type()` to return the same set of - // methods for new_type as it does for old_type. + + /// Given a [TypeInfo] `new_type`, find all the types for which `new_type` is a subset and grab + /// all the methods for those types, then implement them for `new_type` pub(crate) fn copy_methods_to_type( &mut self, - old_type: TypeInfo, new_type: TypeInfo, type_mapping: &TypeMapping, ) { // This map grabs all (trait name, vec of methods) from self.implemented_traits - // corresponding to `old_type`. + // for which `new_type` is a subset of the existing types let methods = self .implemented_traits - .get_methods_for_type_by_trait(old_type); + .get_methods_for_type_by_trait(new_type.clone()); // Insert into `self.implemented_traits` the contents of the map above but with `new_type` // as the `TypeInfo` key. diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index ecac90906ae..0b80c36afdc 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -44,10 +44,25 @@ impl TraitMap { let warnings = vec![]; let errors = vec![]; let mut methods_map = im::HashMap::new(); + if let TypeInfo::Struct { ref name, .. } = type_implementing_for { + if name.as_str() == "DoubleIdentity" { + println!(">>\n\tinserting for {}", type_implementing_for); + } + } for method in methods.into_iter() { let method_name = method.name.as_str().to_string(); + if let TypeInfo::Struct { ref name, .. } = type_implementing_for { + if name.as_str() == "DoubleIdentity" { + println!("\t{}", method_name); + } + } methods_map.insert(method_name, method); } + if let TypeInfo::Struct { ref name, .. } = type_implementing_for { + if name.as_str() == "DoubleIdentity" { + println!(">>"); + } + } self.trait_map .push_back(((trait_name, type_implementing_for), methods_map)); ok((), warnings, errors) @@ -93,9 +108,33 @@ impl TraitMap { if r#type == TypeInfo::ErrorRecovery { return methods; } - for ((_, type_info), l_methods) in self.trait_map.iter() { + if let TypeInfo::Struct { ref name, .. } = r#type { + if name.as_str() == "DoubleIdentity" { + println!( + "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type\n\nfound:\n[", + r#type + ); + } + } + for ((_, type_info), trait_methods) in self.trait_map.iter() { if *type_info == r#type { - methods.append(&mut l_methods.values().cloned().collect()); + let mut trait_methods: Vec = trait_methods.values().cloned().collect(); + if let TypeInfo::Struct { ref name, .. } = type_info { + if name.as_str() == "DoubleIdentity" { + println!("{}\n^ hit", type_info); + for trait_method in trait_methods.iter() { + println!("\t{}", trait_method.name); + } + } + } + methods.append(&mut trait_methods); + // } + } else { + if let TypeInfo::Struct { ref name, .. } = type_info { + if name.as_str() == "DoubleIdentity" { + println!("{}", type_info); + } + } } } methods @@ -110,14 +149,50 @@ impl TraitMap { if r#type == TypeInfo::ErrorRecovery { return methods; } - for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { - if *type_info == r#type { - methods.insert( - (*trait_name).clone(), - trait_methods.values().cloned().collect(), + if let TypeInfo::Struct { ref name, .. } = r#type { + if name.as_str() == "DoubleIdentity" { + println!( + "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type_by_trait\n\nfound:\n[", + r#type ); } } + for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { + if r#type.is_subset_of(type_info) { + let mut trait_methods: Vec = trait_methods.values().cloned().collect(); + if let TypeInfo::Struct { ref name, .. } = type_info { + if name.as_str() == "DoubleIdentity" { + println!("{}\n^ hit", type_info); + for trait_method in trait_methods.iter() { + println!("\t{}", trait_method.name); + } + } + } + match methods.get_mut(trait_name) { + Some(v) => { + v.append(&mut trait_methods); + }, + _ => { + methods.insert( + (*trait_name).clone(), + trait_methods, + ); + } + } + // } + } else { + if let TypeInfo::Struct { ref name, .. } = type_info { + if name.as_str() == "DoubleIdentity" { + println!("{}", type_info); + } + } + } + } + if let TypeInfo::Struct { ref name, .. } = r#type { + if name.as_str() == "DoubleIdentity" { + println!("]"); + } + } methods } } diff --git a/sway-core/src/type_engine/type_info.rs b/sway-core/src/type_engine/type_info.rs index 2e19ffde4cf..dbf7717a836 100644 --- a/sway-core/src/type_engine/type_info.rs +++ b/sway-core/src/type_engine/type_info.rs @@ -863,6 +863,169 @@ impl TypeInfo { ok(generics, warnings, errors) } + /// Given two `TypeInfo`'s `self` and `other`, check to see if `self` is + /// unidirectionally a subset of `other`. + /// + /// `self` is a subset of `other` if it can be generalized over `other`. + /// For example, the generic `T` is a subset of the generic `F` because + /// anything of the type `T` could also be of the type `F` (minus any + /// external context that may make this statement untrue). + /// + /// Given: + /// + /// ```ignore + /// struct Data { + /// x: T, + /// y: F, + /// } + /// ``` + /// + /// the type `Data` is a subset of any generic type. + /// + /// Given: + /// + /// ```ignore + /// struct Data { + /// x: T, + /// y: F, + /// } + /// + /// impl Data { } + /// ``` + /// + /// the type `Data` is a subset of `Data`, but _`Data` is + /// not a subset of `Data`_. + /// + /// Given: + /// + /// ```ignore + /// struct Data { + /// x: T, + /// y: F, + /// } + /// + /// impl Data { } + /// + /// fn dummy() { + /// // the type of foo is Data + /// let foo = Data { + /// x: true, + /// y: 1u64 + /// }; + /// // the type of bar is Data + /// let bar = Data { + /// x: 0u8, + /// y: 0u8 + /// }; + /// } + /// ``` + /// + /// | type: | is subset of: | is not a subset of: | + /// |-------------------|----------------------------------------------|---------------------| + /// | `Data` | `Data`, any generic type | | + /// | `Data` | any generic type | `Data` | + /// | `Data` | `Data`, any generic type | `Data` | + /// | `Data` | `Data`, `Data`, any generic type | | + /// + pub(crate) fn is_subset_of(&self, other: &TypeInfo) -> bool { + match (self, other) { + // any type is the subset of a generic + (_, Self::UnknownGeneric { .. }) => true, + (Self::Ref(l, _), Self::Ref(r, _)) => { + look_up_type_id(*l).is_subset_of(&look_up_type_id(*r)) + } + (Self::Array(l0, l1), Self::Array(r0, r1)) => { + look_up_type_id(*l0).is_subset_of(&look_up_type_id(*r0)) && l1 == r1 + } + ( + Self::Custom { + name: l_name, + type_arguments: l_type_args, + }, + Self::Custom { + name: r_name, + type_arguments: r_type_args, + }, + ) => { + let l_types = l_type_args + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + let r_types = r_type_args + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + l_name == r_name && types_are_subset_of(&l_types, &r_types) + } + ( + Self::Enum { + name: l_name, + variant_types: l_variant_types, + type_parameters: l_type_parameters, + }, + Self::Enum { + name: r_name, + variant_types: r_variant_types, + type_parameters: r_type_parameters, + }, + ) => { + let l_names = l_variant_types + .iter() + .map(|x| x.name.clone()) + .collect::>(); + let r_names = r_variant_types + .iter() + .map(|x| x.name.clone()) + .collect::>(); + let l_types = l_type_parameters + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + let r_types = r_type_parameters + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + l_name == r_name && l_names == r_names && types_are_subset_of(&l_types, &r_types) + } + ( + Self::Struct { + name: l_name, + fields: l_fields, + type_parameters: l_type_parameters, + }, + Self::Struct { + name: r_name, + fields: r_fields, + type_parameters: r_type_parameters, + }, + ) => { + let l_names = l_fields.iter().map(|x| x.name.clone()).collect::>(); + let r_names = r_fields.iter().map(|x| x.name.clone()).collect::>(); + let l_types = l_type_parameters + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + let r_types = r_type_parameters + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + l_name == r_name && l_names == r_names && types_are_subset_of(&l_types, &r_types) + } + (Self::Tuple(l_types), Self::Tuple(r_types)) => { + let l_types = l_types + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + let r_types = r_types + .iter() + .map(|x| look_up_type_id(x.type_id)) + .collect::>(); + types_are_subset_of(&l_types, &r_types) + } + (a, b) => a == b, + } + } + /// Given a `TypeInfo` `self` and a list of `Ident`'s `subfields`, /// iterate through the elements of `subfields` as `subfield`, /// and recursively apply `subfield` to `self`. @@ -982,6 +1145,113 @@ impl TypeInfo { } } +/// Given two lists of `TypeInfo`'s `left` and `right`, check to see if +/// `left` is a subset of `right`. +/// +/// `left` is a subset of `right` if the following invariants are true: +/// 1. `left` and and `right` are of the same length _n_ +/// 2. For every _i_ in [0, n), `left`áµ¢ is a subset of `right`áµ¢ +/// 3. The elements of `left` satisfy the trait constraints of `right` +/// +/// A property that falls of out these constraints are that if `left` and +/// `right` are empty, then `left` is a subset of `right`. +/// +/// Given: +/// +/// ```ignore +/// left: [T] +/// right: [T, F] +/// ``` +/// +/// `left` is not a subset of `right` because it violates invariant #1. +/// +/// Given: +/// +/// ```ignore +/// left: [T, F] +/// right: [bool, F] +/// ``` +/// +/// `left` is not a subset of `right` because it violates invariant #2. +/// +/// Given: +/// +/// ```ignore +/// left: [T, F] +/// right: [T, T] +/// ``` +/// +/// `left` is not a subset of `right` because it violates invariant #3. +/// +/// Given: +/// +/// ```ignore +/// left: [T, T] +/// right: [T, F] +/// ``` +/// +/// `left` is a subset of `right`. +/// +/// Given: +/// +/// ```ignore +/// left: [bool, T] +/// right: [T, F] +/// ``` +/// +/// `left` is a subset of `right`. +/// +/// Given: +/// +/// ```ignore +/// left: [Data, Data] +/// right: [Data, Data] +/// ``` +/// +/// `left` is a subset of `right`. +/// +fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { + // invariant 1. `left` and and `right` are of the same length _n_ + if left.len() != right.len() { + return false; + } + + // if `left` and `right` are empty, `left` is inherently a subset of `right` + if left.is_empty() && right.is_empty() { + return true; + } + + // invariant 2. For every _i_ in [0, n), `left`áµ¢ is a subset of `right`áµ¢ + for (l, r) in left.iter().zip(right.iter()) { + if !l.is_subset_of(r) { + return false; + } + } + + // invariant 3. The elements of `left` satisfy the trait constraints of `right` + let mut constraints = vec![]; + for i in 0..(right.len() - 1) { + for j in (i + 1)..right.len() { + let a = right.get(i).unwrap(); + let b = right.get(j).unwrap(); + if a == b { + // if a and b are the same type + constraints.push((i, j)); + } + } + } + for (i, j) in constraints.into_iter() { + let a = left.get(i).unwrap(); + let b = left.get(j).unwrap(); + if a != b { + return false; + } + } + + // if all of the invariants are met, then `self` is a subset of `other`! + true +} + fn print_inner_types(name: String, inner_types: impl Iterator) -> String { let inner_types = inner_types.map(|x| x.to_string()).collect::>(); format!( diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 5a7a7ae9a33..c2883befd0a 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -577,6 +577,7 @@ pub fn run(filter_regex: Option) { "should_fail/repeated_storage_field", "should_fail/repeated_struct_field", "should_fail/impl_with_bad_generic", + "should_fail/impl_with_semantic_type_constraints", ]; number_of_tests_run += negative_project_names.iter().fold(0, |acc, name| { if filter(name) { diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/.gitignore b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock new file mode 100644 index 00000000000..39a70d597e7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-C569FB5C26218A1B' +dependencies = [] + +[[package]] +name = 'impl_with_semantic_type_constraints' +source = 'root' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-C569FB5C26218A1B' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml new file mode 100644 index 00000000000..e21f59c2882 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "impl_with_semantic_type_constraints" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw new file mode 100644 index 00000000000..e73bfbecd6c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw @@ -0,0 +1,40 @@ +script; + +struct DoubleIdentity { + first: T, + second: F, +} + +impl DoubleIdentity { + fn get_first(self) -> T { + self.first + } +} + +impl DoubleIdentity { + fn get_second(self) -> F { + self.second + } +} + +impl DoubleIdentity { + fn add(self) -> u8 { + self.first + self.second + } +} + +fn main() { + let a = DoubleIdentity { + first: 0u8, + second: 1u8 + }; + let b = a.get_first(); + let c = a.get_second(); + let d = a.add(); + + let e = DoubleIdentity { + first: true, + second: "hi" + }; + let f = e.get_second(); +} From 60ed36060c98991fc976ed403bc84a7cf2190709 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 13:35:10 -0500 Subject: [PATCH 05/17] clippy --- .../src/semantic_analysis/ast_node/declaration/impl_trait.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 ea49ce5b822..28a88303848 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 @@ -6,9 +6,8 @@ use crate::{ type_engine::{ insert_type, look_up_type_id, resolve_type, unify_with_self, CopyTypes, TypeId, TypeMapping, }, - CallPath, CompileError, CompileResult, FunctionDeclaration, FunctionParameter, ImplSelf, - ImplTrait, Namespace, Purity, TypeInfo, TypeParameter, TypedDeclaration, - TypedFunctionDeclaration, + CallPath, CompileError, CompileResult, FunctionDeclaration, ImplSelf, ImplTrait, Namespace, + Purity, TypeInfo, TypeParameter, TypedDeclaration, TypedFunctionDeclaration, }; use super::TypedTraitFn; From 6650bf2325dd17ca80cdaa90308631168cc23342 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 15:14:03 -0500 Subject: [PATCH 06/17] WIP --- .../ast_node/declaration/monomorphize.rs | 10 +- sway-core/src/semantic_analysis/const_eval.rs | 2 +- .../src/semantic_analysis/namespace/items.rs | 36 ++-- .../semantic_analysis/namespace/trait_map.rs | 157 +++++++++--------- sway-core/src/type_engine/type_info.rs | 4 +- sway-core/src/type_engine/type_mapping.rs | 108 +++++++++++- .../Forc.lock | 12 +- .../Forc.toml | 4 +- .../src/main.sw | 10 +- 9 files changed, 221 insertions(+), 122 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs index c69e2a02be9..dcdc6db6c40 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs @@ -174,7 +174,7 @@ where "\n\ntype_mapping:\n[{}]", type_mapping .iter() - .map(|(x, y)| format!("({}, {})", x.type_id, y)) + .map(|(x, y)| format!("({}, {})", x, y)) .collect::>() .join(", ") ); @@ -211,12 +211,16 @@ pub(crate) trait MonomorphizeHelper { 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 +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); - namespace.copy_methods_to_type(look_up_type_id(new_decl.create_type_id()), type_mapping); + //namespace.copy_methods_to_type(look_up_type_id(new_decl.create_type_id()), type_mapping); new_decl } diff --git a/sway-core/src/semantic_analysis/const_eval.rs b/sway-core/src/semantic_analysis/const_eval.rs index 8d3cc804f83..bcae48c5f59 100644 --- a/sway-core/src/semantic_analysis/const_eval.rs +++ b/sway-core/src/semantic_analysis/const_eval.rs @@ -117,7 +117,7 @@ pub fn const_eval_typed_expr( TypedExpressionVariant::StructExpression { fields, .. } => { let (field_typs, field_vals): (Vec<_>, Vec<_>) = fields .iter() - .filter_map(|TypedStructExpressionField { name: _, value }| { + .filter_map(|TypedStructExpressionField { name: _, value, .. }| { const_eval_typed_expr(context, module, known_consts, value) .map(|cv| (value.return_type, cv)) }) diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index dc92d02338d..2d9eb7ea327 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -135,25 +135,25 @@ impl Items { .get_methods_for_type(look_up_type_id(r#type)) } - /// Given a [TypeInfo] `new_type`, find all the types for which `new_type` is a subset and grab - /// all the methods for those types, then implement them for `new_type` - pub(crate) fn copy_methods_to_type(&mut self, new_type: TypeInfo, type_mapping: &TypeMapping) { - // This map grabs all (trait name, vec of methods) from self.implemented_traits - // for which `new_type` is a subset of the existing types - let methods = self - .implemented_traits - .get_methods_for_type_by_trait(new_type.clone()); + // /// Given a [TypeInfo] `new_type`, find all the types for which `new_type` is a subset and grab + // /// all the methods for those types, then implement them for `new_type` + // pub(crate) fn copy_methods_to_type(&mut self, new_type: TypeInfo, type_mapping: &TypeMapping) { + // // This map grabs all (trait name, vec of methods) from self.implemented_traits + // // for which `new_type` is a subset of the existing types + // let methods = self + // .implemented_traits + // .get_methods_for_type_by_trait(new_type.clone()); - // Insert into `self.implemented_traits` the contents of the map above but with `new_type` - // as the `TypeInfo` key. - for (trait_name, mut trait_methods) in methods.into_iter() { - trait_methods - .iter_mut() - .for_each(|method| method.copy_types(type_mapping)); - self.implemented_traits - .insert(trait_name, new_type.clone(), trait_methods); - } - } + // // Insert into `self.implemented_traits` the contents of the map above but with `new_type` + // // as the `TypeInfo` key. + // for (trait_name, mut trait_methods) in methods.into_iter() { + // trait_methods + // .iter_mut() + // .for_each(|method| method.copy_types(type_mapping)); + // self.implemented_traits + // .insert(trait_name, new_type.clone(), trait_methods); + // } + // } pub(crate) fn get_canonical_path(&self, symbol: &Ident) -> &[Ident] { self.use_synonyms.get(symbol).map(|v| &v[..]).unwrap_or(&[]) diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 03d915cc2c0..c9773bdfce4 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -97,90 +97,89 @@ impl TraitMap { if r#type == TypeInfo::ErrorRecovery { return methods; } - if let TypeInfo::Struct { ref name, .. } = r#type { - if name.as_str() == "DoubleIdentity" { - println!( - "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type\n\nfound:\n[", - r#type - ); - } - } + // if let TypeInfo::Struct { ref name, .. } = r#type { + // if name.as_str() == "DoubleIdentity" { + // println!( + // "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type\n\nfound:\n[", + // r#type + // ); + // } + // } for ((_, type_info), trait_methods) in self.trait_map.iter() { - if *type_info == r#type { - let mut trait_methods: Vec = - trait_methods.values().cloned().collect(); - if let TypeInfo::Struct { ref name, .. } = type_info { - if name.as_str() == "DoubleIdentity" { - println!("{}\n^ hit", type_info); - for trait_method in trait_methods.iter() { - println!("\t{}", trait_method.name); - } - } - } + if r#type.is_subset_of(type_info) { + let mut trait_methods = trait_methods.values().cloned().collect(); + // if let TypeInfo::Struct { ref name, .. } = type_info { + // if name.as_str() == "DoubleIdentity" { + // println!("{}\n^ hit", type_info); + // for trait_method in trait_methods.iter() { + // println!("\t{}", trait_method.name); + // } + // } + // } methods.append(&mut trait_methods); - // } - } else { - if let TypeInfo::Struct { ref name, .. } = type_info { - if name.as_str() == "DoubleIdentity" { - println!("{}", type_info); - } - } } - } - methods - } - - pub(crate) fn get_methods_for_type_by_trait( - &self, - r#type: TypeInfo, - ) -> HashMap> { - let mut methods: HashMap> = HashMap::new(); - // small performance gain in bad case - if r#type == TypeInfo::ErrorRecovery { - return methods; - } - if let TypeInfo::Struct { ref name, .. } = r#type { - if name.as_str() == "DoubleIdentity" { - println!( - "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type_by_trait\n\nfound:\n[", - r#type - ); - } - } - for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { - if r#type.is_subset_of(type_info) { - let mut trait_methods: Vec = - trait_methods.values().cloned().collect(); - if let TypeInfo::Struct { ref name, .. } = type_info { - if name.as_str() == "DoubleIdentity" { - println!("{}\n^ hit", type_info); - for trait_method in trait_methods.iter() { - println!("\t{}", trait_method.name); - } - } - } - match methods.get_mut(trait_name) { - Some(v) => { - v.append(&mut trait_methods); - } - _ => { - methods.insert((*trait_name).clone(), trait_methods); - } - } + // } else { + // if let TypeInfo::Struct { ref name, .. } = type_info { + // if name.as_str() == "DoubleIdentity" { + // println!("{}", type_info); + // } + // } // } - } else { - if let TypeInfo::Struct { ref name, .. } = type_info { - if name.as_str() == "DoubleIdentity" { - println!("{}", type_info); - } - } - } - } - if let TypeInfo::Struct { ref name, .. } = r#type { - if name.as_str() == "DoubleIdentity" { - println!("]"); - } } methods } + + // pub(crate) fn get_methods_for_type_by_trait( + // &self, + // r#type: TypeInfo, + // ) -> HashMap> { + // let mut methods: HashMap> = HashMap::new(); + // // small performance gain in bad case + // if r#type == TypeInfo::ErrorRecovery { + // return methods; + // } + // if let TypeInfo::Struct { ref name, .. } = r#type { + // if name.as_str() == "DoubleIdentity" { + // println!( + // "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type_by_trait\n\nfound:\n[", + // r#type + // ); + // } + // } + // for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { + // if r#type.is_subset_of(type_info) { + // let mut trait_methods: Vec = + // trait_methods.values().cloned().collect(); + // if let TypeInfo::Struct { ref name, .. } = type_info { + // if name.as_str() == "DoubleIdentity" { + // println!("{}\n^ hit", type_info); + // for trait_method in trait_methods.iter() { + // println!("\t{}", trait_method.name); + // } + // } + // } + // match methods.get_mut(trait_name) { + // Some(v) => { + // v.append(&mut trait_methods); + // } + // _ => { + // methods.insert((*trait_name).clone(), trait_methods); + // } + // } + // // } + // } else { + // if let TypeInfo::Struct { ref name, .. } = type_info { + // if name.as_str() == "DoubleIdentity" { + // println!("{}", type_info); + // } + // } + // } + // } + // if let TypeInfo::Struct { ref name, .. } = r#type { + // if name.as_str() == "DoubleIdentity" { + // println!("]"); + // } + // } + // methods + // } } diff --git a/sway-core/src/type_engine/type_info.rs b/sway-core/src/type_engine/type_info.rs index b3aef1ca850..2f8402745b3 100644 --- a/sway-core/src/type_engine/type_info.rs +++ b/sway-core/src/type_engine/type_info.rs @@ -557,7 +557,7 @@ impl TypeInfo { match self { TypeInfo::Custom { .. } => { for (param, ty_id) in mapping.iter() { - if look_up_type_id(param.type_id) == *self { + if look_up_type_id(*param) == *self { return Some(*ty_id); } } @@ -565,7 +565,7 @@ impl TypeInfo { } TypeInfo::UnknownGeneric { .. } => { for (param, ty_id) in mapping.iter() { - if look_up_type_id(param.type_id) == *self { + if look_up_type_id(*param) == *self { return Some(*ty_id); } } diff --git a/sway-core/src/type_engine/type_mapping.rs b/sway-core/src/type_engine/type_mapping.rs index e87f23fcb1d..2e944906cab 100644 --- a/sway-core/src/type_engine/type_mapping.rs +++ b/sway-core/src/type_engine/type_mapping.rs @@ -2,14 +2,14 @@ use crate::TypeParameter; use super::*; -pub(crate) type TypeMapping = Vec<(TypeParameter, TypeId)>; +pub(crate) type TypeMapping = Vec<(TypeId, TypeId)>; pub(crate) fn insert_type_parameters(type_parameters: &[TypeParameter]) -> TypeMapping { type_parameters .iter() .map(|x| { ( - x.clone(), + x.type_id, insert_type(TypeInfo::UnknownGeneric { name: x.name_ident.clone(), }), @@ -17,3 +17,107 @@ pub(crate) fn insert_type_parameters(type_parameters: &[TypeParameter]) -> TypeM }) .collect() } + +pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> TypeMapping { + match (look_up_type_id(superset_type), look_up_type_id(subset_type)) { + (TypeInfo::Ref(superset_type, _), TypeInfo::Ref(subset_type, _)) => { + create_type_mapping(superset_type, subset_type) + } + (TypeInfo::Ref(superset_type, _), _) => create_type_mapping(superset_type, subset_type), + (_, TypeInfo::Ref(subset_type, _)) => create_type_mapping(superset_type, subset_type), + (TypeInfo::UnknownGeneric { name }, _) => { + insert_type_parameters_with_type_arguments(vec![superset_type], vec![subset_type]) + } + ( + TypeInfo::Custom { + type_arguments: type_parameters, + .. + }, + TypeInfo::Custom { type_arguments, .. }, + ) => insert_type_parameters_with_type_arguments( + type_parameters + .iter() + .map(|x| x.type_id) + .collect::>(), + type_arguments.iter().map(|x| x.type_id).collect::>(), + ), + ( + TypeInfo::Enum { + type_parameters, .. + }, + TypeInfo::Enum { + type_parameters: type_arguments, + .. + }, + ) => insert_type_parameters_with_type_arguments( + type_parameters + .iter() + .map(|x| x.type_id) + .collect::>(), + type_arguments.iter().map(|x| x.type_id).collect::>(), + ), + ( + TypeInfo::Struct { + type_parameters, .. + }, + TypeInfo::Struct { + type_parameters: type_arguments, + .. + }, + ) => insert_type_parameters_with_type_arguments( + type_parameters + .iter() + .map(|x| x.type_id) + .collect::>(), + type_arguments.iter().map(|x| x.type_id).collect::>(), + ), + (TypeInfo::Tuple(type_parameters), TypeInfo::Tuple(type_arguments)) => { + insert_type_parameters_with_type_arguments( + type_parameters + .iter() + .map(|x| x.type_id) + .collect::>(), + type_arguments.iter().map(|x| x.type_id).collect::>(), + ) + } + (TypeInfo::Array(superset_type, l1), TypeInfo::Array(subset_type, r1)) => { + insert_type_parameters_with_type_arguments(vec![superset_type], vec![subset_type]) + } + ( + TypeInfo::Storage { + fields: type_parameters, + }, + TypeInfo::Storage { + fields: type_arguments, + }, + ) => insert_type_parameters_with_type_arguments( + type_parameters + .iter() + .map(|x| x.type_id) + .collect::>(), + type_arguments.iter().map(|x| x.type_id).collect::>(), + ), + (TypeInfo::Unknown, TypeInfo::Unknown) + | (TypeInfo::Boolean, TypeInfo::Boolean) + | (TypeInfo::SelfType, TypeInfo::SelfType) + | (TypeInfo::Byte, TypeInfo::Byte) + | (TypeInfo::B256, TypeInfo::B256) + | (TypeInfo::Numeric, TypeInfo::Numeric) + | (TypeInfo::Contract, TypeInfo::Contract) + | (TypeInfo::ErrorRecovery, TypeInfo::ErrorRecovery) + | (TypeInfo::Str(_), TypeInfo::Str(_)) + | (TypeInfo::UnsignedInteger(_), TypeInfo::UnsignedInteger(_)) + | (TypeInfo::ContractCaller { .. }, TypeInfo::ContractCaller { .. }) => vec![], + _ => vec![], + } +} + +fn insert_type_parameters_with_type_arguments( + type_parameters: Vec, + type_arguments: Vec, +) -> TypeMapping { + type_parameters + .into_iter() + .zip(type_arguments.into_iter()) + .collect::>() +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock index 39a70d597e7..f674a69b6f1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock @@ -1,14 +1,4 @@ -[[package]] -name = 'core' -source = 'path+from-root-C569FB5C26218A1B' -dependencies = [] - [[package]] name = 'impl_with_semantic_type_constraints' source = 'root' -dependencies = ['std'] - -[[package]] -name = 'std' -source = 'path+from-root-C569FB5C26218A1B' -dependencies = ['core'] +dependencies = [] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml index e21f59c2882..1318034cffa 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml @@ -3,6 +3,4 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" name = "impl_with_semantic_type_constraints" - -[dependencies] -std = { path = "../../../../../../sway-lib-std" } +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw index e73bfbecd6c..1f584c13be9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw @@ -18,8 +18,11 @@ impl DoubleIdentity { } impl DoubleIdentity { - fn add(self) -> u8 { - self.first + self.second + // fn add(self) -> u8 { + // self.first + self.second + // } + fn get_42(self) -> u8 { + 42u8 } } @@ -30,7 +33,8 @@ fn main() { }; let b = a.get_first(); let c = a.get_second(); - let d = a.add(); + // let d = a.add(); + let d = a.get_42(); let e = DoubleIdentity { first: true, From b403607ecadc16df715c4d72f06e6bd193a61160 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 15:44:40 -0500 Subject: [PATCH 07/17] Use TypeId in TypeMapping and in TraitMap. --- .../ast_node/declaration/impl_trait.rs | 4 +- .../ast_node/declaration/monomorphize.rs | 6 +-- .../ast_node/declaration/trait.rs | 6 +-- .../ast_node/expression/typed_expression.rs | 6 +-- .../src/semantic_analysis/ast_node/mod.rs | 4 +- .../src/semantic_analysis/namespace/items.rs | 17 ++++---- .../src/semantic_analysis/namespace/module.rs | 5 +-- .../semantic_analysis/namespace/trait_map.rs | 40 +++++++++++-------- sway-core/src/type_engine/type_info.rs | 4 +- sway-core/src/type_engine/type_mapping.rs | 4 +- 10 files changed, 47 insertions(+), 49 deletions(-) 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 28a88303848..8129c01f747 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 @@ -405,13 +405,13 @@ fn type_check_trait_implementation( suffix: trait_name.suffix.clone(), is_absolute: false, }, - match resolve_type(self_type, self_type_span) { + insert_type(match resolve_type(self_type, self_type_span) { Ok(o) => o, Err(e) => { errors.push(e.into()); return err(warnings, errors); } - }, + }), functions_buf.clone(), ); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs index f983c1b6f8a..d38e781c2d1 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs @@ -198,10 +198,6 @@ where let old_type_id = decl.create_type_id(); let mut new_decl = decl; new_decl.copy_types(type_mapping); - namespace.copy_methods_to_type( - look_up_type_id(old_type_id), - look_up_type_id(new_decl.create_type_id()), - type_mapping, - ); + namespace.copy_methods_to_type(old_type_id, new_decl.create_type_id(), type_mapping); new_decl } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 669cdf13522..bb7483fe649 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -76,7 +76,7 @@ impl TypedTraitDeclaration { suffix: trait_decl.name.clone(), is_absolute: false, }, - TypeInfo::SelfType, + insert_type(TypeInfo::SelfType), interface_surface .iter() .map(|x| x.to_dummy_func(Mode::NonAbi)) @@ -128,7 +128,7 @@ fn handle_supertraits( // insert dummy versions of the interfaces for all of the supertraits trait_namespace.insert_trait_implementation( supertrait.name.clone(), - TypeInfo::SelfType, + insert_type(TypeInfo::SelfType), interface_surface .iter() .map(|x| x.to_dummy_func(Mode::NonAbi)) @@ -144,7 +144,7 @@ fn handle_supertraits( ); trait_namespace.insert_trait_implementation( supertrait.name.clone(), - TypeInfo::SelfType, + insert_type(TypeInfo::SelfType), dummy_funcs, ); 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 7383f11e847..3becc8e00c2 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 @@ -1623,11 +1623,7 @@ impl TypedExpression { } functions_buf.append(&mut type_checked_fn_buf); - namespace.insert_trait_implementation( - abi_name.clone(), - look_up_type_id(return_type), - functions_buf, - ); + namespace.insert_trait_implementation(abi_name.clone(), return_type, functions_buf); let exp = TypedExpression { expression: TypedExpressionVariant::AbiCast { abi_name, diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index d75b7671bd5..255313119eb 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -428,7 +428,7 @@ impl TypedAstNode { ); namespace.insert_trait_implementation( impl_trait.trait_name.clone(), - look_up_type_id(implementing_for_type_id), + implementing_for_type_id, impl_trait.methods.clone(), ); TypedDeclaration::ImplTrait(impl_trait) @@ -442,7 +442,7 @@ impl TypedAstNode { ); namespace.insert_trait_implementation( impl_trait.trait_name.clone(), - look_up_type_id(impl_trait.implementing_for_type_id), + impl_trait.implementing_for_type_id, impl_trait.methods.clone(), ); TypedDeclaration::ImplTrait(impl_trait) diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index 988e6fd2d97..995b5885c47 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -110,7 +110,7 @@ impl Items { pub(crate) fn insert_trait_implementation( &mut self, trait_name: CallPath, - type_implementing_for: TypeInfo, + implementing_for_type_id: TypeId, functions_buf: Vec, ) { let new_prefixes = if trait_name.prefixes.is_empty() { @@ -127,12 +127,15 @@ impl Items { is_absolute: trait_name.is_absolute, }; self.implemented_traits - .insert(trait_name, type_implementing_for, functions_buf); + .insert(trait_name, implementing_for_type_id, functions_buf); } - pub(crate) fn get_methods_for_type(&self, r#type: TypeId) -> Vec { + pub(crate) fn get_methods_for_type( + &self, + implementing_for_type_id: TypeId, + ) -> Vec { self.implemented_traits - .get_methods_for_type(look_up_type_id(r#type)) + .get_methods_for_type(implementing_for_type_id) } // Given a TypeInfo old_type with a set of methods available to it, make those same methods @@ -141,8 +144,8 @@ impl Items { // methods for new_type as it does for old_type. pub(crate) fn copy_methods_to_type( &mut self, - old_type: TypeInfo, - new_type: TypeInfo, + old_type: TypeId, + new_type: TypeId, type_mapping: &TypeMapping, ) { // This map grabs all (trait name, vec of methods) from self.implemented_traits @@ -158,7 +161,7 @@ impl Items { .iter_mut() .for_each(|method| method.copy_types(type_mapping)); self.implemented_traits - .insert(trait_name, new_type.clone(), trait_methods); + .insert(trait_name, new_type, trait_methods); } } diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index a6740445832..088268d1a84 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -2,7 +2,6 @@ use crate::{ error::*, parse_tree::Visibility, semantic_analysis::{ast_node::TypedVariableDeclaration, declaration::VariableMutability}, - type_engine::*, CompileResult, Ident, TypedDeclaration, }; @@ -181,9 +180,7 @@ impl Module { let a = decl.return_type().value; // if this is an enum or struct, import its implementations let mut res = match a { - Some(a) => src_ns - .implemented_traits - .get_call_path_and_type_info(look_up_type_id(a)), + Some(a) => src_ns.implemented_traits.get_call_path_and_type_info(a), None => vec![], }; impls_to_insert.append(&mut res); diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 7a0bb796e0d..ee6202df506 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -1,4 +1,7 @@ -use crate::{CallPath, TypeInfo, TypedFunctionDeclaration}; +use crate::{ + type_engine::{look_up_type_id, TypeId}, + CallPath, TypeInfo, TypedFunctionDeclaration, +}; use std::collections::HashMap; @@ -26,7 +29,7 @@ type TraitName = CallPath; // However, we need this structure to be able to maintain the // difference between 3 and 4, as in practice, 1 and 2 might not yet // be resolved. -type TraitMapInner = im::Vector<((TraitName, TypeInfo), TraitMethods)>; +type TraitMapInner = im::Vector<((TraitName, TypeId), TraitMethods)>; type TraitMethods = im::HashMap; #[derive(Clone, Debug, Default, PartialEq)] @@ -38,7 +41,7 @@ impl TraitMap { pub(crate) fn insert( &mut self, trait_name: CallPath, - type_implementing_for: TypeInfo, + incoming_type_id: TypeId, methods: Vec, ) { let mut methods_map = im::HashMap::new(); @@ -47,7 +50,7 @@ impl TraitMap { methods_map.insert(method_name, method); } self.trait_map - .push_back(((trait_name, type_implementing_for), methods_map)); + .push_back(((trait_name, incoming_type_id), methods_map)); } pub(crate) fn extend(&mut self, other: TraitMap) { @@ -62,13 +65,13 @@ impl TraitMap { pub(crate) fn get_call_path_and_type_info( &self, - r#type: TypeInfo, - ) -> Vec<((CallPath, TypeInfo), Vec)> { + incoming_type_id: TypeId, + ) -> Vec<((CallPath, TypeId), Vec)> { let mut ret = vec![]; - for ((call_path, type_info), methods) in self.trait_map.iter() { - if type_info.clone() == r#type { + for ((call_path, map_type_id), methods) in self.trait_map.iter() { + if look_up_type_id(*map_type_id) == look_up_type_id(incoming_type_id) { ret.push(( - (call_path.clone(), type_info.clone()), + (call_path.clone(), *map_type_id), methods.values().cloned().collect(), )); } @@ -76,14 +79,17 @@ impl TraitMap { ret } - pub(crate) fn get_methods_for_type(&self, r#type: TypeInfo) -> Vec { + pub(crate) fn get_methods_for_type( + &self, + incoming_type_id: TypeId, + ) -> Vec { let mut methods = vec![]; // small performance gain in bad case - if r#type == TypeInfo::ErrorRecovery { + if look_up_type_id(incoming_type_id) == TypeInfo::ErrorRecovery { return methods; } - for ((_, type_info), l_methods) in self.trait_map.iter() { - if *type_info == r#type { + for ((_, map_type_id), l_methods) in self.trait_map.iter() { + if look_up_type_id(*map_type_id) == look_up_type_id(incoming_type_id) { methods.append(&mut l_methods.values().cloned().collect()); } } @@ -92,15 +98,15 @@ impl TraitMap { pub(crate) fn get_methods_for_type_by_trait( &self, - r#type: TypeInfo, + incoming_type_id: TypeId, ) -> HashMap> { let mut methods: HashMap> = HashMap::new(); // small performance gain in bad case - if r#type == TypeInfo::ErrorRecovery { + if look_up_type_id(incoming_type_id) == TypeInfo::ErrorRecovery { return methods; } - for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { - if *type_info == r#type { + for ((trait_name, map_type_id), trait_methods) in self.trait_map.iter() { + if look_up_type_id(*map_type_id) == look_up_type_id(incoming_type_id) { methods.insert( (*trait_name).clone(), trait_methods.values().cloned().collect(), diff --git a/sway-core/src/type_engine/type_info.rs b/sway-core/src/type_engine/type_info.rs index 5e273b02d80..ab970e56801 100644 --- a/sway-core/src/type_engine/type_info.rs +++ b/sway-core/src/type_engine/type_info.rs @@ -556,7 +556,7 @@ impl TypeInfo { match self { TypeInfo::Custom { .. } => { for (param, ty_id) in mapping.iter() { - if look_up_type_id(param.type_id) == *self { + if look_up_type_id(*param) == *self { return Some(*ty_id); } } @@ -564,7 +564,7 @@ impl TypeInfo { } TypeInfo::UnknownGeneric { .. } => { for (param, ty_id) in mapping.iter() { - if look_up_type_id(param.type_id) == *self { + if look_up_type_id(*param) == *self { return Some(*ty_id); } } diff --git a/sway-core/src/type_engine/type_mapping.rs b/sway-core/src/type_engine/type_mapping.rs index e87f23fcb1d..8335676addc 100644 --- a/sway-core/src/type_engine/type_mapping.rs +++ b/sway-core/src/type_engine/type_mapping.rs @@ -2,14 +2,14 @@ use crate::TypeParameter; use super::*; -pub(crate) type TypeMapping = Vec<(TypeParameter, TypeId)>; +pub(crate) type TypeMapping = Vec<(TypeId, TypeId)>; pub(crate) fn insert_type_parameters(type_parameters: &[TypeParameter]) -> TypeMapping { type_parameters .iter() .map(|x| { ( - x.clone(), + x.type_id, insert_type(TypeInfo::UnknownGeneric { name: x.name_ident.clone(), }), From 6f8c11689dfb108cbc48784ac2ec514e923b77ee Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 16:06:58 -0500 Subject: [PATCH 08/17] Add semantic type constraints. --- .../ast_node/declaration/monomorphize.rs | 21 ---- .../semantic_analysis/namespace/trait_map.rs | 107 ++---------------- sway-core/src/type_engine/type_mapping.rs | 52 +++++---- .../src/main.sw | 27 +++-- 4 files changed, 57 insertions(+), 150 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs index dcdc6db6c40..18d5bce5c58 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/monomorphize.rs @@ -169,16 +169,6 @@ where } } } - if self.name().as_str() == "DoubleIdentity" { - println!( - "\n\ntype_mapping:\n[{}]", - type_mapping - .iter() - .map(|(x, y)| format!("({}, {})", x, y)) - .collect::>() - .join(", ") - ); - } let module = check!( namespace.check_submodule_mut(module_path), return err(warnings, errors), @@ -186,17 +176,6 @@ where errors ); let new_decl = self.monomorphize_inner(&type_mapping, module); - if new_decl.name().as_str() == "DoubleIdentity" { - println!( - "\n\ndecl.type_parameters():\n[{}]", - new_decl - .type_parameters() - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(", ") - ); - } ok(new_decl, warnings, errors) } } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index cec7357cb62..4e6fa67f1ae 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -1,5 +1,5 @@ use crate::{ - type_engine::{look_up_type_id, TypeId}, + type_engine::{create_type_mapping, look_up_type_id, CopyTypes, TypeId}, CallPath, TypeInfo, TypedFunctionDeclaration, }; @@ -43,25 +43,9 @@ impl TraitMap { methods: Vec, ) { let mut methods_map = im::HashMap::new(); - // if let TypeInfo::Struct { ref name, .. } = type_implementing_for { - // if name.as_str() == "DoubleIdentity" { - // println!(">>\n\tinserting for {}", type_implementing_for); - // } - // } for method in methods.into_iter() { - let method_name = method.name.as_str().to_string(); - // if let TypeInfo::Struct { ref name, .. } = type_implementing_for { - // if name.as_str() == "DoubleIdentity" { - // println!("\t{}", method_name); - // } - // } - methods_map.insert(method_name, method); + methods_map.insert(method.name.as_str().to_string(), method); } - // if let TypeInfo::Struct { ref name, .. } = type_implementing_for { - // if name.as_str() == "DoubleIdentity" { - // println!(">>"); - // } - // } self.trait_map .push_back(((trait_name, incoming_type_id), methods_map)); } @@ -101,89 +85,16 @@ impl TraitMap { if look_up_type_id(incoming_type_id) == TypeInfo::ErrorRecovery { return methods; } - // if let TypeInfo::Struct { ref name, .. } = r#type { - // if name.as_str() == "DoubleIdentity" { - // println!( - // "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type\n\nfound:\n[", - // r#type - // ); - // } - // } - for ((_, type_info), trait_methods) in self.trait_map.iter() { - if look_up_type_id(incoming_type_id).is_subset_of(&look_up_type_id(*type_info)) { - let mut trait_methods = trait_methods.values().cloned().collect(); - // if let TypeInfo::Struct { ref name, .. } = type_info { - // if name.as_str() == "DoubleIdentity" { - // println!("{}\n^ hit", type_info); - // for trait_method in trait_methods.iter() { - // println!("\t{}", trait_method.name); - // } - // } - // } + for ((_, map_type_id), trait_methods) in self.trait_map.iter() { + if look_up_type_id(incoming_type_id).is_subset_of(&look_up_type_id(*map_type_id)) { + let type_mapping = create_type_mapping(*map_type_id, incoming_type_id); + let mut trait_methods = trait_methods.values().cloned().collect::>(); + trait_methods + .iter_mut() + .for_each(|x| x.copy_types(&type_mapping)); methods.append(&mut trait_methods); } - // } else { - // if let TypeInfo::Struct { ref name, .. } = type_info { - // if name.as_str() == "DoubleIdentity" { - // println!("{}", type_info); - // } - // } - // } } methods } - - // pub(crate) fn get_methods_for_type_by_trait( - // &self, - // r#type: TypeInfo, - // ) -> HashMap> { - // let mut methods: HashMap> = HashMap::new(); - // // small performance gain in bad case - // if r#type == TypeInfo::ErrorRecovery { - // return methods; - // } - // if let TypeInfo::Struct { ref name, .. } = r#type { - // if name.as_str() == "DoubleIdentity" { - // println!( - // "\n\nlooking for:\n{}\n\nin:\nget_methods_for_type_by_trait\n\nfound:\n[", - // r#type - // ); - // } - // } - // for ((trait_name, type_info), trait_methods) in self.trait_map.iter() { - // if r#type.is_subset_of(type_info) { - // let mut trait_methods: Vec = - // trait_methods.values().cloned().collect(); - // if let TypeInfo::Struct { ref name, .. } = type_info { - // if name.as_str() == "DoubleIdentity" { - // println!("{}\n^ hit", type_info); - // for trait_method in trait_methods.iter() { - // println!("\t{}", trait_method.name); - // } - // } - // } - // match methods.get_mut(trait_name) { - // Some(v) => { - // v.append(&mut trait_methods); - // } - // _ => { - // methods.insert((*trait_name).clone(), trait_methods); - // } - // } - // // } - // } else { - // if let TypeInfo::Struct { ref name, .. } = type_info { - // if name.as_str() == "DoubleIdentity" { - // println!("{}", type_info); - // } - // } - // } - // } - // if let TypeInfo::Struct { ref name, .. } = r#type { - // if name.as_str() == "DoubleIdentity" { - // println!("]"); - // } - // } - // methods - // } } diff --git a/sway-core/src/type_engine/type_mapping.rs b/sway-core/src/type_engine/type_mapping.rs index 2e944906cab..c743cc68267 100644 --- a/sway-core/src/type_engine/type_mapping.rs +++ b/sway-core/src/type_engine/type_mapping.rs @@ -25,8 +25,8 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> } (TypeInfo::Ref(superset_type, _), _) => create_type_mapping(superset_type, subset_type), (_, TypeInfo::Ref(subset_type, _)) => create_type_mapping(superset_type, subset_type), - (TypeInfo::UnknownGeneric { name }, _) => { - insert_type_parameters_with_type_arguments(vec![superset_type], vec![subset_type]) + (TypeInfo::UnknownGeneric { .. }, _) => { + vec![(superset_type, subset_type)] } ( TypeInfo::Custom { @@ -34,13 +34,14 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> .. }, TypeInfo::Custom { type_arguments, .. }, - ) => insert_type_parameters_with_type_arguments( - type_parameters + ) => { + let type_parameters = type_parameters .iter() .map(|x| x.type_id) - .collect::>(), - type_arguments.iter().map(|x| x.type_id).collect::>(), - ), + .collect::>(); + let type_arguments = type_arguments.iter().map(|x| x.type_id).collect::>(); + insert_type_parameters_with_type_arguments(type_parameters, type_arguments) + } ( TypeInfo::Enum { type_parameters, .. @@ -49,13 +50,14 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> type_parameters: type_arguments, .. }, - ) => insert_type_parameters_with_type_arguments( - type_parameters + ) => { + let type_parameters = type_parameters .iter() .map(|x| x.type_id) - .collect::>(), - type_arguments.iter().map(|x| x.type_id).collect::>(), - ), + .collect::>(); + let type_arguments = type_arguments.iter().map(|x| x.type_id).collect::>(); + insert_type_parameters_with_type_arguments(type_parameters, type_arguments) + } ( TypeInfo::Struct { type_parameters, .. @@ -64,13 +66,14 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> type_parameters: type_arguments, .. }, - ) => insert_type_parameters_with_type_arguments( - type_parameters + ) => { + let type_parameters = type_parameters .iter() .map(|x| x.type_id) - .collect::>(), - type_arguments.iter().map(|x| x.type_id).collect::>(), - ), + .collect::>(); + let type_arguments = type_arguments.iter().map(|x| x.type_id).collect::>(); + insert_type_parameters_with_type_arguments(type_parameters, type_arguments) + } (TypeInfo::Tuple(type_parameters), TypeInfo::Tuple(type_arguments)) => { insert_type_parameters_with_type_arguments( type_parameters @@ -80,8 +83,8 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> type_arguments.iter().map(|x| x.type_id).collect::>(), ) } - (TypeInfo::Array(superset_type, l1), TypeInfo::Array(subset_type, r1)) => { - insert_type_parameters_with_type_arguments(vec![superset_type], vec![subset_type]) + (TypeInfo::Array(superset_type, _), TypeInfo::Array(subset_type, _)) => { + vec![(superset_type, subset_type)] } ( TypeInfo::Storage { @@ -90,13 +93,14 @@ pub(crate) fn create_type_mapping(superset_type: TypeId, subset_type: TypeId) -> TypeInfo::Storage { fields: type_arguments, }, - ) => insert_type_parameters_with_type_arguments( - type_parameters + ) => { + let type_parameters = type_parameters .iter() .map(|x| x.type_id) - .collect::>(), - type_arguments.iter().map(|x| x.type_id).collect::>(), - ), + .collect::>(); + let type_arguments = type_arguments.iter().map(|x| x.type_id).collect::>(); + insert_type_parameters_with_type_arguments(type_parameters, type_arguments) + } (TypeInfo::Unknown, TypeInfo::Unknown) | (TypeInfo::Boolean, TypeInfo::Boolean) | (TypeInfo::SelfType, TypeInfo::SelfType) diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw index 1f584c13be9..7dd055a49b7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw @@ -31,14 +31,27 @@ fn main() { first: 0u8, second: 1u8 }; - let b = a.get_first(); - let c = a.get_second(); - // let d = a.add(); - let d = a.get_42(); - - let e = DoubleIdentity { + let b = DoubleIdentity { first: true, + second: false, + }; + let c = DoubleIdentity { + first: 0u64, second: "hi" }; - let f = e.get_second(); + + let d = a.get_first(); + let e = a.get_second(); + let f = a.get_42(); + + let g = b.get_first(); + let h = b.get_second(); + // should fail + let i = b.get_42(); + + // should fail + let j = c.get_first(); + let k = c.get_second(); + // should fail + let l = c.get_42(); } From d8a7b91f767fec9c9d3c6aaf2050fa03e3e13e8d Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 13 Jun 2022 16:15:50 -0500 Subject: [PATCH 09/17] Update test case. --- .../src/semantic_analysis/namespace/items.rs | 20 ------------------- .../Forc.lock | 12 ++++++++++- .../Forc.toml | 4 +++- .../src/main.sw | 13 +++++------- 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index 825550bae46..92f137fc7a4 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -138,26 +138,6 @@ impl Items { .get_methods_for_type(implementing_for_type_id) } - // /// Given a [TypeInfo] `new_type`, find all the types for which `new_type` is a subset and grab - // /// all the methods for those types, then implement them for `new_type` - // pub(crate) fn copy_methods_to_type(&mut self, new_type: TypeInfo, type_mapping: &TypeMapping) { - // // This map grabs all (trait name, vec of methods) from self.implemented_traits - // // for which `new_type` is a subset of the existing types - // let methods = self - // .implemented_traits - // .get_methods_for_type_by_trait(new_type.clone()); - - // // Insert into `self.implemented_traits` the contents of the map above but with `new_type` - // // as the `TypeInfo` key. - // for (trait_name, mut trait_methods) in methods.into_iter() { - // trait_methods - // .iter_mut() - // .for_each(|method| method.copy_types(type_mapping)); - // self.implemented_traits - // .insert(trait_name, new_type.clone(), trait_methods); - // } - // } - pub(crate) fn get_canonical_path(&self, symbol: &Ident) -> &[Ident] { self.use_synonyms.get(symbol).map(|v| &v[..]).unwrap_or(&[]) } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock index f674a69b6f1..39a70d597e7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.lock @@ -1,4 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-C569FB5C26218A1B' +dependencies = [] + [[package]] name = 'impl_with_semantic_type_constraints' source = 'root' -dependencies = [] +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-C569FB5C26218A1B' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml index 1318034cffa..e21f59c2882 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/Forc.toml @@ -3,4 +3,6 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" name = "impl_with_semantic_type_constraints" -implicit-std = false + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw index 7dd055a49b7..bfdc1398d1a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/impl_with_semantic_type_constraints/src/main.sw @@ -18,11 +18,8 @@ impl DoubleIdentity { } impl DoubleIdentity { - // fn add(self) -> u8 { - // self.first + self.second - // } - fn get_42(self) -> u8 { - 42u8 + fn add(self) -> u8 { + self.first + self.second } } @@ -42,16 +39,16 @@ fn main() { let d = a.get_first(); let e = a.get_second(); - let f = a.get_42(); + let f = a.add(); let g = b.get_first(); let h = b.get_second(); // should fail - let i = b.get_42(); + let i = b.add(); // should fail let j = c.get_first(); let k = c.get_second(); // should fail - let l = c.get_42(); + let l = c.add(); } From 1e7d3ce4d6dbb2d974f4055b4e2b3a75d91fbd8a Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Tue, 14 Jun 2022 17:54:45 -0500 Subject: [PATCH 10/17] fix --- sway-core/src/semantic_analysis/namespace/trait_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 4e6fa67f1ae..72f9c1eb890 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -66,7 +66,7 @@ impl TraitMap { ) -> Vec<((CallPath, TypeId), Vec)> { let mut ret = vec![]; for ((call_path, map_type_id), methods) in self.trait_map.iter() { - if look_up_type_id(*map_type_id) == look_up_type_id(incoming_type_id) { + if look_up_type_id(incoming_type_id).is_subset_of(&look_up_type_id(*map_type_id)) { ret.push(( (call_path.clone(), *map_type_id), methods.values().cloned().collect(), From 3b5e2f134dd3c3603f346a5cec55c68b7aa06e42 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Thu, 16 Jun 2022 20:22:31 -0500 Subject: [PATCH 11/17] Bug is fixed. --- test/src/e2e_vm_tests/mod.rs | 7 ++ .../call_find_associated_methods/Forc.toml | 9 +++ .../json_abi_oracle.json | 1 + .../call_find_associated_methods/src/main.sw | 13 ++++ .../test_abis/abi_with_tuples/Forc.lock | 8 ++- .../find_associated_methods_library/Forc.toml | 6 ++ .../json_abi_oracle.json | 1 + .../src/main.sw | 6 ++ .../Forc.lock | 22 ++++++ .../Forc.toml | 9 +++ .../json_abi_oracle.json | 72 +++++++++++++++++++ .../src/main.sw | 33 +++++++++ 12 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 6f7a8cad349..a4889a2d8fc 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -609,6 +609,13 @@ pub fn run(locked: bool, filter_regex: Option) { ), 4242, ), + ( + ( + "should_pass/test_contracts/find_associated_methods_contract", + "should_pass/require_contract_deployment/call_find_associated_methods", + ), + 1, + ), ( ( "should_pass/test_contracts/increment_contract", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml new file mode 100644 index 00000000000..b2d5d9d4869 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "call_abi_with_tuples" + +[dependencies] +find_associated_methods_library = { path = "../../test_abis/find_associated_methods_library" } +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw new file mode 100644 index 00000000000..4b21fee6d07 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw @@ -0,0 +1,13 @@ +script; + +use find_associated_methods_library::MyContract; +use std::assert::*; + +fn main() -> bool { + let the_abi = abi(MyContract, 0x4b0e0324f65fc5440440962c0d13352dff4d5d358890427b5af36ee86ecdc221); + + let res = the_abi.test_function(); + assert(res); + + 1 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/abi_with_tuples/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/abi_with_tuples/Forc.lock index ccbfdf27499..b94f93e5b57 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/abi_with_tuples/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/abi_with_tuples/Forc.lock @@ -1,3 +1,9 @@ [[package]] -name = 'auth_testing_abi' +name = 'abi_with_tuples' +source = 'root' +dependencies = ['core'] + +[[package]] +name = 'core' +source = 'path+from-root-D1CDC58B8291BA8B' dependencies = [] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml new file mode 100644 index 00000000000..1d9935a71b4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml @@ -0,0 +1,6 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "find_associated_methods_library" +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw new file mode 100644 index 00000000000..6cb1ede1fa6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw @@ -0,0 +1,6 @@ +library find_associated_methods_library; + +abi MyContract { + #[storage(read)] + fn test_function() -> bool; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock new file mode 100644 index 00000000000..45d6f5d6ab8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock @@ -0,0 +1,22 @@ +[[package]] +name = 'core' +source = 'path+from-root-85350A31A47B8419' +dependencies = [] + +[[package]] +name = 'find_associated_methods_contract' +source = 'root' +dependencies = [ + 'find_associated_methods_library', + 'std', +] + +[[package]] +name = 'find_associated_methods_library' +source = 'path+from-root-85350A31A47B8419' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-85350A31A47B8419' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml new file mode 100644 index 00000000000..fdd455f9bf4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "find_associated_methods_contract" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } +find_associated_methods_library = { path = "../../test_abis/find_associated_methods_library" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json new file mode 100644 index 00000000000..95b93c7cfac --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json @@ -0,0 +1,72 @@ +[ + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "components": null, + "name": "age", + "type": "u64" + } + ], + "name": "__tuple_element", + "type": "struct Person" + }, + { + "components": null, + "name": "__tuple_element", + "type": "u64" + } + ], + "name": "param", + "type": "(struct Person, u64)" + } + ], + "name": "bug1", + "outputs": [ + { + "components": null, + "name": "", + "type": "bool" + } + ], + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "components": [], + "name": "Earth", + "type": "()" + } + ], + "name": "__tuple_element", + "type": "enum Location" + }, + { + "components": null, + "name": "__tuple_element", + "type": "u64" + } + ], + "name": "param", + "type": "(enum Location, u64)" + } + ], + "name": "bug2", + "outputs": [ + { + "components": null, + "name": "", + "type": "bool" + } + ], + "type": "function" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw new file mode 100644 index 00000000000..5bb468ca516 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw @@ -0,0 +1,33 @@ +contract; + +use find_associated_methods_library::MyContract; + +use std::result::*; +use std::identity::*; +use std::chain::auth::*; +use std::option::*; +use std::assert::*; + +fn bogus() -> Identity { + let sender = msg_sender(); + sender.unwrap() +} + +struct MyStruct { + int_option: Option +} + +storage { + stored_struct: MyStruct, +} + +impl MyContract for Contract { + #[storage(read)] + fn test_function() -> bool { + let identity = bogus(); + let stored_struct = storage.stored_struct; + let stored_option_in_struct = stored_struct.int_option; + require(stored_option_in_struct.is_some(), "Error"); + true + } +} \ No newline at end of file From 60ff0aa1ceb5123fd6f96f17c75087342ca16dca Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Thu, 16 Jun 2022 20:30:20 -0500 Subject: [PATCH 12/17] Add forc.lock. --- .../call_find_associated_methods/Forc.lock | 22 +++++++++++++++++++ .../call_find_associated_methods/src/main.sw | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock new file mode 100644 index 00000000000..dfaf076db5a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock @@ -0,0 +1,22 @@ +[[package]] +name = 'call_abi_with_tuples' +source = 'root' +dependencies = [ + 'find_associated_methods_library', + 'std', +] + +[[package]] +name = 'core' +source = 'path+from-root-A94357F7D125B65F' +dependencies = [] + +[[package]] +name = 'find_associated_methods_library' +source = 'path+from-root-A94357F7D125B65F' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-A94357F7D125B65F' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw index 4b21fee6d07..daf653111c6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw @@ -3,7 +3,7 @@ script; use find_associated_methods_library::MyContract; use std::assert::*; -fn main() -> bool { +fn main() -> u64 { let the_abi = abi(MyContract, 0x4b0e0324f65fc5440440962c0d13352dff4d5d358890427b5af36ee86ecdc221); let res = the_abi.test_function(); From a7b19efb3ca2ab49d8b011533b3fb9a24665d702 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Thu, 16 Jun 2022 20:46:46 -0500 Subject: [PATCH 13/17] update --- .../call_find_associated_methods/src/main.sw | 8 ++++---- .../test_abis/find_associated_methods_library/src/main.sw | 2 +- .../find_associated_methods_contract/src/main.sw | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw index daf653111c6..d63fa2d99ac 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw @@ -1,13 +1,13 @@ script; -use find_associated_methods_library::MyContract; +use find_associated_methods_library::*; use std::assert::*; -fn main() -> u64 { - let the_abi = abi(MyContract, 0x4b0e0324f65fc5440440962c0d13352dff4d5d358890427b5af36ee86ecdc221); +fn main() -> bool { + let the_abi = abi(MyContract, 0x8afb04df8c2b85db4b33550a7b736795a6a687303ca58f48aa98a487bfda91a9); let res = the_abi.test_function(); assert(res); - 1 + true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw index 6cb1ede1fa6..462cfd1c88c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw @@ -1,6 +1,6 @@ library find_associated_methods_library; abi MyContract { - #[storage(read)] + #[storage(read, write)] fn test_function() -> bool; } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw index 5bb468ca516..7d1549967c8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw @@ -22,9 +22,12 @@ storage { } impl MyContract for Contract { - #[storage(read)] + #[storage(read, write)] fn test_function() -> bool { let identity = bogus(); + storage.stored_struct = MyStruct { + int_option: Option::Some(99u64) + }; let stored_struct = storage.stored_struct; let stored_option_in_struct = stored_struct.int_option; require(stored_option_in_struct.is_some(), "Error"); From d7e81c5f76f0890976070aa6ce61c74946c65f8f Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 20 Jun 2022 14:46:33 -0500 Subject: [PATCH 14/17] Move test to inside of the SDK. --- .../call_find_associated_methods/Forc.lock | 22 ------ .../call_find_associated_methods/Forc.toml | 9 --- .../json_abi_oracle.json | 1 - .../call_find_associated_methods/src/main.sw | 13 ---- .../json_abi_oracle.json | 1 - .../Forc.lock | 22 ------ .../Forc.toml | 9 --- .../json_abi_oracle.json | 72 ------------------- .../test_artifacts/methods_abi}/Forc.toml | 2 +- .../test_artifacts/methods_abi}/src/main.sw | 4 +- .../test_artifacts/methods_contract/Forc.toml | 9 +++ .../methods_contract}/src/main.sw | 9 ++- .../sdk-harness/test_projects/methods/mod.rs | 36 ++++++++++ 13 files changed, 55 insertions(+), 154 deletions(-) delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json rename test/src/{e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library => sdk-harness/test_artifacts/methods_abi}/Forc.toml (73%) rename test/src/{e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library => sdk-harness/test_artifacts/methods_abi}/src/main.sw (52%) create mode 100644 test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml rename test/src/{e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract => sdk-harness/test_artifacts/methods_contract}/src/main.sw (80%) create mode 100644 test/src/sdk-harness/test_projects/methods/mod.rs diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock deleted file mode 100644 index dfaf076db5a..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.lock +++ /dev/null @@ -1,22 +0,0 @@ -[[package]] -name = 'call_abi_with_tuples' -source = 'root' -dependencies = [ - 'find_associated_methods_library', - 'std', -] - -[[package]] -name = 'core' -source = 'path+from-root-A94357F7D125B65F' -dependencies = [] - -[[package]] -name = 'find_associated_methods_library' -source = 'path+from-root-A94357F7D125B65F' -dependencies = [] - -[[package]] -name = 'std' -source = 'path+from-root-A94357F7D125B65F' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml deleted file mode 100644 index b2d5d9d4869..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/Forc.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "call_abi_with_tuples" - -[dependencies] -find_associated_methods_library = { path = "../../test_abis/find_associated_methods_library" } -std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/json_abi_oracle.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw deleted file mode 100644 index d63fa2d99ac..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_find_associated_methods/src/main.sw +++ /dev/null @@ -1,13 +0,0 @@ -script; - -use find_associated_methods_library::*; -use std::assert::*; - -fn main() -> bool { - let the_abi = abi(MyContract, 0x8afb04df8c2b85db4b33550a7b736795a6a687303ca58f48aa98a487bfda91a9); - - let res = the_abi.test_function(); - assert(res); - - true -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/json_abi_oracle.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock deleted file mode 100644 index 45d6f5d6ab8..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.lock +++ /dev/null @@ -1,22 +0,0 @@ -[[package]] -name = 'core' -source = 'path+from-root-85350A31A47B8419' -dependencies = [] - -[[package]] -name = 'find_associated_methods_contract' -source = 'root' -dependencies = [ - 'find_associated_methods_library', - 'std', -] - -[[package]] -name = 'find_associated_methods_library' -source = 'path+from-root-85350A31A47B8419' -dependencies = [] - -[[package]] -name = 'std' -source = 'path+from-root-85350A31A47B8419' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml deleted file mode 100644 index fdd455f9bf4..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/Forc.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "find_associated_methods_contract" - -[dependencies] -std = { path = "../../../../../../../sway-lib-std" } -find_associated_methods_library = { path = "../../test_abis/find_associated_methods_library" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json deleted file mode 100644 index 95b93c7cfac..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/json_abi_oracle.json +++ /dev/null @@ -1,72 +0,0 @@ -[ - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "components": null, - "name": "age", - "type": "u64" - } - ], - "name": "__tuple_element", - "type": "struct Person" - }, - { - "components": null, - "name": "__tuple_element", - "type": "u64" - } - ], - "name": "param", - "type": "(struct Person, u64)" - } - ], - "name": "bug1", - "outputs": [ - { - "components": null, - "name": "", - "type": "bool" - } - ], - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "components": [], - "name": "Earth", - "type": "()" - } - ], - "name": "__tuple_element", - "type": "enum Location" - }, - { - "components": null, - "name": "__tuple_element", - "type": "u64" - } - ], - "name": "param", - "type": "(enum Location, u64)" - } - ], - "name": "bug2", - "outputs": [ - { - "components": null, - "name": "", - "type": "bool" - } - ], - "type": "function" - } -] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml b/test/src/sdk-harness/test_artifacts/methods_abi/Forc.toml similarity index 73% rename from test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml rename to test/src/sdk-harness/test_artifacts/methods_abi/Forc.toml index 1d9935a71b4..d4c28b1b93a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/Forc.toml +++ b/test/src/sdk-harness/test_artifacts/methods_abi/Forc.toml @@ -2,5 +2,5 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "find_associated_methods_library" +name = "methods_abi" implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw b/test/src/sdk-harness/test_artifacts/methods_abi/src/main.sw similarity index 52% rename from test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw rename to test/src/sdk-harness/test_artifacts/methods_abi/src/main.sw index 462cfd1c88c..288efc7153f 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/find_associated_methods_library/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/methods_abi/src/main.sw @@ -1,6 +1,6 @@ -library find_associated_methods_library; +library methods_abi; -abi MyContract { +abi MethodsContract { #[storage(read, write)] fn test_function() -> bool; } diff --git a/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml new file mode 100644 index 00000000000..9c9f9cc728d --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "methods_contract" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } +methods_abi = { path = "../../test_abis/methods_abi" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw similarity index 80% rename from test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw rename to test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw index 7d1549967c8..0ba065a12c1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/find_associated_methods_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw @@ -1,6 +1,6 @@ contract; -use find_associated_methods_library::MyContract; +use methods_abi::MethodsContract; use std::result::*; use std::identity::*; @@ -13,6 +13,10 @@ fn bogus() -> Identity { sender.unwrap() } +fn bogus2() -> Identity { + msg_sender().unwrap() +} + struct MyStruct { int_option: Option } @@ -21,10 +25,11 @@ storage { stored_struct: MyStruct, } -impl MyContract for Contract { +impl MethodsContract for Contract { #[storage(read, write)] fn test_function() -> bool { let identity = bogus(); + let identity2 = bogus2(); storage.stored_struct = MyStruct { int_option: Option::Some(99u64) }; diff --git a/test/src/sdk-harness/test_projects/methods/mod.rs b/test/src/sdk-harness/test_projects/methods/mod.rs new file mode 100644 index 00000000000..760a7571353 --- /dev/null +++ b/test/src/sdk-harness/test_projects/methods/mod.rs @@ -0,0 +1,36 @@ +use fuels::prelude::*; +use fuels::signers::wallet::Wallet; +use fuels::tx::{default_parameters::MAX_GAS_PER_TX, ContractId}; +use fuels_abigen_macro::abigen; + +abigen!( + MethodsContract, + "test_artifacts/methods_contract/out/debug/methods_abi-abi.json", +); + +#[tokio::test] +async fn test_function() { + let wallet = launch_provider_and_get_single_wallet().await; + let (instance, _) = get_methods_instance(wallet).await; + + let result = instance + .test_function() + .call() + .await + .unwrap(); + assert_eq!(result, true); +} + +async fn get_methods_instance(wallet: Wallet) -> (MethodsContract, ContractId) { + let id = Contract::deploy( + "test_artifacts/methods_contract/out/debug/methods_contract.bin", + &wallet, + TxParameters::default(), + ) + .await + .unwrap(); + + let instance = MethodsContract::new(id.to_string(), wallet); + + (instance, id) +} From 997747eb2515c6f5b13026fbca7b9cca1053e2f7 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 20 Jun 2022 14:47:59 -0500 Subject: [PATCH 15/17] Fix test cases. --- test/src/e2e_vm_tests/mod.rs | 7 ------- test/src/sdk-harness/test_projects/harness.rs | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 1210068a216..ea5868bf338 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -614,13 +614,6 @@ pub fn run(locked: bool, filter_regex: Option) { ), 4242, ), - ( - ( - "should_pass/test_contracts/find_associated_methods_contract", - "should_pass/require_contract_deployment/call_find_associated_methods", - ), - 1, - ), ( ( "should_pass/test_contracts/increment_contract", diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index 4469718f340..e55a53d5e1f 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -13,3 +13,4 @@ mod storage; mod storage_map; mod token_ops; mod tx_fields; +mod methods; From 75efbefc356ef1fd5b4e01e71ff927d0e8038ed7 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 20 Jun 2022 15:12:40 -0500 Subject: [PATCH 16/17] Add lock files. --- .../test_artifacts/methods_abi/Forc.lock | 4 ++++ .../test_artifacts/methods_contract/Forc.lock | 22 +++++++++++++++++++ .../test_artifacts/methods_contract/Forc.toml | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/src/sdk-harness/test_artifacts/methods_abi/Forc.lock create mode 100644 test/src/sdk-harness/test_artifacts/methods_contract/Forc.lock diff --git a/test/src/sdk-harness/test_artifacts/methods_abi/Forc.lock b/test/src/sdk-harness/test_artifacts/methods_abi/Forc.lock new file mode 100644 index 00000000000..1fb6b0979c0 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/methods_abi/Forc.lock @@ -0,0 +1,4 @@ +[[package]] +name = 'methods_abi' +source = 'root' +dependencies = [] diff --git a/test/src/sdk-harness/test_artifacts/methods_contract/Forc.lock b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.lock new file mode 100644 index 00000000000..4faa448e08d --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.lock @@ -0,0 +1,22 @@ +[[package]] +name = 'core' +source = 'path+from-root-051EC93A63B1E039' +dependencies = [] + +[[package]] +name = 'methods_abi' +source = 'path+from-root-051EC93A63B1E039' +dependencies = [] + +[[package]] +name = 'methods_contract' +source = 'root' +dependencies = [ + 'methods_abi', + 'std', +] + +[[package]] +name = 'std' +source = 'path+from-root-051EC93A63B1E039' +dependencies = ['core'] diff --git a/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml index 9c9f9cc728d..19f2d059625 100644 --- a/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml +++ b/test/src/sdk-harness/test_artifacts/methods_contract/Forc.toml @@ -6,4 +6,4 @@ name = "methods_contract" [dependencies] std = { path = "../../../../../sway-lib-std" } -methods_abi = { path = "../../test_abis/methods_abi" } +methods_abi = { path = "../methods_abi" } From 7e98ff0bf9be21e3a0f8cd65b656557660e56134 Mon Sep 17 00:00:00 2001 From: emilyaherbert Date: Mon, 20 Jun 2022 16:36:05 -0500 Subject: [PATCH 17/17] Fix test. --- test/src/sdk-harness/test_projects/methods/mod.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/src/sdk-harness/test_projects/methods/mod.rs b/test/src/sdk-harness/test_projects/methods/mod.rs index 760a7571353..1ed7b29d007 100644 --- a/test/src/sdk-harness/test_projects/methods/mod.rs +++ b/test/src/sdk-harness/test_projects/methods/mod.rs @@ -5,23 +5,23 @@ use fuels_abigen_macro::abigen; abigen!( MethodsContract, - "test_artifacts/methods_contract/out/debug/methods_abi-abi.json", + "test_artifacts/methods_contract/out/debug/methods_contract-abi.json", ); #[tokio::test] -async fn test_function() { +async fn run_methods_test() { let wallet = launch_provider_and_get_single_wallet().await; - let (instance, _) = get_methods_instance(wallet).await; + let instance = get_methods_instance(wallet).await; let result = instance .test_function() .call() .await .unwrap(); - assert_eq!(result, true); + assert_eq!(result.value, true); } -async fn get_methods_instance(wallet: Wallet) -> (MethodsContract, ContractId) { +async fn get_methods_instance(wallet: Wallet) -> MethodsContract { let id = Contract::deploy( "test_artifacts/methods_contract/out/debug/methods_contract.bin", &wallet, @@ -29,8 +29,5 @@ async fn get_methods_instance(wallet: Wallet) -> (MethodsContract, ContractId) { ) .await .unwrap(); - - let instance = MethodsContract::new(id.to_string(), wallet); - - (instance, id) + MethodsContract::new(id.to_string(), wallet) }