Improved error messages for foo(void), foo(int!) declarations.

This commit is contained in:
Christoffer Lerno
2022-08-11 12:59:55 +02:00
parent 48fb342834
commit f513b6237f
14 changed files with 69 additions and 22 deletions

View File

@@ -1594,7 +1594,7 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path)
}
else
{
ASSIGN_TYPE_OR_RET(type, parse_failable_type(c), poisoned_expr);
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), poisoned_expr);
}
if (tok_is(c, TOKEN_LBRACE))
{

View File

@@ -703,7 +703,7 @@ TypeInfo *parse_type(ParseContext *c)
return parse_type_with_base(c, base);
}
TypeInfo *parse_failable_type(ParseContext *c)
TypeInfo *parse_optional_type(ParseContext *c)
{
ASSIGN_TYPE_OR_RET(TypeInfo *info, parse_base_type(c), poisoned_type_info);
ASSIGN_TYPE_OR_RET(info, parse_type_with_base(c, info), poisoned_type_info);
@@ -771,7 +771,7 @@ Decl *parse_decl(ParseContext *c)
bool is_threadlocal = try_consume(c, TOKEN_TLOCAL);
bool is_static = !is_threadlocal && try_consume(c, TOKEN_STATIC);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_failable_type(c), poisoned_decl);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
ASSIGN_DECL_OR_RET(Decl * decl, parse_decl_after_type(c, type), poisoned_decl);
if (type->failable && decl->var.unwrap)
@@ -959,7 +959,7 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
{
bool threadlocal = try_consume(c, TOKEN_TLOCAL);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_failable_type(c), poisoned_decl);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
Decl *decl = DECL_VAR_NEW(type, VARDECL_GLOBAL, visibility);
@@ -999,7 +999,12 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
*/
static inline bool parse_param_decl(ParseContext *c, Visibility parent_visibility, Decl*** parameters, bool require_name)
{
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_type(c), false);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), false);
if (type->failable)
{
SEMA_ERROR(type, "Parameters may not be failable.");
return false;
}
bool vararg = try_consume(c, TOKEN_ELLIPSIS);
Decl *param = DECL_VAR_NEW(type, VARDECL_PARAM, parent_visibility);
param->var.vararg = vararg;
@@ -1069,7 +1074,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
if (!ellipsis && parse_next_is_typed_parameter(c))
{
ASSIGN_TYPE_OR_RET(type, parse_type(c), false);
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
ellipsis = try_consume(c, TOKEN_ELLIPSIS);
}
@@ -1159,7 +1164,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
default:
if (!type && parse_next_may_be_type(c))
{
ASSIGN_TYPE_OR_RET(type, parse_type(c), false);
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
param_kind = VARDECL_PARAM;
no_name = true;
span = type->span;
@@ -1168,6 +1173,11 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
SEMA_ERROR_HERE("Expected a parameter.");
return false;
}
if (type && type->failable)
{
SEMA_ERROR(type, "Parameters may not be failable.");
return false;
}
Decl *param = decl_new_var(name, span, type, param_kind, visibility);
param->var.type_info = type;
if (!no_name)
@@ -1523,7 +1533,7 @@ static inline Decl *parse_define_type(ParseContext *c, Visibility visibility)
Decl *decl = decl_new_with_type(alias_name, name_loc, DECL_TYPEDEF, visibility);
decl->typedef_decl.is_func = true;
decl->typedef_decl.is_distinct = distinct;
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_failable_type(c), poisoned_decl);
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
decl->typedef_decl.function_signature.returntype = type_infoid(type_info);
if (!parse_parameter_list(c, decl->visibility, &(decl->typedef_decl.function_signature), true))
{
@@ -1726,7 +1736,7 @@ static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
}
// 2. Now we must have a type - either that is the return type or the method type.
ASSIGN_TYPE_OR_RET(rtype, parse_failable_type(c), false);
ASSIGN_TYPE_OR_RET(rtype, parse_optional_type(c), false);
// 4. We might have a type here, if so then we read it.
if (!tok_is(c, TOKEN_DOT) && !parse_is_macro_name(c))

