Allow splat in initializers.

This commit is contained in:
Christoffer Lerno
2024-11-11 23:54:35 +01:00
parent c46933a81a
commit a228eb020d
4 changed files with 86 additions and 6 deletions

View File

@@ -3,6 +3,7 @@
## 0.6.5 Change list
### Changes / improvements
- Allow splat in initializers.
### Fixes
- Fix bug where `a > 0 ? f() : g()` could cause a compiler crash if both returned `void!`.

View File

@@ -2290,7 +2290,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement);
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right,
bool is_unwrapped_var, bool is_declaration);
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr);
Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs);
Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs);
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional,
bool *no_match_ref);

View File

@@ -5213,10 +5213,10 @@ static Expr **sema_vasplat_insert(SemaContext *context, Expr **init_expressions,
return init_expressions;
}
Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs)
Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs)
{
if (!c || !c->current_macro) return exprs;
if (!context) return exprs;
bool in_macro = context->current_macro;
unsigned count = vec_size(exprs);
bool expand;
do
@@ -5224,15 +5224,54 @@ Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs)
expand = false;
for (unsigned i = 0; i < count; i++)
{
if (exprs[i]->expr_kind == EXPR_VASPLAT)
Expr *arg = exprs[i];
ExprKind kind = arg->expr_kind;
if (in_macro && kind == EXPR_VASPLAT)
{
exprs = sema_vasplat_insert(c, exprs, exprs[i], i);
exprs = sema_vasplat_insert(context, exprs, arg, i);
// If we have null back it failed.
if (!exprs) return NULL;
count = vec_size(exprs);
expand = true;
break;
}
if (kind == EXPR_SPLAT)
{
Expr *inner = arg->inner_expr;
if (!sema_analyse_expr(context, inner)) return false;
Type *flat = type_flatten(inner->type);
switch (flat->type_kind)
{
case TYPE_VECTOR:
case TYPE_ARRAY:
case TYPE_SLICE:
case TYPE_UNTYPED_LIST:
// These may be splatted
break;
default:
SEMA_ERROR(arg, "An argument of type %s cannot be splatted.",
type_quoted_error_string(inner->type));
return NULL;
}
ArrayIndex len = sema_len_from_expr(inner);
if (len == -1)
{
SEMA_ERROR(arg,
"Splat may not be used with if the length is not known, but if you slice it to a constant length it will work (e.g '...val[:2]')");
return NULL;
}
if (len == 0 && !expr_is_const(arg))
{
SEMA_ERROR(arg, "A non-constant zero size splat is not allowed.");
return NULL;
}
Expr **new_args = sema_splat_arraylike_insert(context, exprs, inner, len, i);
if (!new_args) return false;
if (!exprs) return NULL;
count = vec_size(exprs);
expand = true;
break;
}
}
} while (expand);
return exprs;

View File

@@ -0,0 +1,40 @@
// #target: macos-x64
module splat;
import std;
int a = 0;
fn int[2] test()
{
a++;
return { 2, 3 };
}
fn void main()
{
int[4] z = { a, ...test(), a };
}
/* #expect: splat.ll
define void @splat.main() #0 {
entry:
%z = alloca [4 x i32], align 16
%.anon = alloca [2 x i32], align 4
%result = alloca [2 x i32], align 4
%0 = load i32, ptr @splat.a, align 4
store i32 %0, ptr %z, align 4
%ptradd = getelementptr inbounds i8, ptr %z, i64 4
%1 = call i64 @splat.test()
store i64 %1, ptr %result, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %.anon, ptr align 4 %result, i32 8, i1 false)
%2 = load i32, ptr %.anon, align 4
store i32 %2, ptr %ptradd, align 4
%ptradd1 = getelementptr inbounds i8, ptr %z, i64 8
%ptradd2 = getelementptr inbounds i8, ptr %.anon, i64 4
%3 = load i32, ptr %ptradd2, align 4
store i32 %3, ptr %ptradd1, align 4
%ptradd3 = getelementptr inbounds i8, ptr %z, i64 12
%4 = load i32, ptr @splat.a, align 4
store i32 %4, ptr %ptradd3, align 4
ret void
}