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;