Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check if all required generic arguments are valid #6462

Merged
merged 10 commits into from
Aug 28, 2024
27 changes: 25 additions & 2 deletions sway-core/src/language/ty/expression/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ impl CollectTypesMetadata for TyExpression {
arguments,
fn_ref,
call_path,
type_binding,
..
} => {
for arg in arguments.iter() {
Expand All @@ -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() {
Expand Down
6 changes: 4 additions & 2 deletions sway-core/src/type_system/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ impl CollectTypesMetadata for TypeId {
ctx: &mut CollectTypesMetadataContext,
) -> Result<Vec<TypeMetadata>, 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
script;

struct S {}

impl S {
fn one_generic<T>(self) { }
fn two_generics<A, B>(self) { }
}

struct W<A> { }

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::<u64>();

// 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::<u64>();

// Missing generic argument of W
one_generic::<W>();
}

fn three_generics(a: A, b: B, c: C) -> A {
let new_a: A = a;
new_a
}

fn one_generic<T>() { }
fn two_generics<A, B>() { }
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u64>();
# nextln: $()Expected 2 type arguments for "two_generics", but instead found 1.

# check: $()S{}.two_generics::<u64>();
# 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::<W>();
# nextln: $()Cannot infer type for type parameter "A". Insufficient type information provided. Try annotating its type.
Original file line number Diff line number Diff line change
Expand Up @@ -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<S1, S2>(lhs: S1, rhs: str) {
fn assert_streq<S1>(lhs: S1, rhs: str) {
assert(sha256_str_array(lhs) == sha256(rhs));
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<S1, S2>(lhs: S1, rhs: str) {
fn assert_streq<S1>(lhs: S1, rhs: str) {
assert(sha256_str_array(lhs) == sha256(rhs));
}
Loading