diff --git a/releasenotes.md b/releasenotes.md index f38271770..7732c7f00 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -50,6 +50,7 @@ - Constants defined by indexing into another constant could fail codegen. - Stdlib nolibc code bugs fixed. - Regression: duplicate symbols with static variable declared in macro #1248. +- Unsplat with named parameters was accidentally disallowed. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 798f40f9b..f7ca8d7ca 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -498,6 +498,11 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool * { if (splat) { + if (*splat) + { + PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call."); + return false; + } *splat = try_consume(c, TOKEN_ELLIPSIS); } ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false); @@ -510,8 +515,6 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool * if (tok_is(c, param_end)) return true; if (splat && *splat) { - PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call."); - return false; } } } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index a54f2476b..1a3e8d2f2 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1301,6 +1301,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, // 2. Loop through the parameters. bool has_named = false; + bool found_splat = false; for (unsigned i = 0; i < num_args; i++) { Expr *arg = args[i]; @@ -1340,7 +1341,13 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, actual_args[index] = arg->designator_expr.value; continue; } - + if (*vararg_splat_ref) + { + if (no_match_ref) goto NO_MATCH_REF; + RETURN_SEMA_FUNC_ERROR(callee->definition, arg, + "This looks like an argument after a splatted variable, which " + "isn't allowed. Did you add too many arguments?"); + } if (has_named) { RETURN_SEMA_FUNC_ERROR(callee->definition, args[i - 1], @@ -1365,14 +1372,6 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, // 11a. Look if we did a splat if (call->call_expr.splat_vararg) { - // 11b. Is this the last argument, or did we get some before the splat? - if (i < num_args - 1) - { - if (no_match_ref) goto NO_MATCH_REF; - RETURN_SEMA_FUNC_ERROR(callee->definition, arg, - "This looks like a variable argument before an splatted variable which " - "isn't allowed. Did you add too many arguments?"); - } *vararg_splat_ref = arg; continue; } diff --git a/test/test_suite/functions/unsplat_named.c3 b/test/test_suite/functions/unsplat_named.c3 new file mode 100644 index 000000000..760acb708 --- /dev/null +++ b/test/test_suite/functions/unsplat_named.c3 @@ -0,0 +1,8 @@ +fn void test(int... abc, int a) +{ } + +fn void main() +{ + int[] b = { 1, 2 }; + test(...b, .a = 123); +} \ No newline at end of file