From a81f857d8cac17bb1dc7384e3d0897139b536ae5 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 20 Oct 2025 02:26:04 +0200 Subject: [PATCH] Update to fix with splat. --- src/compiler/ast.c | 5 ++ src/compiler/compiler_internal.h | 1 + src/compiler/sema_expr.c | 30 ++++++--- src/compiler/sema_stmts.c | 2 +- src/compiler/sema_types.c | 4 ++ test/test_suite/functions/splat_err.c3 | 62 +++++++++++++++++++ .../test_suite/lambda/lambda_splat_macro2.c3t | 30 +++++++++ 7 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 test/test_suite/functions/splat_err.c3 create mode 100644 test/test_suite/lambda/lambda_splat_macro2.c3t diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 8bbfde523..ec4debb5d 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -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. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 3935fbd8f..71c475b83 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 7b4d29433..a8341dba9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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(¯o_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: diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index d39a008d4..1cce6af59 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -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; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index bcb6a9eeb..cc0821da9 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -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)); diff --git a/test/test_suite/functions/splat_err.c3 b/test/test_suite/functions/splat_err.c3 new file mode 100644 index 000000000..2c8b79d1c --- /dev/null +++ b/test/test_suite/functions/splat_err.c3 @@ -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; +} diff --git a/test/test_suite/lambda/lambda_splat_macro2.c3t b/test/test_suite/lambda/lambda_splat_macro2.c3t new file mode 100644 index 000000000..867d62bfb --- /dev/null +++ b/test/test_suite/lambda/lambda_splat_macro2.c3t @@ -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 +}