diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index 76905296788..d080abe9a53 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -139,6 +139,18 @@ impl DisplayWithEngines for Box { } } +impl DisplayWithEngines for Vec { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + let text = self + .iter() + .map(|e| format!("{}", engines.help_out(e))) + .collect::>() + .join(", ") + .to_string(); + f.write_str(&text) + } +} + pub(crate) trait DebugWithEngines { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result; } @@ -164,6 +176,18 @@ impl DebugWithEngines for Box { } } +impl DebugWithEngines for Vec { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + let text = self + .iter() + .map(|e| format!("{:?}", engines.help_out(e))) + .collect::>() + .join(", ") + .to_string(); + f.write_str(&text) + } +} + pub trait HashWithEngines { fn hash(&self, state: &mut H, engines: &Engines); } 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 3ec50a2849b..b9bdfdcae3c 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 @@ -875,6 +875,29 @@ fn type_check_trait_implementation( match item { TyImplItem::Fn(decl_ref) => { let mut method = decl_engine.get_function(decl_ref); + + // We need to add impl type parameters to the method's type parameters + // so that in-line monomorphization can complete. + // + // We also need to add impl type parameters to the method's type + // parameters so the type constraints are correctly applied to the method. + // + // NOTE: this is a semi-hack that is used to force monomorphization of + // trait methods that contain a generic defined in the parent impl... + // without stuffing the generic into the method's type parameters, its + // not currently possible to monomorphize on that generic at function + // application time. + method.type_parameters.append( + &mut impl_type_parameters + .iter() + .cloned() + .map(|mut t| { + t.is_from_parent = true; + t + }) + .collect::>(), + ); + method.replace_decls(&decl_mapping, handler, &mut ctx)?; method.subst(&type_mapping, engines); all_items_refs.push(TyImplItem::Fn( @@ -1119,7 +1142,7 @@ fn type_check_impl_method( ); } - // We need to add impl type parameters to the method's type parameters + // We need to add impl type parameters to the method's type parameters // so that in-line monomorphization can complete. // // We also need to add impl type parameters to the method's type diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index c28a13c5f34..5b3104ee472 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -563,7 +563,7 @@ impl DebugWithEngines for TypeInfo { let s = match self { Unknown => "unknown".into(), UnknownGeneric { name, .. } => name.to_string(), - Placeholder(_) => "_".to_string(), + Placeholder(t) => format!("placeholder({:?})", engines.help_out(t)), TypeParam(n) => format!("typeparam({n})"), StringSlice => "str".into(), StringArray(x) => format!("str[{}]", x.val()), diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.lock new file mode 100644 index 00000000000..506066330b5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = "trait_method_and_generic_trait_impl" +source = "member" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.toml new file mode 100644 index 00000000000..1f1915308c9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/Forc.toml @@ -0,0 +1,6 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "trait_method_and_generic_trait_impl" +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/src/main.sw new file mode 100644 index 00000000000..17a0ebf29d0 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/src/main.sw @@ -0,0 +1,34 @@ +script; + +struct MyStruct { + val: T +} + +trait MyTrait { + fn foo(self, other: Self) -> bool; +} { + fn bar(self, other: Self) -> bool { + self.foo(other) + } +} + +impl MyTrait for MyStruct where T: MyTrait { + fn foo(self, other: Self) -> bool { + self.val.foo(other.val) + } +} + +fn main() -> bool { + let my_struct_1 = MyStruct { val: 5 }; + let my_struct_2 = MyStruct { val: 9 }; + + // Calling foo() gives us the following expected error: + // Trait "MyTrait" is not implemented for type "u64". + my_struct_1.foo(my_struct_2); + + // Calling bar() gives us the following expected error: + // Trait "MyTrait" is not implemented for type "u64". + my_struct_1.bar(my_struct_2); + + true +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/test.toml new file mode 100644 index 00000000000..6ea45dca41e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/trait_method_and_generic_trait_impl/test.toml @@ -0,0 +1,7 @@ +category = "fail" + +# check: $()my_struct_1.foo(my_struct_2); +# nextln: $()Trait "MyTrait" is not implemented for type "u64". + +# check: $()my_struct_1.bar(my_struct_2); +# nextln: $()Trait "MyTrait" is not implemented for type "u64".