Improve error message when using functions as values #2856

This commit is contained in:
Christoffer Lerno
2026-02-05 16:03:56 +01:00
parent 054fcd2deb
commit 016254d38c
7 changed files with 41 additions and 31 deletions

View File

@@ -4,6 +4,7 @@
### Changes / improvements
- Method resolution and `$define` now works together well unless definitions are out of order for real.
- Improve error message when using functions as values #2856
### Stdlib changes
- Summarize sort macros as generic function wrappers to reduce the amount of generated code. #2831

View File

@@ -65,7 +65,8 @@ void compiler_init(BuildOptions *build_options)
INFO_LOG("Version: %s", COMPILER_VERSION);
compiler.context = (GlobalContext) { .in_panic_mode = false };
GlobalContext new_context = { .in_panic_mode = false };
compiler.context = new_context;
// Skip library detection.
//compiler.lib_dir = find_lib_dir();
//DEBUG_LOG("Found std library: %s", compiler.lib_dir);

View File

@@ -592,7 +592,7 @@ void expr_insert_addr(Expr *original)
Expr *inner = expr_copy(original);
original->expr_kind = EXPR_UNARY;
original->type = new_type;
original->unary_expr = (ExprUnary) { .operator = UNARYOP_ADDR, .expr = inner };
original->unary_expr = (ExprUnary) { .operator = UNARYOP_ADDR, .expr = inner, .no_wrap = false, .no_read = false };
}
Expr *expr_generated_local(Expr *assign, Decl **decl_ref)
@@ -1189,6 +1189,6 @@ void expr_rewrite_const_string(Expr *expr_to_rewrite, const char *string)
void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op)
{
expr_to_rewrite->binary_expr = (ExprBinary) { .operator = op, .left = exprid(left), .right = exprid(right) };
expr_to_rewrite->binary_expr = (ExprBinary) { .operator = op, .left = exprid(left), .right = exprid(right), .grouped = false };
expr_to_rewrite->expr_kind = EXPR_BINARY;
}

View File

