Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named params implementation #5357

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
424f0b6
Partial named params implementation
nikic Apr 6, 2020
4afe5b4
Check for duplicate parameter names in internal functions
nikic Jul 24, 2020
a8e7462
Add AST export support
nikic Jul 27, 2020
8b14583
Fix test name
nikic Jul 27, 2020
75964c0
Add tests for Attribut(flags: )
nikic Jul 27, 2020
e550f4a
Only check for undef in RECV(_INIT)
nikic Jul 27, 2020
d346bbd
Check for undef in recv jit
nikic Jul 27, 2020
8bdd1a9
Add flag to distinguish named fcalls
nikic Jul 27, 2020
883c0a5
SEND may throw for named params
nikic Jul 27, 2020
3683f0e
For unpacks, we should also assume there may be named args
nikic Jul 27, 2020
368500b
Free extra named args in jit
nikic Jul 27, 2020
d0492b1
Initialize icall undef args in jit
nikic Jul 27, 2020
bb79eed
Always emit type check in RECV_INIT
nikic Jul 28, 2020
268b69c
Fix attribtue tests for new syntax
nikic Jul 28, 2020
fc37bc0
WIP
nikic Jul 30, 2020
5fddc6f
Fixes
nikic Jul 30, 2020
06a4ab7
Cleanup
nikic Jul 30, 2020
a46694c
jit
nikic Jul 30, 2020
1aec287
Fix windows?
nikic Jul 30, 2020
a164e5d
Rename opcode to be more precise
nikic Jul 30, 2020
90dac08
Make flag meaning more precise
nikic Jul 31, 2020
a9a0252
Make compiler code a bit smarter
nikic Jul 31, 2020
2700037
Move function back to where it was
nikic Jul 31, 2020
0f9131e
Rename function to match opcode name
nikic Jul 31, 2020
141ded0
jit cleanup
nikic Jul 31, 2020
077886d
Support extra named params in backtraces
nikic Jul 31, 2020
3e45549
Prepare for extra named params reuse
nikic Jul 31, 2020
e77c2b6
Reuse extra_named_params if possible
nikic Jul 31, 2020
e31838a
Combine check for extra named params and allocated call
nikic Jul 31, 2020
ed108d4
Drop one of the free extra named params helpers
nikic Jul 31, 2020
a6b566d
Revert an incorrect change
nikic Jul 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Zend/tests/arg_unpack/non_integer_keys.phpt
Expand Up @@ -18,4 +18,4 @@ try {

?>
--EXPECT--
Exception: Cannot unpack Traversable with non-integer keys
Exception: Keys must be of type int|string during argument unpacking
8 changes: 1 addition & 7 deletions Zend/tests/arg_unpack/string_keys.phpt
Expand Up @@ -7,11 +7,6 @@ set_error_handler(function($errno, $errstr) {
var_dump($errstr);
});

try {
var_dump(...[1, 2, "foo" => 3, 4]);
} catch (Error $ex) {
var_dump($ex->getMessage());
}
try {
var_dump(...new ArrayIterator([1, 2, "foo" => 3, 4]));
} catch (Error $ex) {
Expand All @@ -20,5 +15,4 @@ try {

?>
--EXPECT--
string(36) "Cannot unpack array with string keys"
string(42) "Cannot unpack Traversable with string keys"
string(68) "Cannot use positional argument after named argument during unpacking"
2 changes: 2 additions & 0 deletions Zend/tests/assert/expect_015.phpt
Expand Up @@ -60,6 +60,7 @@ assert(0 && ($a = function &(array &$a, ?X $b = null) use ($c,&$d) : ?X {
$x = C::${$z . "_1"};
$x?->y;
$x?->y();
foo(bar: $x);
}
}
}));
Expand Down Expand Up @@ -202,6 +203,7 @@ Warning: assert(): assert(0 && ($a = function &(array &$a, ?X $b = null) use($c,
$x = C::${$z . '_1'};
$x?->y;
$x?->y();
foo(bar: $x);
}

}
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/bug43343.phpt
Expand Up @@ -8,4 +8,4 @@ $foo = 'bar';
var_dump(new namespace::$foo);
?>
--EXPECTF--
Parse error: syntax error, unexpected token "namespace" in %s on line %d
Parse error: syntax error, unexpected token "namespace", expecting ":" in %s on line %d
37 changes: 37 additions & 0 deletions Zend/tests/named_params/__call.phpt
@@ -0,0 +1,37 @@
--TEST--
Check that __call() and __callStatic() work with named parameters
--FILE--
<?php

class Test {
public function __call(string $method, array $args) {
$this->{'_'.$method}(...$args);
}

public static function __callStatic(string $method, array $args) {
(new static)->{'_'.$method}(...$args);
}

private function _method($a = 'a', $b = 'b') {
echo "a: $a, b: $b\n";
}
}

$obj = new class { public function __toString() { return "STR"; } };

$test = new Test;
$test->method(a: 'A', b: 'B');
$test->method(b: 'B');
$test->method(b: $obj);
Test::method(a: 'A', b: 'B');
Test::method(b: 'B');
Test::method(b: $obj);

?>
--EXPECT--
a: A, b: B
a: a, b: B
a: a, b: STR
nikic marked this conversation as resolved.
Show resolved Hide resolved
a: A, b: B
a: a, b: B
a: a, b: STR
64 changes: 64 additions & 0 deletions Zend/tests/named_params/__invoke.phpt
@@ -0,0 +1,64 @@
--TEST--
Check that __invoke() works with named parameters
--FILE--
<?php

class Test {
public function __invoke($a = 'a', $b = 'b') {
echo "a: $a, b: $b\n";
}
}

class Test2 {
public function __invoke($a = 'a', $b = 'b', ...$rest) {
echo "a: $a, b: $b\n";
var_dump($rest);
}
}

$test = new Test;
$test(b: 'B', a: 'A');
$test(b: 'B');
try {
$test(b: 'B', c: 'C');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
echo "\n";

$test2 = new Test2;
$test2(b: 'B', a: 'A', c: 'C');
$test2(b: 'B', c: 'C');
echo "\n";

$test3 = function($a = 'a', $b = 'b') {
echo "a: $a, b: $b\n";
};
$test3(b: 'B', a: 'A');
$test3(b: 'B');
try {
$test3(b: 'B', c: 'C');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
a: A, b: B
a: a, b: B
Unknown named parameter $c

a: A, b: B
array(1) {
["c"]=>
string(1) "C"
}
a: a, b: B
array(1) {
["c"]=>
string(1) "C"
}

a: A, b: B
a: a, b: B
Unknown named parameter $c
50 changes: 50 additions & 0 deletions Zend/tests/named_params/attributes.phpt
@@ -0,0 +1,50 @@
--TEST--
Named params in attributes
--FILE--
<?php

@@Attribute
class MyAttribute {
public function __construct(
public $a = 'a',
public $b = 'b',
public $c = 'c',
) {}
}

@@MyAttribute('A', c: 'C')
class Test1 {}

@@MyAttribute('A', a: 'C')
class Test2 {}

$attr = (new ReflectionClass(Test1::class))->getAttributes()[0];
var_dump($attr->getName());
var_dump($attr->getArguments());
var_dump($attr->newInstance());

$attr = (new ReflectionClass(Test2::class))->getAttributes()[0];
try {
var_dump($attr->newInstance());
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
string(11) "MyAttribute"
array(2) {
[0]=>
string(1) "A"
["c"]=>
string(1) "C"
}
object(MyAttribute)#1 (3) {
["a"]=>
string(1) "A"
["b"]=>
string(1) "b"
["c"]=>
string(1) "C"
}
Named parameter $a overwrites previous argument
11 changes: 11 additions & 0 deletions Zend/tests/named_params/attributes_duplicate_named_param.phpt
@@ -0,0 +1,11 @@
--TEST--
Named params in attributes: Duplicate named parameter error
--FILE--
<?php

@@MyAttribute(a: 'A', a: 'A')
class Test {}

?>
--EXPECTF--
Fatal error: Duplicate named parameter $a in %s on line %d
21 changes: 21 additions & 0 deletions Zend/tests/named_params/attributes_named_flags.phpt
@@ -0,0 +1,21 @@
--TEST--
Named flags parameter for Attribute attribute
--FILE--
<?php

@@Attribute(flags: Attribute::TARGET_CLASS)
class MyAttribute {
}

@@MyAttribute
function test() {}

(new ReflectionFunction('test'))->getAttributes()[0]->newInstance();

?>
--EXPECTF--
Fatal error: Uncaught Error: Attribute "MyAttribute" cannot target function (allowed targets: class) in %s:%d
Stack trace:
#0 %s(%d): ReflectionAttribute->newInstance()
#1 {main}
thrown in %s on line %d
22 changes: 22 additions & 0 deletions Zend/tests/named_params/attributes_named_flags_incorrect.phpt
@@ -0,0 +1,22 @@
--TEST--
Named flags parameter for Attribute attribute (incorrect parameter name)
--FILE--
<?php

// TODO: This should error at compile-time.
@@Attribute(not_flags: Attribute::TARGET_CLASS)
class MyAttribute {
}

@@MyAttribute
function test() {}

(new ReflectionFunction('test'))->getAttributes()[0]->newInstance();

?>
--EXPECTF--
Fatal error: Uncaught Error: Attribute "MyAttribute" cannot target function (allowed targets: class) in %s:%d
Stack trace:
#0 %s(%d): ReflectionAttribute->newInstance()
#1 {main}
thrown in %s on line %d
14 changes: 14 additions & 0 deletions Zend/tests/named_params/attributes_positional_after_named.phpt
@@ -0,0 +1,14 @@
--TEST--
Named params in attributes: Positional after named error
--FILE--
<?php

@@Attribute
class MyAttribute { }

@@MyAttribute(a: 'A', 'B')
class Test {}

?>
--EXPECTF--
Fatal error: Cannot use positional argument after named argument in %s on line %d
69 changes: 69 additions & 0 deletions Zend/tests/named_params/backtrace.phpt
@@ -0,0 +1,69 @@
--TEST--
Extra named params in backtraces
--FILE--
<?php

function test($a, ...$rest) {
var_dump(debug_backtrace());
debug_print_backtrace();
throw new Exception("Test");
}

try {
test(1, 2, x: 3, y: 4);
} catch (Exception $e) {
var_dump($e->getTrace());
echo $e, "\n";
}

?>
--EXPECTF--
array(1) {
[0]=>
array(4) {
["file"]=>
string(%d) "%s"
["line"]=>
int(10)
["function"]=>
string(4) "test"
["args"]=>
array(4) {
[0]=>
int(1)
[1]=>
int(2)
["x"]=>
int(3)
["y"]=>
int(4)
}
}
}
#0 test(1, 2, x: 3, y: 4) called at [%s:10]
array(1) {
[0]=>
array(4) {
["file"]=>
string(%d) "%s"
["line"]=>
int(10)
["function"]=>
string(4) "test"
["args"]=>
array(4) {
[0]=>
int(1)
[1]=>
int(2)
["x"]=>
int(3)
["y"]=>
int(4)
}
}
}
Exception: Test in %s:%d
Stack trace:
#0 %s(%d): test(1, 2, x: 3, y: 4)
#1 {main}