- Improve error message for Foo{} when Foo is not a generic type #2574.

This commit is contained in:
Christoffer Lerno
2025-11-16 23:54:19 +01:00
parent 1ea181524e
commit 06884720e5
5 changed files with 51 additions and 16 deletions

View File

@@ -11,6 +11,7 @@
- Enums now work with `membersof` to return the associated values. #2571
- Deprecated `SomeEnum.associated` in favour of `SomeEnum.membersof`
- Refactored `@simd` implementation.
- Improve error message for `Foo{}` when `Foo` is not a generic type #2574.
### Fixes
- `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable.

View File

@@ -75,13 +75,8 @@ bool parse_range(ParseContext *c, Range *range)
}
bool parse_generic_expr_list(ParseContext *c, Expr ***exprs_ref)
{
SourceSpan start = c->span;
advance_and_verify(c, TOKEN_LBRACE);
if (try_consume(c, TOKEN_RBRACE))
{
print_error_at(extend_span_with_token(start, c->prev_span), "At least one generic parameter was expected here.");
return false;
}
if (try_consume(c, TOKEN_RBRACE)) return true;
do
{
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), false);
@@ -2064,7 +2059,7 @@ ADVANCE:;
/**
* string_literal ::= STRING+
*/
static Expr *parse_string_literal(ParseContext *c, Expr *left, SourceSpan lhs_start)
static Expr *parse_string_literal(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
{
ASSERT(!left && "Had left hand side");
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST);
@@ -2082,7 +2077,7 @@ static Expr *parse_string_literal(ParseContext *c, Expr *left, SourceSpan lhs_st
/*
* bool ::= 'true' | 'false'
*/
static Expr *parse_bool(ParseContext *c, Expr *left, SourceSpan lhs_start)
static Expr *parse_bool(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
{
ASSERT(!left && "Had left hand side");
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST);

View File

@@ -5262,13 +5262,22 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con
unsigned parameter_count = vec_size(module->parameters);
ASSERT(parameter_count > 0);
if (parameter_count != vec_size(params))
unsigned count = vec_size(params);
if (parameter_count != count)
{
ASSERT_AT(span, vec_size(params));
sema_error_at(c, extend_span_with_token(params[0]->span, vectail(params)->span),
"The generic module expected %d arguments, but you supplied %d, did you make a mistake?",
parameter_count,
vec_size(params));
if (!count)
{
sema_error_at(c, invocation_span,
"'%s' must be instantiatied with generic module arguments inside the '{}', did you forget them?", name, (int)parameter_count);
}
else
{
sema_error_at(c, extend_span_with_token(params[0]->span, vectail(params)->span),
"The generic module expected %d argument(s), but you supplied %d, did you make a mistake?",
parameter_count,
vec_size(params));
}
return poisoned_decl;
}
if (!sema_generate_parameterized_name_to_scratch(c, module, params, true, was_recursive_ref)) return poisoned_decl;

View File

@@ -0,0 +1,30 @@
module foo;
import std, bar;
struct Foo
{
int i;
}
fn void foo(Foo f) {}
fn void a()
{
List{} a; // #error: must be instantiatied with generic module arguments
}
fn void b()
{
foo(Foo{}); // #error: 'Foo' is not a generic type
}
fn void c()
{
bar::test{}(); // #error: must be instantiatied with generic module arguments
}
fn int main()
{
return 0;
}
module bar{Type};
fn void test()
{}

View File

@@ -17,12 +17,12 @@ import std::collections::list;
fn void test1()
{
int x = values::test{}(); // #error: At least one generic parameter
int x = values::test{}(); // #error: must be instantiatied with generic
}
fn void test2()
{
List{Values{ }} v1s; // #error: At least one generic parameter
List{Values{ }} v1s; // #error: must be instantiatied with generic
}
fn void main()