@@ -3691,7 +3691,8 @@ static inline bool sema_analyse_custom_attribute(SemaContext *context, ResolvedA
SemaContext eval_context;
sema_context_init(&eval_context, attr_decl->unit);
eval_context.macro_call_depth = context->macro_call_depth + 1;
eval_context.call_env = (CallEnv) { .kind = CALL_ENV_ATTR, .attr_declaration = decl, };
CallEnv eval_env = { .kind = CALL_ENV_ATTR, .attr_declaration = decl, };
eval_context.call_env = eval_env;
// We copy the compilation unit.
eval_context.compilation_unit = context->unit;
@@ -5372,7 +5373,8 @@ FOUND:;
{
SemaContext context_gen;
sema_context_init(&context_gen, decl->unit);
context_gen.active_scope = (DynamicScope) { .depth = 0 };
DynamicScope empty = { .depth = 0 };
context_gen.active_scope = empty;
sema_analyse_decl(&context_gen, decl);
context_gen.generic_instance = instance;
sema_analyse_inner_func_ptr(&context_gen, decl);

View File

@@ -953,9 +953,8 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
decl = decl_flatten(decl);
switch (decl->decl_kind)
{
case DECL_FNTYPE:
case DECL_FUNC:
SEMA_ERROR(expr, "Expected function followed by (...) or prefixed by &.");
SEMA_ERROR(expr, "A function name cannot be used as a value, did you want to pass it by pointer? If so then you need to add '&', like '&%s'.", decl->span);
return expr_poison(expr);
case DECL_MACRO:
SEMA_ERROR(expr, "Expected a macro followed by (...).");
@@ -968,6 +967,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
case DECL_FAULT:
expr_rewrite_const_fault(expr, decl);
return true;
case DECL_FNTYPE:
case DECL_ALIAS:
case DECL_ALIAS_PATH:
case DECL_ATTRIBUTE:
@@ -1647,7 +1647,8 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
{
Expr *inner = expr_copy(arg);
arg->expr_kind = EXPR_OTHER_CONTEXT;
arg->expr_other_context = (ExprOtherContext) { .context = context, .inner = inner };
ExprOtherContext other = { .context = context, .inner = inner };
arg->expr_other_context = other;
arg->resolve_status = RESOLVE_NOT_DONE;
}
break;
@@ -3599,8 +3600,9 @@ FOUND:;
new_path->module = kw_std__core__runtime;
new_path->span = expr->span;
new_path->len = strlen(kw_std__core__runtime);
call->unresolved_ident_expr = (ExprUnresolvedIdentifier) { .ident = kw_at_enum_lookup, .path = new_path };
expr->call_expr = (ExprCall) { .arguments = args, .function = exprid(call) };
call->unresolved_ident_expr = (ExprUnresolvedIdentifier) { .ident = kw_at_enum_lookup, .path = new_path, .is_const = false };
ExprCall call_expr = { .arguments = args, .function = exprid(call) };
expr->call_expr = call_expr;
expr->resolve_status = RESOLVE_NOT_DONE;
return sema_analyse_expr_rvalue(context, expr);
}
@@ -7405,8 +7407,8 @@ AFTER_ADDR:;
// init, expr -> lvalue = rvalue + a
expr->expr_kind = EXPR_BINARY;
left->expr_kind = EXPR_BINARY;
left->binary_expr = (ExprBinary) { .left = exprid(left_lvalue), .right = exprid(right), new_op };
expr->binary_expr = (ExprBinary) { .left = exprid(left_rvalue), .right = exprid(left), .operator = BINARYOP_ASSIGN, .grouped = false };
left->binary_expr = (ExprBinary) { exprid(left_lvalue), exprid(right), new_op, false };
expr->binary_expr = (ExprBinary) { exprid(left_rvalue), exprid(left), BINARYOP_ASSIGN, false };
expr->resolve_status = RESOLVE_NOT_DONE;
left->resolve_status = RESOLVE_NOT_DONE;
Expr *binary = expr_copy(expr);

View File

@@ -915,7 +915,7 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
RETURN_SEMA_ERROR(ident, "Expected this variable to be an optional, otherwise it can't be used for unwrap, maybe you didn't intend to use 'try'?");
}
expr->expr_kind = EXPR_TRY;
expr->try_expr = (ExprTry) { .decl = decl };
expr->try_expr = (ExprTry) { .decl = decl, .assign_existing = false };
expr->type = type_bool;
sema_unwrap_var(context, decl);
expr->resolve_status = RESOLVE_DONE;
@@ -977,7 +977,7 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
if (!sema_analyse_var_decl(context, decl, true, NULL)) return false;
expr->expr_kind = EXPR_TRY;
expr->try_expr = (ExprTry) { .decl = decl, .optional = optional };
expr->try_expr = (ExprTry) { .decl = decl, .optional = optional, .assign_existing = false };
expr->type = type_bool;
expr->resolve_status = RESOLVE_DONE;
return true;
@@ -3449,21 +3449,24 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
// Set up the context for analysis
context->original_module = NULL;
context->call_env = (CallEnv) {
CallEnv env = {
.current_function = func,
.is_naked_fn = func->func_decl.attr_naked,
.kind = CALL_ENV_FUNCTION,
.pure = func->func_decl.signature.attrs.is_pure,
.ignore_deprecation = func->allow_deprecated || decl_is_deprecated(func)
};
context->call_env = env;
Type *rtype = context->rtype = typeget(signature->rtype);
context->macro_call_depth = 0;
context->active_scope = (DynamicScope) {
.depth = 0,
.label_start = 0,
.current_local = 0
DynamicScope new_scope = {
.depth = 0,
.label_start = 0,
.current_local = 0
};
context->active_scope = new_scope;
vec_resize(context->ct_locals, 0);
// Clear returns
vec_resize(context->block_returns, 0);

View File

@@ -35,18 +35,19 @@ void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags, Sou
if (is_macro) flags &= ~(SCOPE_ENSURE | SCOPE_ENSURE_MACRO);
unsigned label_start = new_label_scope ? last_local : context->active_scope.label_start;
context->active_scope = (DynamicScope) {
.allow_dead_code = false,
.is_dead = scope_is_dead,
.is_poisoned = scope_is_poisoned,
.depth = depth,
.current_local = last_local,
.label_start = label_start,
.in_defer = previous_defer,
.defer_last = parent_defer,
.defer_start = parent_defer,
.flags = flags,
DynamicScope new_scope = {
.allow_dead_code = false,
.is_dead = scope_is_dead,
.is_poisoned = scope_is_poisoned,
.depth = depth,
.current_local = last_local,
.label_start = label_start,
.in_defer = previous_defer,
.defer_last = parent_defer,
.defer_start = parent_defer,
.flags = flags,
};
context->active_scope = new_scope;
}
const char *context_filename(SemaContext *context)
@@ -144,7 +145,7 @@ void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast)
ASSERT(ast->ast_kind != AST_COMPOUND_STMT);
Ast *replacement = ast_copy(ast);
ast->ast_kind = AST_COMPOUND_STMT;
ast->compound_stmt = (AstCompoundStmt) { .first_stmt = astid(replacement) };
ast->compound_stmt = (AstCompoundStmt) { .first_stmt = astid(replacement), .parent_defer = 0 };
replacement->next = defer_first;
}