diff --git a/sway-core/src/decl_engine/associated_item_decl_id.rs b/sway-core/src/decl_engine/associated_item_decl_id.rs index ea62c67c7b6..ea91c1730ed 100644 --- a/sway-core/src/decl_engine/associated_item_decl_id.rs +++ b/sway-core/src/decl_engine/associated_item_decl_id.rs @@ -1,9 +1,11 @@ use sway_error::error::CompileError; -use sway_types::Span; +use sway_types::{Named, Span, Spanned}; use crate::{ decl_engine::*, + engine_threading::DisplayWithEngines, language::ty::{self, TyFunctionDecl}, + Engines, }; #[derive(Debug, Eq, PartialEq, Hash, Clone)] @@ -14,6 +16,17 @@ pub enum AssociatedItemDeclId { Type(DeclId), } +impl AssociatedItemDeclId { + pub fn span(&self, engines: &Engines) -> Span { + match self { + Self::TraitFn(decl_id) => engines.de().get(decl_id).span(), + Self::Function(decl_id) => engines.de().get(decl_id).span(), + Self::Constant(decl_id) => engines.de().get(decl_id).span(), + Self::Type(decl_id) => engines.de().get(decl_id).span(), + } + } +} + impl From> for AssociatedItemDeclId { fn from(val: DeclId) -> Self { Self::Function(val) @@ -97,6 +110,29 @@ impl std::fmt::Display for AssociatedItemDeclId { } } +impl DisplayWithEngines for AssociatedItemDeclId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>, engines: &Engines) -> std::fmt::Result { + match self { + Self::TraitFn(decl_id) => { + write!( + f, + "decl(trait function {})", + engines.de().get(decl_id).name() + ) + } + Self::Function(decl_id) => { + write!(f, "decl(function {})", engines.de().get(decl_id).name()) + } + Self::Constant(decl_id) => { + write!(f, "decl(constant {})", engines.de().get(decl_id).name()) + } + Self::Type(decl_id) => { + write!(f, "decl(type {})", engines.de().get(decl_id).name()) + } + } + } +} + impl TryFrom for DeclRefFunction { type Error = CompileError; fn try_from(value: DeclRefMixedFunctional) -> Result { diff --git a/sway-core/src/decl_engine/mapping.rs b/sway-core/src/decl_engine/mapping.rs index 231a339abb5..ca6e6baed81 100644 --- a/sway-core/src/decl_engine/mapping.rs +++ b/sway-core/src/decl_engine/mapping.rs @@ -1,17 +1,21 @@ -use std::fmt; +use std::{collections::HashSet, fmt}; + +use sway_error::handler::{ErrorEmitted, Handler}; use crate::{ + engine_threading::DebugWithEngines, language::ty::{TyTraitInterfaceItem, TyTraitItem}, Engines, TypeId, UnifyCheck, }; -use super::{AssociatedItemDeclId, DeclEngineGet, InterfaceItemMap, ItemMap}; +use super::{AssociatedItemDeclId, InterfaceItemMap, ItemMap}; -type SourceDecl = AssociatedItemDeclId; +type SourceDecl = (AssociatedItemDeclId, TypeId); type DestinationDecl = AssociatedItemDeclId; /// The [DeclMapping] is used to create a mapping between a [SourceDecl] (LHS) /// and a [DestinationDecl] (RHS). +#[derive(Clone)] pub struct DeclMapping { mapping: Vec<(SourceDecl, DestinationDecl)>, } @@ -26,7 +30,7 @@ impl fmt::Display for DeclMapping { .map(|(source_type, dest_type)| { format!( "{} -> {}", - source_type, + source_type.0, match dest_type { AssociatedItemDeclId::TraitFn(decl_id) => decl_id.inner(), AssociatedItemDeclId::Function(decl_id) => decl_id.inner(), @@ -55,17 +59,27 @@ impl fmt::Debug for DeclMapping { } } -impl DeclMapping { - pub(crate) fn new() -> Self { - Self { - mapping: Vec::new(), - } - } - - pub(crate) fn insert(&mut self, k: SourceDecl, v: DestinationDecl) { - self.mapping.push((k, v)) +impl DebugWithEngines for DeclMapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + write!( + f, + "DeclMapping {{ {} }}", + self.mapping + .iter() + .map(|(source_type, dest_type)| { + format!( + "{} -> {}", + engines.help_out(source_type.0.clone()), + engines.help_out(dest_type) + ) + }) + .collect::>() + .join(", ") + ) } +} +impl DeclMapping { pub(crate) fn is_empty(&self) -> bool { self.mapping.is_empty() } @@ -79,9 +93,15 @@ impl DeclMapping { for (interface_decl_name, interface_item) in interface_decl_refs.into_iter() { if let Some(new_item) = impld_decl_refs.get(&interface_decl_name) { let interface_decl_ref = match interface_item { - TyTraitInterfaceItem::TraitFn(decl_ref) => decl_ref.id().into(), - TyTraitInterfaceItem::Constant(decl_ref) => decl_ref.id().into(), - TyTraitInterfaceItem::Type(decl_ref) => decl_ref.id().into(), + TyTraitInterfaceItem::TraitFn(decl_ref) => { + (decl_ref.id().into(), interface_decl_name.1) + } + TyTraitInterfaceItem::Constant(decl_ref) => { + (decl_ref.id().into(), interface_decl_name.1) + } + TyTraitInterfaceItem::Type(decl_ref) => { + (decl_ref.id().into(), interface_decl_name.1) + } }; let new_decl_ref = match new_item { TyTraitItem::Fn(decl_ref) => decl_ref.id().into(), @@ -94,9 +114,9 @@ impl DeclMapping { for (decl_name, item) in item_decl_refs.into_iter() { if let Some(new_item) = impld_decl_refs.get(&decl_name) { let interface_decl_ref = match item { - TyTraitItem::Fn(decl_ref) => decl_ref.id().into(), - TyTraitItem::Constant(decl_ref) => decl_ref.id().into(), - TyTraitItem::Type(decl_ref) => decl_ref.id().into(), + TyTraitItem::Fn(decl_ref) => (decl_ref.id().into(), decl_name.1), + TyTraitItem::Constant(decl_ref) => (decl_ref.id().into(), decl_name.1), + TyTraitItem::Type(decl_ref) => (decl_ref.id().into(), decl_name.1), }; let new_decl_ref = match new_item { TyTraitItem::Fn(decl_ref) => decl_ref.id().into(), @@ -109,39 +129,41 @@ impl DeclMapping { DeclMapping { mapping } } - pub(crate) fn find_match(&self, decl_ref: SourceDecl) -> Option { - for (source_decl_ref, dest_decl_ref) in self.mapping.iter() { - if *source_decl_ref == decl_ref { - return Some(dest_decl_ref.clone()); - } - } - None - } - - /// This method returns only associated item functions that have as self type the given type. - pub(crate) fn filter_functions_by_self_type( + pub(crate) fn find_match( &self, - self_type: TypeId, + _handler: &Handler, engines: &Engines, - ) -> DeclMapping { - let mut mapping: Vec<(SourceDecl, DestinationDecl)> = vec![]; - for (source_decl_ref, dest_decl_ref) in self.mapping.iter().cloned() { - match dest_decl_ref { - AssociatedItemDeclId::TraitFn(_) => mapping.push((source_decl_ref, dest_decl_ref)), - AssociatedItemDeclId::Function(func_id) => { - let func = engines.de().get(&func_id); + decl_ref: AssociatedItemDeclId, + typeid: Option, + self_typeid: Option, + ) -> Result, ErrorEmitted> { + let mut dest_decl_refs = HashSet::::new(); - let unify_check = UnifyCheck::non_dynamic_equality(engines); - if let (left, Some(right)) = (self_type, func.parameters.first()) { - if unify_check.check(left, right.type_argument.type_id) { - mapping.push((source_decl_ref, dest_decl_ref)); - } - } + if let Some(mut typeid) = typeid { + if engines.te().get(typeid).is_self_type() && self_typeid.is_some() { + // If typeid is `Self`, then we use the self_typeid instead. + typeid = self_typeid.unwrap(); + } + for (source_decl_ref, dest_decl_ref) in self.mapping.iter() { + let unify_check = UnifyCheck::non_dynamic_equality(engines); + if source_decl_ref.0 == decl_ref && unify_check.check(source_decl_ref.1, typeid) { + dest_decl_refs.insert(dest_decl_ref.clone()); } - AssociatedItemDeclId::Constant(_) => mapping.push((source_decl_ref, dest_decl_ref)), - AssociatedItemDeclId::Type(_) => mapping.push((source_decl_ref, dest_decl_ref)), } } - DeclMapping { mapping } + + // At most one replacement should be found for decl_ref. + /* TODO uncomment this and close issue #5540 + if dest_decl_refs.len() > 1 { + handler.emit_err(CompileError::InternalOwned( + format!( + "Multiple replacements for decl {} implemented in {}", + engines.help_out(decl_ref), + engines.help_out(typeid), + ), + dest_decl_refs.iter().last().unwrap().span(engines), + )); + }*/ + Ok(dest_decl_refs.iter().next().cloned()) } } diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index 58c90fd256b..48dec69fdc5 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -294,12 +294,21 @@ impl ReplaceDecls for DeclRefFunction { fn replace_decls_inner( &mut self, decl_mapping: &DeclMapping, - _handler: &Handler, + handler: &Handler, ctx: &mut TypeCheckContext, ) -> Result<(), ErrorEmitted> { let engines = ctx.engines(); let decl_engine = engines.de(); - if let Some(new_decl_ref) = decl_mapping.find_match(self.id.into()) { + + let func = decl_engine.get(self); + + if let Some(new_decl_ref) = decl_mapping.find_match( + handler, + ctx.engines(), + self.id.into(), + func.implementing_for_typeid, + ctx.self_type(), + )? { if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref { self.id = new_decl_ref; } @@ -307,7 +316,13 @@ impl ReplaceDecls for DeclRefFunction { } let all_parents = decl_engine.find_all_parents(engines, &self.id); for parent in all_parents.iter() { - if let Some(new_decl_ref) = decl_mapping.find_match(parent.clone()) { + if let Some(new_decl_ref) = decl_mapping.find_match( + handler, + ctx.engines(), + parent.clone(), + func.implementing_for_typeid, + ctx.self_type(), + )? { if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref { self.id = new_decl_ref; } diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 54c64ff2038..81436492356 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -30,6 +30,7 @@ pub struct TyFunctionDecl { pub body: TyCodeBlock, pub parameters: Vec, pub implementing_type: Option, + pub implementing_for_typeid: Option, pub span: Span, pub call_path: CallPath, pub attributes: transform::AttributesMap, @@ -159,6 +160,7 @@ impl HashWithEngines for TyFunctionDecl { span: _, attributes: _, implementing_type: _, + implementing_for_typeid: _, where_clause: _, is_trait_method_dummy: _, } = self; @@ -183,6 +185,9 @@ impl SubstTypes for TyFunctionDecl { .for_each(|x| x.subst(type_mapping, engines)); self.return_type.subst(type_mapping, engines); self.body.subst(type_mapping, engines); + if let Some(implementing_for) = self.implementing_for_typeid.as_mut() { + implementing_for.subst(type_mapping, engines); + } } } @@ -193,7 +198,9 @@ impl ReplaceDecls for TyFunctionDecl { handler: &Handler, ctx: &mut TypeCheckContext, ) -> Result<(), ErrorEmitted> { - self.body.replace_decls(decl_mapping, handler, ctx) + let mut func_ctx = ctx.by_ref().with_self_type(self.implementing_for_typeid); + self.body + .replace_decls(decl_mapping, handler, &mut func_ctx) } } @@ -296,6 +303,7 @@ impl TyFunctionDecl { name: name.clone(), body: TyCodeBlock::default(), implementing_type: None, + implementing_for_typeid: None, span: span.clone(), call_path: CallPath::from(Ident::dummy()), attributes: Default::default(), diff --git a/sway-core/src/language/ty/declaration/trait.rs b/sway-core/src/language/ty/declaration/trait.rs index 9107e944382..c5fdeeb24d7 100644 --- a/sway-core/src/language/ty/declaration/trait.rs +++ b/sway-core/src/language/ty/declaration/trait.rs @@ -8,8 +8,8 @@ use sway_types::{Ident, Named, Span, Spanned}; use crate::{ decl_engine::{ - mapping::DeclMapping, DeclEngineReplace, DeclRefConstant, DeclRefFunction, DeclRefTraitFn, - DeclRefTraitType, ReplaceFunctionImplementingType, + DeclEngineReplace, DeclRefConstant, DeclRefFunction, DeclRefTraitFn, DeclRefTraitType, + ReplaceFunctionImplementingType, }, engine_threading::*, language::{parsed, CallPath, Visibility}, @@ -44,6 +44,35 @@ pub enum TyTraitInterfaceItem { Type(DeclRefTraitType), } +impl DisplayWithEngines for TyTraitInterfaceItem { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + write!(f, "{:?}", engines.help_out(self)) + } +} + +impl DebugWithEngines for TyTraitInterfaceItem { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + write!( + f, + "TyTraitItem {}", + match self { + TyTraitInterfaceItem::TraitFn(fn_ref) => format!( + "fn {:?}", + engines.help_out(&*engines.de().get_trait_fn(fn_ref)) + ), + TyTraitInterfaceItem::Constant(const_ref) => format!( + "const {:?}", + engines.help_out(&*engines.de().get_constant(const_ref)) + ), + TyTraitInterfaceItem::Type(type_ref) => format!( + "type {:?}", + engines.help_out(&*engines.de().get_type(type_ref)) + ), + } + ) + } +} + #[derive(Clone, Debug)] pub enum TyTraitItem { Fn(DeclRefFunction), @@ -242,7 +271,6 @@ impl Spanned for TyTraitItem { impl SubstTypes for TyTraitDecl { fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: &Engines) { - let mut decl_mapping = DeclMapping::new(); self.type_parameters .iter_mut() .for_each(|x| x.subst(type_mapping, engines)); @@ -253,14 +281,12 @@ impl SubstTypes for TyTraitDecl { let new_item_ref = item_ref .clone() .subst_types_and_insert_new_with_parent(type_mapping, engines); - decl_mapping.insert(item_ref.id().into(), new_item_ref.id().into()); item_ref.replace_id(*new_item_ref.id()); } TyTraitInterfaceItem::Constant(decl_ref) => { let new_decl_ref = decl_ref .clone() .subst_types_and_insert_new(type_mapping, engines); - decl_mapping.insert(decl_ref.id().into(), new_decl_ref.id().into()); decl_ref.replace_id(*new_decl_ref.id()); } TyTraitInterfaceItem::Type(decl_ref) => { diff --git a/sway-core/src/language/ty/declaration/trait_fn.rs b/sway-core/src/language/ty/declaration/trait_fn.rs index d4a53972bcb..f090e5d7f75 100644 --- a/sway-core/src/language/ty/declaration/trait_fn.rs +++ b/sway-core/src/language/ty/declaration/trait_fn.rs @@ -1,4 +1,7 @@ -use std::hash::{Hash, Hasher}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; use sway_types::{Ident, Named, Span, Spanned}; @@ -20,6 +23,26 @@ pub struct TyTraitFn { pub attributes: transform::AttributesMap, } +impl DebugWithEngines for TyTraitFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + write!( + f, + "{:?}({}):{}", + self.name, + self.parameters + .iter() + .map(|p| format!( + "{}:{}", + p.name.as_str(), + engines.help_out(p.type_argument.initial_type_id) + )) + .collect::>() + .join(", "), + engines.help_out(self.return_type.initial_type_id), + ) + } +} + impl Named for TyTraitFn { fn name(&self) -> &Ident { &self.name diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index c2c4e3ea516..f2f3db78599 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -626,6 +626,7 @@ impl SubstTypes for TyExpressionVariant { FunctionApplication { arguments, ref mut fn_ref, + ref mut call_path_typeid, .. } => { arguments @@ -635,6 +636,9 @@ impl SubstTypes for TyExpressionVariant { .clone() .subst_types_and_insert_new_with_parent(type_mapping, engines); fn_ref.replace_id(*new_decl_ref.id()); + if let Some(call_path_typeid) = call_path_typeid { + call_path_typeid.subst(type_mapping, engines); + } } LazyOperator { lhs, rhs, .. } => { (*lhs).subst(type_mapping, engines); @@ -779,15 +783,7 @@ impl ReplaceDecls for TyExpressionVariant { ref mut arguments, .. } => { - let filter_type_opt = arguments.first().map(|(_, arg)| arg.return_type); - - if let Some(filter_type) = filter_type_opt { - let filtered_decl_mapping = - decl_mapping.filter_functions_by_self_type(filter_type, ctx.engines()); - fn_ref.replace_decls(&filtered_decl_mapping, handler, ctx)?; - } else { - fn_ref.replace_decls(decl_mapping, handler, ctx)?; - }; + fn_ref.replace_decls(decl_mapping, handler, ctx)?; let new_decl_ref = fn_ref.clone().replace_decls_and_insert_new_with_parent( decl_mapping, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 42b7b141002..16632fc2a01 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -172,9 +172,15 @@ impl ty::TyAbiDecl { let mut new_items = vec![]; for method_id in methods.into_iter() { let method = engines.pe().get_function(&method_id); - let method = - ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), &method, false, false) - .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); + let method = ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + &method, + false, + false, + Some(self_type_param.type_id), + ) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); error_on_shadowing_superabi_method(&method.name, &mut ctx); for param in &method.parameters { if param.is_reference || param.is_mutable { @@ -280,10 +286,10 @@ impl ty::TyAbiDecl { all_items.push(TyImplItem::Fn( ctx.engines .de() - .insert(method.to_dummy_func(AbiMode::ImplAbiFn( - self.name.clone(), - Some(self_decl_id), - ))) + .insert(method.to_dummy_func( + AbiMode::ImplAbiFn(self.name.clone(), Some(self_decl_id)), + Some(type_id), + )) .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), )); } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index be587413368..0cd3b83b9e3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -122,6 +122,7 @@ impl TyDecl { &fn_decl, false, false, + None, ) { Ok(res) => res, Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), 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 008b0909782..a9996d829df 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -25,9 +25,16 @@ impl ty::TyFunctionDecl { fn_decl: &FunctionDeclaration, is_method: bool, is_in_impl_self: bool, + implementing_for_typeid: Option, ) -> Result { - let mut ty_fn_decl = - Self::type_check_signature(handler, ctx.by_ref(), fn_decl, is_method, is_in_impl_self)?; + let mut ty_fn_decl = Self::type_check_signature( + handler, + ctx.by_ref(), + fn_decl, + is_method, + is_in_impl_self, + implementing_for_typeid, + )?; Self::type_check_body(handler, ctx, fn_decl, &mut ty_fn_decl) } @@ -37,6 +44,7 @@ impl ty::TyFunctionDecl { fn_decl: &FunctionDeclaration, is_method: bool, is_in_impl_self: bool, + implementing_for_typeid: Option, ) -> Result { let FunctionDeclaration { name, @@ -139,6 +147,7 @@ impl ty::TyFunctionDecl { body: TyCodeBlock::default(), parameters: new_parameters, implementing_type: None, + implementing_for_typeid, span: span.clone(), call_path, attributes: attributes.clone(), @@ -357,6 +366,7 @@ fn test_function_selector_behavior() { purity: Default::default(), name: Ident::dummy(), implementing_type: None, + implementing_for_typeid: None, body: ty::TyCodeBlock::default(), parameters: vec![], span: Span::dummy(), @@ -380,6 +390,7 @@ fn test_function_selector_behavior() { purity: Default::default(), name: Ident::new_with_override("bar".into(), Span::dummy()), implementing_type: None, + implementing_for_typeid: None, body: ty::TyCodeBlock::default(), parameters: vec![ ty::TyFunctionParameter { 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 1d2d2e38fdd..e65ea4a206f 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 @@ -385,6 +385,7 @@ impl TyImplTrait { &fn_decl, true, true, + Some(implementing_for.type_id), ) { Ok(res) => res, Err(_) => continue, @@ -922,6 +923,7 @@ fn type_check_trait_implementation( .collect::>(), ); + method.implementing_for_typeid = Some(implementing_for); method.replace_decls(&decl_mapping, handler, &mut ctx)?; method.subst(&type_mapping, engines); all_items_refs.push(TyImplItem::Fn( @@ -1000,8 +1002,14 @@ fn type_check_impl_method( }; // type check the function declaration - let mut impl_method = - ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), impl_method, true, false)?; + let mut impl_method = ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + impl_method, + true, + false, + Some(implementing_for), + )?; // Ensure that there aren't multiple definitions of this function impl'd if impld_item_refs.contains_key(&(impl_method.name.clone(), implementing_for)) { 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 2db64684a3c..8d48cbeab41 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -137,7 +137,7 @@ impl TyTraitDecl { let decl_ref = decl_engine.insert(method.clone()); dummy_interface_surface.push(ty::TyImplItem::Fn( decl_engine - .insert(method.to_dummy_func(AbiMode::NonAbi)) + .insert(method.to_dummy_func(AbiMode::NonAbi, Some(self_type))) .with_parent(decl_engine, (*decl_ref.id()).into()), )); new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(decl_ref)); @@ -202,9 +202,15 @@ impl TyTraitDecl { let mut new_items = vec![]; for method_decl_id in methods.into_iter() { let method = engines.pe().get_function(&method_decl_id); - let method = - ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), &method, true, false) - .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); + let method = ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + &method, + true, + false, + Some(self_type_param.type_id), + ) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(&method)); new_items.push(ty::TyTraitItem::Fn(decl_engine.insert(method))); } @@ -428,7 +434,7 @@ impl TyTraitDecl { all_items.push(TyImplItem::Fn( ctx.engines .de() - .insert(method.to_dummy_func(AbiMode::NonAbi)) + .insert(method.to_dummy_func(AbiMode::NonAbi, Some(type_id))) .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), )); } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index bd40e9dfcf2..8ecfe2f094b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -77,7 +77,11 @@ impl ty::TyTraitFn { /// This function is used in trait declarations to insert "placeholder" /// functions in the methods. This allows the methods to use functions /// declared in the interface surface. - pub(crate) fn to_dummy_func(&self, abi_mode: AbiMode) -> ty::TyFunctionDecl { + pub(crate) fn to_dummy_func( + &self, + abi_mode: AbiMode, + implementing_for_typeid: Option, + ) -> ty::TyFunctionDecl { ty::TyFunctionDecl { purity: self.purity, name: self.name.clone(), @@ -97,6 +101,7 @@ impl ty::TyTraitFn { } AbiMode::NonAbi => None, }, + implementing_for_typeid, span: self.name.span(), call_path: CallPath::from(self.name.clone()), attributes: self.attributes.clone(), 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 5c929645fca..1dc50686418 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 @@ -1672,10 +1672,10 @@ impl ty::TyExpression { let method = decl_engine.get_trait_fn(decl_ref); abi_items.push(TyImplItem::Fn( decl_engine - .insert(method.to_dummy_func(AbiMode::ImplAbiFn( - abi_name.suffix.clone(), - Some(*abi_ref.id()), - ))) + .insert(method.to_dummy_func( + AbiMode::ImplAbiFn(abi_name.suffix.clone(), Some(*abi_ref.id())), + Some(return_type), + )) .with_parent(decl_engine, (*decl_ref.id()).into()), )); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.lock new file mode 100644 index 00000000000..324a704afdb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-7AAE81D36BEAEB00" + +[[package]] +name = "std" +source = "path+from-root-7AAE81D36BEAEB00" +dependencies = ["core"] + +[[package]] +name = "trait_nested" +source = "member" +dependencies = ["std"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.toml new file mode 100644 index 00000000000..a8ba8271288 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "trait_nested" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw new file mode 100644 index 00000000000..0593601061f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw @@ -0,0 +1,45 @@ +script; + +trait T1 { + fn trait_fn() -> Self; +} + +impl T1 for u64 { + fn trait_fn() -> u64 { + 42 + } +} + +impl T1 for (A, ) +where + A: T1 +{ + fn trait_fn() -> (A, ) { + (A::trait_fn(), ) + } +} + +fn f () -> T +where + T: T1 +{ + T::trait_fn() +} + +impl Eq for (u64,) { + fn eq(self, other: Self) -> bool { + self.0 == other.0 + } +} + +impl AbiEncode for (u64, ) { + fn abi_encode(self, ref mut buffer: Buffer) { + buffer.push(self.0); + } +} + +fn main() -> bool { + assert_eq(f::<(u64, )>(), (42,)); + + true +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/test.toml new file mode 100644 index 00000000000..14012ed8d21 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 1 } +validate_abi = false +expected_warnings = 3