aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-07 22:42:38 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-07 22:42:38 +0100
commit3d02f8a5fdcd18f08083994a51ac9518fc565f79 (patch)
tree0f774dfc4b1a704e2b48324512a6fe1142ffcd33 /src
parent50aeea1c2e11ed1413ca29bf5993b80dff38fa62 (diff)
Slice variadic expansion `..`
Diffstat (limited to 'src')
-rw-r--r--src/checker/expr.cpp40
-rw-r--r--src/codegen/ssa.cpp15
2 files changed, 43 insertions, 12 deletions
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 13d367acd..5e97727fd 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -2032,7 +2032,10 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
}
AstNode *len = ce->args[1];
- AstNode *cap = ce->args[2];
+ AstNode *cap = NULL;
+ if (gb_array_count(ce->args) > 2) {
+ cap = ce->args[2];
+ }
check_expr(c, &op, len);
if (op.mode == Addressing_Invalid)
@@ -2542,7 +2545,10 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
}
AstNode *len = ce->args[1];
- AstNode *cap = ce->args[2];
+ AstNode *cap = NULL;
+ if (gb_array_count(ce->args) > 2) {
+ cap = ce->args[2];
+ }
Operand op = {};
check_expr(c, &op, len);
@@ -2753,6 +2759,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
isize param_index = 0;
isize param_count = 0;
b32 variadic = proc_type->Proc.variadic;
+ b32 vari_expand = (ce->ellipsis.pos.line != 0);
if (proc_type->Proc.params) {
param_count = proc_type->Proc.params->Tuple.variable_count;
@@ -2782,23 +2789,37 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
} else {
Entity **sig_params = proc_type->Proc.params->Tuple.variables;
gb_for_array(arg_index, ce->args) {
- AstNode *call_arg = ce->args[arg_index];
- check_multi_expr(c, operand, call_arg);
+ check_multi_expr(c, operand, ce->args[arg_index]);
if (operand->mode == Addressing_Invalid)
continue;
if (operand->type->kind != Type_Tuple) {
check_not_tuple(c, operand);
isize index = param_index;
b32 end_variadic = false;
+ b32 variadic_expand = false;
if (variadic && param_index >= param_count-1) {
index = param_count-1;
end_variadic = true;
+ if (vari_expand) {
+ variadic_expand = true;
+ if (param_index != param_count-1) {
+ error(&c->error_collector, ast_node_token(operand->expr),
+ "`..` in a variadic procedure can only have one variadic argument at the end");
+ break;
+ }
+ }
}
Type *arg_type = sig_params[index]->type;
if (end_variadic && is_type_slice(arg_type)) {
- arg_type = get_base_type(arg_type)->Slice.elem;
+ if (variadic_expand) {
+ check_assignment(c, operand, arg_type, make_string("argument"), true);
+ } else {
+ arg_type = get_base_type(arg_type)->Slice.elem;
+ check_assignment(c, operand, arg_type, make_string("argument"), true);
+ }
+ } else {
+ check_assignment(c, operand, arg_type, make_string("argument"), true);
}
- check_assignment(c, operand, arg_type, make_string("argument"), true);
param_index++;
} else {
auto *tuple = &operand->type->Tuple;
@@ -2815,6 +2836,11 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
if (variadic && param_index >= param_count-1) {
index = param_count-1;
end_variadic = true;
+ if (vari_expand) {
+ error(&c->error_collector, ast_node_token(operand->expr),
+ "`..` in a variadic procedure cannot be applied to a %td-valued expression", tuple->variable_count);
+ goto end;
+ }
}
Type *arg_type = sig_params[index]->type;
if (end_variadic && is_type_slice(arg_type)) {
@@ -2824,6 +2850,8 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
param_index++;
}
+ end:
+
if (i < tuple->variable_count && param_index == param_count) {
error_code = +1;
break;
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index 8a9e00e6d..aa7d49649 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -2273,6 +2273,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
}
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, arg_count);
b32 variadic = proc_type_->Proc.variadic;
+ b32 vari_expand = ce->ellipsis.pos.line != 0;
gb_for_array(i, ce->args) {
ssaValue *a = ssa_build_expr(proc, ce->args[i]);
@@ -2295,11 +2296,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
for (; i < type->param_count-1; i++) {
args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type, true);
}
- Type *variadic_type = pt->variables[i]->type;
- GB_ASSERT(is_type_slice(variadic_type));
- variadic_type = get_base_type(variadic_type)->Slice.elem;
- for (; i < arg_count; i++) {
- args[i] = ssa_emit_conv(proc, args[i], variadic_type, true);
+ if (!vari_expand) {
+ Type *variadic_type = pt->variables[i]->type;
+ GB_ASSERT(is_type_slice(variadic_type));
+ variadic_type = get_base_type(variadic_type)->Slice.elem;
+ for (; i < arg_count; i++) {
+ args[i] = ssa_emit_conv(proc, args[i], variadic_type, true);
+ }
}
} else {
for (isize i = 0; i < arg_count; i++) {
@@ -2307,7 +2310,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
}
}
- if (variadic) {
+ if (variadic && !vari_expand) {
ssa_emit_comment(proc, make_string("variadic call argument generation"));
gbAllocator allocator = proc->module->allocator;
Type *slice_type = pt->variables[type->param_count-1]->type;