fix(compiler): support first-class callable of internal functions (#93)
* fix(compiler): support first-class callable of internal functions PHP 8.1 `foo(...)` builds a Closure from a single VariadicPlaceholder argument instead of calling foo. Two paths mishandled it: - checkInternalFunctionArgCount() counted the placeholder as a real argument, so first-class callables of internal functions requiring 2+ parameters (e.g. `posix_kill(...)`) failed with a bogus "expects at least N arguments, 1 given". - The math-function return-type optimization read `$expr->args[0]->value` on callables such as `round(...)`, crashing on the undefined VariadicPlaceholder::$value property. Guard both with isFirstClassCallable() so the expression falls through to Closure (Type::OBJECT) resolution. * fix(compiler): infer builtin callables before return optimizations --------- Co-authored-by: Tinywan <tinywan@gmail.com>master
parent
38d828cbbe
commit
055dee01f8
5 changed files with 72 additions and 4 deletions
@ -0,0 +1,19 @@ |
|||||||
|
--TEST-- |
||||||
|
First-class callable of builtins requiring multiple arguments |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function main(): void { |
||||||
|
// str_repeat() and array_slice() are internal functions with 2 required |
||||||
|
// parameters. `foo(...)` builds a Closure; its single VariadicPlaceholder |
||||||
|
// must not be counted as one real argument and rejected by the internal |
||||||
|
// function argument-count check. |
||||||
|
$repeat = str_repeat(...); |
||||||
|
echo $repeat('ab', 3), "\n"; |
||||||
|
|
||||||
|
$slice = array_slice(...); |
||||||
|
echo implode(',', $slice([1, 2, 3, 4, 5], 1, 2)), "\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
ababab |
||||||
|
2,3 |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
--TEST-- |
||||||
|
First-class callable of a math function (round) |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function main(): void { |
||||||
|
// round() is in the math-function return-type optimization list. For the |
||||||
|
// first-class callable `round(...)`, args[0] is a VariadicPlaceholder with |
||||||
|
// no ->value, so the optimization must be skipped and the expression must |
||||||
|
// resolve to a Closure instead of crashing. |
||||||
|
$values = [1.4, 2.6, 3.5]; |
||||||
|
$rounded = array_map(round(...), $values); |
||||||
|
echo implode(',', $rounded), "\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
1,3,4 |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
--TEST-- |
||||||
|
First-class callable of a stream-returning function |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function useOpener(Closure $open): void { |
||||||
|
echo "callable\n"; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void { |
||||||
|
useOpener(fopen(...)); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
callable |
||||||
Loading…
Reference in new issue