Allow any expression as default expression.

This commit is contained in:
Christoffer Lerno
2022-07-28 21:24:23 +02:00
committed by Christoffer Lerno
parent 2698ba1a94
commit 12c17b62cf
8 changed files with 148 additions and 20 deletions

View File

@@ -9,6 +9,7 @@ struct File
CFile file;
}
fn int putchar(char c) @inline
{
return libc::putchar(c);
@@ -41,7 +42,6 @@ fn int println(char *message = "") @inline
fn void! File.open(File* file, char[] filename, char[] mode)
{
char* filename_copy = mem::talloc(filename.len + 1)!!;
char* mode_copy = mem::talloc(mode.len + 1)!!;
mem::copy(filename_copy, (char*)(filename), filename.len);

View File

@@ -349,6 +349,7 @@ typedef struct VarDecl_
Expr *init_expr;
Decl *alias;
};
struct CompilationUnit_ *unit;
union
{
int32_t index;

View File

@@ -563,16 +563,13 @@ static inline bool sema_analyse_function_param(SemaContext *context, Decl *param
{
Expr *expr = param->var.init_expr;
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false;
if (IS_FAILABLE(expr))
if (expr->expr_kind == EXPR_CONST)
{
SEMA_ERROR(expr, "Default arguments may not be failable.");
return false;
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false;
}
if (!expr_is_constant_eval(expr, CONSTANT_EVAL_ANY))
else
{
SEMA_ERROR(expr, "Only constant expressions may be used as default values.");
return false;
param->var.unit = context->unit;
}
*has_default = true;
}
@@ -2099,6 +2096,16 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
}
else
{
if (!context->current_function)
{
if (context->current_macro)
{
SEMA_ERROR(decl, "Macros with declarations may not be used outside of functions.");
return false;
}
SEMA_ERROR(decl, "Variable declarations may not be used outside of functions.");
return false;
}
// Add a local to the current context, will throw error on shadowing.
if (!sema_add_local(context, decl)) return decl_poison(decl);
}

View File

@@ -1378,17 +1378,23 @@ static inline bool sema_expand_call_arguments(SemaContext *context, CalledDecl *
if (is_func_ptr) goto FAIL_MISSING;
// 17b. Set the init expression.
Expr *init_expr = params[i]->var.init_expr;
Decl *param = params[i];
Expr *init_expr = param->var.init_expr;
if (init_expr)
{
if (callee->macro)
Expr *arg = actual_args[i] = expr_macro_copy(init_expr);
if (arg->resolve_status != RESOLVE_DONE)
{
actual_args[i] = expr_macro_copy(init_expr);
}
else
{
assert(init_expr->resolve_status == RESOLVE_DONE);
actual_args[i] = init_expr;
SemaContext default_context;
Type *rtype = NULL;
sema_context_init(&default_context, param->var.unit);
default_context.compilation_unit = context->unit;
default_context.current_function = context->current_function;
context_change_scope_with_flags(&default_context, SCOPE_NONE);
default_context.original_inline_line = context->original_inline_line ? context->original_inline_line : init_expr->span.row;
bool success = sema_analyse_expr_rhs(&default_context, param->type, arg, true);
sema_context_destroy(&default_context);
if (!success) return false;
}
continue;
}

View File

@@ -6,6 +6,6 @@ fault MyError
FOO,
}
fn void test(int a = z) {} // #error: Only constant expressions may be used as default values
fn void test(int a = z) {}
fn void test2(int b = MyError.FOO!) {} // #error: Default arguments may not be failable
fn void test2(int b = MyError.FOO!) {}

View File

@@ -0,0 +1,57 @@
module test;
import std::io;
import test2;
fn void test(int a = test2::bar(), int b = test2::foo())
{
io::printf("%d %d\n", a, b);
}
module test2;
fn int foo()
{
static int x = 0;
return ++x;
}
macro int bar()
{
static int x = 0;
return ++x;
}
module test3;
import test;
import std::io;
fn void main()
{
test::test(1, 2);
test::test(.a = 3);
test::test(1, .b = 32);
test::test();
test::test();
}
// #expect: test3.ll
entry:
call void @test_test(i32 1, i32 2)
%0 = call i32 @test2_foo()
call void @test_test(i32 3, i32 %0)
call void @test_test(i32 1, i32 32)
%1 = load i32, i32* @"main$x", align 4
%add = add i32 %1, 1
store i32 %add, i32* @"main$x", align 4
%2 = call i32 @test2_foo()
call void @test_test(i32 %add, i32 %2)
%3 = load i32, i32* @"main$x.1", align 4
%add1 = add i32 %3, 1
store i32 %add1, i32* @"main$x.1", align 4
%4 = call i32 @test2_foo()
call void @test_test(i32 %add1, i32 %4)
ret void
}

View File

@@ -6,6 +6,6 @@ fault MyError
FOO,
}
fn void test(int a = z) {} // #error: Only constant expressions may be used as default values
fn void test(int a = z) {}
fn void test2(int b = MyError.FOO!) {} // #error: Default arguments may not be failable
fn void test2(int b = MyError.FOO!) {}

View File

@@ -0,0 +1,57 @@
module test;
import std::io;
import test2;
fn void test(int a = test2::bar(), int b = test2::foo())
{
io::printf("%d %d\n", a, b);
}
module test2;
fn int foo()
{
static int x = 0;
return ++x;
}
macro int bar()
{
static int x = 0;
return ++x;
}
module test3;
import test;
import std::io;
fn void main()
{
test::test(1, 2);
test::test(.a = 3);
test::test(1, .b = 32);
test::test();
test::test();
}
// #expect: test3.ll
entry:
call void @test_test(i32 1, i32 2)
%0 = call i32 @test2_foo()
call void @test_test(i32 3, i32 %0)
call void @test_test(i32 1, i32 32)
%1 = load i32, ptr @"main$x", align 4
%add = add i32 %1, 1
store i32 %add, ptr @"main$x", align 4
%2 = call i32 @test2_foo()
call void @test_test(i32 %add, i32 %2)
%3 = load i32, ptr @"main$x.1", align 4
%add1 = add i32 %3, 1
store i32 %add1, ptr @"main$x.1", align 4
%4 = call i32 @test2_foo()
call void @test_test(i32 %add1, i32 %4)
ret void
}