View File

@@ -375,7 +375,7 @@ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach)
// If we don't get foreach (foo ... or foreach (*foo ... then a type is expected.
if (!tok_is(c, TOKEN_IDENT) && !tok_is(c, TOKEN_AMP))
{
ASSIGN_TYPE_OR_RET(type, parse_failable_type(c), false);
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
// Add the failable to the type for nicer error reporting.
RANGE_EXTEND_PREV(type);

View File

@@ -24,7 +24,7 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path);
Expr *parse_expr(ParseContext *c);
bool consume_ident(ParseContext *c, const char* name);
TypeInfo *parse_type(ParseContext *c);
TypeInfo *parse_failable_type(ParseContext *c);
TypeInfo *parse_optional_type(ParseContext *c);
TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info);
Expr* parse_constant_expr(ParseContext *c);
void parse_imports(ParseContext *c);

View File

@@ -49,8 +49,20 @@ static bool sema_check_section(SemaContext *context, Attr *attr)
return true;
}
static inline bool sema_check_no_duplicate_parameter(Decl **decls, Decl *current, unsigned current_index, unsigned count)
static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count)
{
if (current->type && current->type == type_void)
{
if (count == 1 && !current->name && current->var.kind == VARDECL_PARAM)
{
SEMA_ERROR(current, "C-style 'foo(void)' style argument declarations are not valid, please remove 'void'.");
}
else
{
SEMA_ERROR(current, "Parameters may not be of type 'void'.");
}
return false;
}
const char *name = current->name;
if (!name) return true;
for (int i = 0; i < current_index; i++)
@@ -637,7 +649,7 @@ static inline Type *sema_analyse_function_signature(SemaContext *context, CallAB
all_ok = false;
continue;
}
if (!sema_check_no_duplicate_parameter(params, param, i, param_count))
if (!sema_check_param_uniqueness_and_type(params, param, i, param_count))
{
all_ok = false;
continue;
@@ -1980,7 +1992,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
case VARDECL_ERASE:
UNREACHABLE
}
if (!sema_check_no_duplicate_parameter(parameters, param, i, param_count)) return decl_poison(decl);
if (!sema_check_param_uniqueness_and_type(parameters, param, i, param_count)) return decl_poison(decl);
param->resolve_status = RESOLVE_DONE;
}
DeclId body_param = decl->macro_decl.body_param;
@@ -2021,7 +2033,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
case VARDECL_ERASE:
UNREACHABLE
}
if (!sema_check_no_duplicate_parameter(body_parameters, param, i, body_param_count)) return decl_poison(decl);
if (!sema_check_param_uniqueness_and_type(body_parameters, param, i, body_param_count)) return decl_poison(decl);
param->resolve_status = RESOLVE_DONE;
}
bool pure = false;

View File

@@ -1416,12 +1416,27 @@ FAIL_MISSING:
if (params && params[i]->var.vararg) continue;
// 17d. Argument missing, that's bad.
if (is_func_ptr)
if (!uses_named_parameters || is_func_ptr || !params[i]->name)
{
SEMA_ERROR(call, "The call is missing parameter(s), please check the definition.");
if (entries_needed == 1)
{
SEMA_ERROR(call, "A parameter was expected for the call.");
return false;
}
if (num_args)
{
unsigned needed = entries_needed - num_args;
SEMA_ERROR(args[num_args - 1],
"Expected %d more %s after this one, did you forget %s?",
needed, needed > 1 ? "arguments" : "argument", needed > 1 ? "them" : "it");
}
else
{
SEMA_ERROR(call, "The call needs %d parameters, please provide them.", entries_needed);
}
return false;
}
SEMA_ERROR(call, "The mandatory parameter '%s' was not set, please add it.", params[i]->name);
SEMA_ERROR(call, "The parameter '%s' must be set, did you forget it?", params[i]->name);
return false;
}
call->call_expr.arguments = actual_args;