diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index c6d9e0c5e37..b4ac96b8d83 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -188,6 +188,7 @@ impl CollectTypesMetadata for TyExpression { arguments, fn_ref, call_path, + type_binding, .. } => { for arg in arguments.iter() { @@ -196,8 +197,30 @@ impl CollectTypesMetadata for TyExpression { let function_decl = decl_engine.get_function(fn_ref); ctx.call_site_push(); - for type_parameter in &function_decl.type_parameters { - ctx.call_site_insert(type_parameter.type_id, call_path.span()) + for (idx, type_parameter) in function_decl.type_parameters.iter().enumerate() { + ctx.call_site_insert(type_parameter.type_id, call_path.span()); + + // Verify type arguments are concrete + res.extend( + type_parameter + .type_id + .collect_types_metadata(handler, ctx)? + .into_iter() + // try to use the caller span for better error messages + .map(|x| match x { + TypeMetadata::UnresolvedType(ident, original_span) => { + let span = type_binding + .as_ref() + .and_then(|type_binding| { + type_binding.type_arguments.as_slice().get(idx) + }) + .map(|type_argument| Some(type_argument.span.clone())) + .unwrap_or(original_span); + TypeMetadata::UnresolvedType(ident, span) + } + x => x, + }), + ); } for content in function_decl.body.contents.iter() { diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index bc6085919ba..d029cc2d772 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -61,8 +61,10 @@ impl CollectTypesMetadata for TypeId { ctx: &mut CollectTypesMetadataContext, ) -> Result, ErrorEmitted> { fn filter_fn(type_info: &TypeInfo) -> bool { - matches!(type_info, TypeInfo::UnknownGeneric { .. }) - || matches!(type_info, TypeInfo::Placeholder(_)) + matches!( + type_info, + TypeInfo::UnknownGeneric { .. } | TypeInfo::Placeholder(_) + ) } let engines = ctx.engines; let possible = self.extract_any_including_self(engines, &filter_fn, vec![], 0); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/src/main.sw index 6927766f189..08605fa28fa 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/src/main.sw @@ -1,10 +1,43 @@ script; +struct S {} + +impl S { + fn one_generic(self) { } + fn two_generics(self) { } +} + +struct W { } + fn main() { let g: bool = three_generics(true, "foo", 10); + + // Should fail because compiler cannot infer generic argument T + one_generic(); + + // Should fail because compiler cannot infer generic arguments A, B + two_generics(); + + // Two generics arguments expected + two_generics::(); + + // Should fail because compiler cannot infer generic argument T + S{}.one_generic(); + + // Should fail because compiler cannot infer generic arguments A, B + S{}.two_generics(); + + // Two generics arguments expected + S{}.two_generics::(); + + // Missing generic argument of W + one_generic::(); } fn three_generics(a: A, b: B, c: C) -> A { let new_a: A = a; new_a } + +fn one_generic() { } +fn two_generics() { } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/test.toml index af45dbb8e7e..471410b9291 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/missing_type_parameters/test.toml @@ -6,3 +6,30 @@ category = "fail" # check: $()Unknown type name "B" # check: $()Could not find symbol "C" in this scope. # check: $()Unknown type name "C" + +# check: $()two_generics::(); +# nextln: $()Expected 2 type arguments for "two_generics", but instead found 1. + +# check: $()S{}.two_generics::(); +# nextln: $()Expected 2 type arguments for "two_generics", but instead found 1. + +# check: $()one_generic() +# nextln: $()Cannot infer type for type parameter "T". Insufficient type information provided. Try annotating its type. + +# check: $()two_generics(); +# nextln: $()Cannot infer type for type parameter "A". Insufficient type information provided. Try annotating its type. + +# check: $()two_generics(); +# nextln: $()Cannot infer type for type parameter "B". Insufficient type information provided. Try annotating its type. + +# check: $()S{}.one_generic() +# nextln: $()Cannot infer type for type parameter "T". Insufficient type information provided. Try annotating its type. + +# check: $()S{}.two_generics(); +# nextln: $()Cannot infer type for type parameter "A". Insufficient type information provided. Try annotating its type. + +# check: $()S{}.two_generics(); +# nextln: $()Cannot infer type for type parameter "B". Insufficient type information provided. Try annotating its type. + +# check: $()one_generic::(); +# nextln: $()Cannot infer type for type parameter "A". Insufficient type information provided. Try annotating its type. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw index 261bd8cb0e8..532709bfed7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw @@ -303,6 +303,6 @@ fn test_storage() { // If these comparisons are done inline just above then it blows out the register allocator due to // all the ASM blocks. #[inline(never)] -fn assert_streq(lhs: S1, rhs: str) { +fn assert_streq(lhs: S1, rhs: str) { assert(sha256_str_array(lhs) == sha256(rhs)); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/src/main.sw index 934376a211b..d84c9d9ee3b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/src/main.sw @@ -291,6 +291,6 @@ fn test_storage() { // If these comparisons are done inline just above then it blows out the register allocator due to // all the ASM blocks. #[inline(never)] -fn assert_streq(lhs: S1, rhs: str) { +fn assert_streq(lhs: S1, rhs: str) { assert(sha256_str_array(lhs) == sha256(rhs)); }