Browse Source

Slice variadic expansion `..`

Ginger Bill 9 years ago
parent
commit
3d02f8a5fd
2 changed files with 43 additions and 12 deletions
  1. 34 6
      src/checker/expr.cpp
  2. 9 6
      src/codegen/ssa.cpp

+ 34 - 6
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;

+ 9 - 6
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;