Update to fix with splat.

This commit is contained in:
Christoffer Lerno
2025-10-20 02:26:04 +02:00
parent 6169d7acdf
commit a81f857d8c
7 changed files with 126 additions and 8 deletions

View File

@@ -315,6 +315,11 @@ void decl_append_links_to_global_during_codegen(Decl *decl)
}
}
bool decl_is_defaulted_var(Decl *decl)
{
return decl->decl_kind == DECL_VAR && decl->var.no_init && decl->var.defaulted;
}
/*
* Count the expected number of elements needed for an initializer
* by folding any anonymous structs and unions.

View File

@@ -2324,6 +2324,7 @@ const char *decl_safe_name(Decl *decl);
const char *decl_to_name(Decl *decl);
const char *decl_to_a_name(Decl *decl);
int decl_count_elements(Decl *structlike);
bool decl_is_defaulted_var(Decl *decl);
void decl_append_links_to_global_during_codegen(Decl *decl);
INLINE bool decl_ok(Decl *decl);

View File

@@ -1281,10 +1281,13 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
default:
UNREACHABLE
}
SEMA_ERROR(expr, message);
return false;
RETURN_SEMA_ERROR(expr, message);
}
}
if (decl_is_defaulted_var(decl))
{
RETURN_SEMA_ERROR(expr, "The parameter '%s' was not provided by the caller.", decl->name);
}
if (decl->resolve_status != RESOLVE_DONE)
{
if (!sema_analyse_decl(context, decl)) return decl_poison(decl);
@@ -1348,6 +1351,10 @@ static inline bool sema_expr_resolve_ct_identifier(SemaContext *context, Expr *e
return expr_poison(expr);
}
if (decl_is_defaulted_var(decl))
{
RETURN_SEMA_ERROR(expr, "The parameter '%s' was not provided by the caller.", decl->name);
}
ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR);
ASSERT_SPAN(expr, decl->resolve_status == RESOLVE_DONE);
@@ -1830,7 +1837,7 @@ static SplatResult sema_splat_optional_argument(SemaContext *context, Expr *expr
if (!candidate->var.no_init) return SPLAT_NONE;
// We found it, it's a valid variable.
Decl *local = sema_find_local(context, candidate->name);
if (local && local->var.kind == candidate->var.kind) return SPLAT_ONE;
if (local && local->var.kind == candidate->var.kind && !decl_is_defaulted_var(local)) return SPLAT_ONE;
// It's missing! Let's splat-zero
return SPLAT_ZERO;
}
@@ -2923,8 +2930,8 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
{
// Skip raw vararg
if (!param) continue;
if (param->var.no_init && param->var.defaulted) continue;
if (!sema_add_local(&macro_context, param)) goto EXIT_FAIL;
if (param->var.no_init && param->var.defaulted) continue;
if (param->var.init_expr)
{
Type *param_type = param->type;
@@ -6854,6 +6861,10 @@ static bool sema_expr_fold_hash(SemaContext *context, Expr *expr)
ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR);
DEBUG_LOG("Replacing expr (%p) with '%s' (%p) expression resolve: %d", expr, expr_kind_to_string(decl->var.init_expr->expr_kind), decl->var.init_expr, decl->var.init_expr->resolve_status);
bool is_ref = expr->hash_ident_expr.is_ref;
if (decl_is_defaulted_var(decl))
{
RETURN_SEMA_ERROR(expr, "The parameter '%s' was not provided by the caller.", decl->name);
}
expr_replace(expr, copy_expr_single(decl->var.init_expr));
if (is_ref) expr_set_to_ref(expr);
REMINDER("Handle inlining at");
@@ -10756,7 +10767,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{
Decl *decl = sema_find_path_symbol(active_context, main_expr->unresolved_ident_expr.ident, main_expr->unresolved_ident_expr.path);
if (!decl_ok(decl)) goto FAIL;
success = decl != NULL;
success = decl != NULL && !decl_is_defaulted_var(decl);
break;
}
case EXPR_HASH_IDENT:
@@ -10765,6 +10776,11 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->hash_ident_expr.identifier, NULL, main_expr->span);
if (!decl) goto FAIL;
if (decl_is_defaulted_var(decl))
{
success = false;
break;
}
bool is_ref = main_expr->hash_ident_expr.is_ref;
main_expr = copy_expr_single(decl->var.init_expr);
if (is_ref) expr_set_to_ref(main_expr);
@@ -10772,7 +10788,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
}
Decl *decl = sema_find_symbol(active_context, main_expr->hash_ident_expr.identifier);
if (!decl_ok(decl)) goto FAIL;
success = decl != NULL;
success = decl != NULL && !decl_is_defaulted_var(decl);
break;
}
case EXPR_COMPILER_CONST:
@@ -10837,7 +10853,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{
Decl *decl = sema_find_symbol(active_context, main_expr->ct_ident_expr.identifier);
if (!decl_ok(decl)) goto FAIL;
success = decl != NULL;
success = decl != NULL && !decl_is_defaulted_var(decl);
break;
}
case EXPR_CALL:

View File

@@ -1217,7 +1217,7 @@ static inline bool sema_analyse_ct_type_assign_stmt(SemaContext *context, Ast *s
Decl *decl = sema_find_symbol(context, statement->ct_type_assign_stmt.var_name);
if (!decl) RETURN_SEMA_ERROR(statement, "'%s' is not defined in this scope yet.", statement->ct_type_assign_stmt.var_name);
if (decl_is_defaulted_var(decl)) RETURN_SEMA_ERROR(statement, "The parameter '%s' was not provided by the caller.", decl->name);
decl->var.init_expr = right;
statement->ast_kind = AST_NOP_STMT;

View File

@@ -258,6 +258,10 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
Expr *init_expr = decl->var.init_expr;
if (!init_expr)
{
if (decl_is_defaulted_var(decl))
{
RETURN_SEMA_ERROR(type_info, "The parameter '%s' was not provided by the caller.", decl->name);
}
RETURN_SEMA_ERROR(type_info, "You need to assign a type to '%s' before using it.", decl->name);
}
ASSERT_SPAN(init_expr, expr_is_const_typeid(init_expr));

View File

@@ -0,0 +1,62 @@
import std;
fn int test1()
{
@test1();
}
fn int test2()
{
@test2();
}
fn int test3()
{
@test3();
}
fn int test4()
{
@test4();
}
fn void test5()
{
@test5();
}
fn void test6()
{
@test6();
}
macro @test1($Foo = ...)
{
return $Foo.typeid; // #error: The parameter '$Foo' was not provided by the caller.
}
macro @test2(#foo = ...)
{
return #foo; // #error: The parameter '#foo' was not provided by the caller
}
macro @test3(foo = ...)
{
return foo; // #error: The parameter 'foo' was not provided by the caller.
}
macro @test4($foo = ...)
{
return $foo; // #error: The parameter '$foo' was not provided by the caller
}
macro @test5($Foo = ...)
{
$Foo = int; // #error: The parameter '$Foo' was not provided by the caller
return $Foo.typeid;
}
macro @test6(foo = ...)
{
foo = 1; // #error: The parameter 'foo' was not provided by the caller
return foo;
}

View File

@@ -0,0 +1,30 @@
// #target: macos-x64
module test;
import std;
fn int main()
{
bool x = test1a()();
return 0;
}
macro test1a(bool $a = ...) => fn bool()
{
return test1b(...$a);
};
macro test1b(bool $a = ...) => $defined($a) ??? $a : false;
/* #expect: test.ll
entry:
%x = alloca i8, align 1
%0 = call i8 @"test.test1a$lambda1"()
store i8 %0, ptr %x, align 1
ret i32 0
}
; Function Attrs: nounwind uwtable
define internal zeroext i8 @"test.test1a$lambda1"() #0 {
entry:
ret i8 0
}