Allow named args after unpack

Currently, argument unpacking and named arguments cannot be mixed
at all. This relaxes the restriction to allow
foo(...$args, named: $arg). The variant foo(named: $arg, ...$args)
is still forbidden, because we can't ensure that positional
parameters come before named parameters in that case (without more
intrusive changes). Effectively this just enforces a required style,
as the order of unpack and named args doesn't matter for the cases
where both could be well-defined.

ML discussion: https://externals.io/message/114589

Closes GH-7009.
This commit is contained in:
Nikita Popov 2021-05-18 14:21:23 +02:00
parent 71fb83567f
commit 1c08f8a48a
4 changed files with 58 additions and 13 deletions

View file

@ -185,6 +185,8 @@ PHP 8.1 UPGRADE NOTES
. File uploads now provide an additional full_path key, which contains the . File uploads now provide an additional full_path key, which contains the
full path (rather than just the basename) of the uploaded file. This is full path (rather than just the basename) of the uploaded file. This is
intended for use in conjunction with "upload webkitdirectory". intended for use in conjunction with "upload webkitdirectory".
. It is now allowed to specify named arguments after an argument unpack, e.g.
foo(...$args, named: $arg).
- Curl: - Curl:
. Added CURLOPT_DOH_URL option. . Added CURLOPT_DOH_URL option.

View file

@ -1,10 +1,58 @@
--TEST-- --TEST--
Mixing unpacking and named params (1) Named args after unpacking (supported)
--FILE-- --FILE--
<?php <?php
test(...[], a: 42); function test(...$args) {
var_dump($args);
}
test(...[1, 2], a: 3);
test(...[1, 'a' => 2], b: 3);
function test2($a, $b, $c = 3, $d = 4) {
var_dump($a, $b, $c, $d);
}
test2(...[1, 2], d: 40);
test2(...['b' => 2, 'a' => 1], d: 40);
try {
test2(...[1, 2], b: 20);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
test2(...[1, 'b' => 2], b: 20);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?> ?>
--EXPECTF-- --EXPECT--
Fatal error: Cannot combine named arguments and argument unpacking in %s on line %d array(3) {
[0]=>
int(1)
[1]=>
int(2)
["a"]=>
int(3)
}
array(3) {
[0]=>
int(1)
["a"]=>
int(2)
["b"]=>
int(3)
}
int(1)
int(2)
int(3)
int(40)
int(1)
int(2)
int(3)
int(40)
Named parameter $b overwrites previous argument
Named parameter $b overwrites previous argument

View file

@ -1,5 +1,5 @@
--TEST-- --TEST--
Mixing unpacking and named params (2) Named args before unpacking (not supported)
--FILE-- --FILE--
<?php <?php
@ -7,4 +7,4 @@ test(a: 42, ...[]);
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Cannot combine named arguments and argument unpacking in %s on line %d Fatal error: Cannot use argument unpacking after named arguments in %s on line %d

View file

@ -3472,7 +3472,7 @@ uint32_t zend_compile_args(
if (arg->kind == ZEND_AST_UNPACK) { if (arg->kind == ZEND_AST_UNPACK) {
if (uses_named_args) { if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR, zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking"); "Cannot use argument unpacking after named arguments");
} }
uses_arg_unpack = 1; uses_arg_unpack = 1;
@ -3492,16 +3492,11 @@ uint32_t zend_compile_args(
} }
if (arg->kind == ZEND_AST_NAMED_ARG) { if (arg->kind == ZEND_AST_NAMED_ARG) {
if (uses_arg_unpack) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking");
}
uses_named_args = 1; uses_named_args = 1;
arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0])); arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0]));
arg = arg->child[1]; arg = arg->child[1];
if (fbc) { if (fbc && !uses_arg_unpack) {
arg_num = zend_get_arg_num(fbc, arg_name); arg_num = zend_get_arg_num(fbc, arg_name);
if (arg_num == arg_count + 1 && !may_have_undef) { if (arg_num == arg_count + 1 && !may_have_undef) {
/* Using named arguments, but passing in order. */ /* Using named arguments, but passing in order. */