@@ -3696,8 +3696,8 @@ static uint32_t zend_get_arg_num(zend_function *fn, zend_string *arg_name) {
3696
3696
}
3697
3697
3698
3698
static uint32_t zend_compile_args (
3699
- zend_ast * ast , zend_function * fbc , bool * may_have_extra_named_args ,
3700
- bool * is_call_partial ) /* {{{ */
3699
+ zend_ast * ast , zend_function * fbc , bool is_call_partial ,
3700
+ bool * may_have_extra_named_args ) /* {{{ */
3701
3701
{
3702
3702
zend_ast_list * args = zend_ast_get_list (ast );
3703
3703
uint32_t i ;
@@ -3712,8 +3712,6 @@ static uint32_t zend_compile_args(
3712
3712
bool may_have_undef = 0 ;
3713
3713
/* Whether there may be any extra named arguments collected into a variadic. */
3714
3714
* may_have_extra_named_args = 0 ;
3715
- /* Whether this is a partial call */
3716
- * is_call_partial = false;
3717
3715
3718
3716
for (i = 0 ; i < args -> children ; ++ i ) {
3719
3717
zend_ast * arg = args -> child [i ];
@@ -3730,7 +3728,7 @@ static uint32_t zend_compile_args(
3730
3728
"Cannot use argument unpacking after named arguments" );
3731
3729
}
3732
3730
3733
- if (* is_call_partial ) {
3731
+ if (is_call_partial ) {
3734
3732
zend_error_noreturn (E_COMPILE_ERROR ,
3735
3733
"Cannot combine partial application and unpacking" );
3736
3734
}
@@ -3824,7 +3822,6 @@ static uint32_t zend_compile_args(
3824
3822
opline -> result .var = EX_NUM_TO_VAR (arg_num - 1 );
3825
3823
}
3826
3824
3827
- * is_call_partial = true;
3828
3825
continue ;
3829
3826
}
3830
3827
@@ -3938,7 +3935,7 @@ static uint32_t zend_compile_args(
3938
3935
}
3939
3936
}
3940
3937
3941
- if (!* is_call_partial ) {
3938
+ if (!is_call_partial ) {
3942
3939
if (may_have_undef ) {
3943
3940
zend_emit_op (NULL , ZEND_CHECK_UNDEF_ARGS , NULL , NULL );
3944
3941
}
@@ -4010,27 +4007,38 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, zend_fun
4010
4007
{
4011
4008
zend_op * opline ;
4012
4009
uint32_t opnum_init = get_next_op_number () - 1 ;
4010
+ bool is_partial_call = false;
4013
4011
4014
4012
if (args_ast -> kind == ZEND_AST_CALLABLE_CONVERT ) {
4013
+ is_partial_call = true;
4014
+
4015
4015
opline = & CG (active_op_array )-> opcodes [opnum_init ];
4016
4016
opline -> extended_value = 0 ;
4017
4017
4018
4018
if (opline -> opcode == ZEND_NEW ) {
4019
4019
zend_error_noreturn (E_COMPILE_ERROR , "Cannot create Closure for new expression" );
4020
4020
}
4021
4021
4022
- if (opline -> opcode == ZEND_INIT_FCALL ) {
4023
- opline -> op1 .num = zend_vm_calc_used_stack (0 , fbc );
4022
+ zend_ast_list * fcc_args = zend_ast_get_list (((zend_ast_fcc * )args_ast )-> args );
4023
+
4024
+ /* FCCs are a special case of PFAs with a single variadic placeholder */
4025
+ if (fcc_args -> children == 1 && fcc_args -> child [0 ]-> attr == _IS_PLACEHOLDER_VARIADIC ) {
4026
+
4027
+ if (opline -> opcode == ZEND_INIT_FCALL ) {
4028
+ opline -> op1 .num = zend_vm_calc_used_stack (0 , fbc );
4029
+ }
4030
+
4031
+ zend_emit_op_tmp (result , ZEND_CALLABLE_CONVERT , NULL , NULL );
4032
+
4033
+ return true;
4024
4034
}
4025
4035
4026
- zend_emit_op_tmp (result , ZEND_CALLABLE_CONVERT , NULL , NULL );
4027
- return true;
4036
+ args_ast = ((zend_ast_fcc * )args_ast )-> args ;
4028
4037
}
4029
4038
4030
4039
bool may_have_extra_named_args ;
4031
- bool is_partial_call ;
4032
4040
uint32_t arg_count = zend_compile_args (args_ast , fbc ,
4033
- & may_have_extra_named_args , & is_partial_call );
4041
+ is_partial_call , & may_have_extra_named_args );
4034
4042
4035
4043
if (is_partial_call ) {
4036
4044
zend_compile_call_partial (result , arg_count , may_have_extra_named_args , opnum_init , fbc );
@@ -6519,11 +6527,13 @@ static zend_ast *zend_partial_apply(zend_ast *callable_ast, zend_ast *pipe_arg)
6519
6527
return NULL ;
6520
6528
}
6521
6529
6522
- zend_ast_list * arg_list = zend_ast_call_get_arg_list (callable_ast );
6523
- if (!arg_list ) {
6530
+ zend_ast * args_ast = zend_ast_call_get_args (callable_ast );
6531
+ if (!args_ast || args_ast -> kind != ZEND_AST_CALLABLE_CONVERT ) {
6524
6532
return NULL ;
6525
6533
}
6526
6534
6535
+ zend_ast_list * arg_list = zend_ast_get_list (((zend_ast_fcc * )args_ast )-> args );
6536
+
6527
6537
zend_ast * first_placeholder = NULL ;
6528
6538
bool uses_variadic_placeholder = false;
6529
6539
@@ -6557,10 +6567,7 @@ static zend_ast *zend_partial_apply(zend_ast *callable_ast, zend_ast *pipe_arg)
6557
6567
}
6558
6568
}
6559
6569
6560
- if (first_placeholder == NULL ) {
6561
- /* Not a PFA */
6562
- return NULL ;
6563
- }
6570
+ ZEND_ASSERT (first_placeholder );
6564
6571
6565
6572
zend_ast * new_arg_list = zend_ast_create_list (0 , arg_list -> kind );
6566
6573
for (uint32_t i = 0 ; i < arg_list -> children ; i ++ ) {
@@ -6601,30 +6608,14 @@ static void zend_compile_pipe(znode *result, zend_ast *ast)
6601
6608
6602
6609
/* Turn the operand into a function parameter list. */
6603
6610
zend_ast * arg = zend_ast_create_znode (& wrapped_operand_result );
6604
- zend_ast * arg_list_ast = zend_ast_create_list (1 , ZEND_AST_ARG_LIST , arg );
6605
6611
6606
6612
zend_ast * fcall_ast ;
6607
6613
znode callable_result ;
6608
6614
6609
6615
zend_ast * pfa_arg_list_ast = NULL ;
6610
6616
6611
- /* Turn $foo |> bar(...) into bar($foo). */
6612
- if (callable_ast -> kind == ZEND_AST_CALL
6613
- && callable_ast -> child [1 ]-> kind == ZEND_AST_CALLABLE_CONVERT ) {
6614
- fcall_ast = zend_ast_create (ZEND_AST_CALL ,
6615
- callable_ast -> child [0 ], arg_list_ast );
6616
- /* Turn $foo |> bar::baz(...) into bar::baz($foo). */
6617
- } else if (callable_ast -> kind == ZEND_AST_STATIC_CALL
6618
- && callable_ast -> child [2 ]-> kind == ZEND_AST_CALLABLE_CONVERT ) {
6619
- fcall_ast = zend_ast_create (ZEND_AST_STATIC_CALL ,
6620
- callable_ast -> child [0 ], callable_ast -> child [1 ], arg_list_ast );
6621
- /* Turn $foo |> $bar->baz(...) into $bar->baz($foo). */
6622
- } else if (callable_ast -> kind == ZEND_AST_METHOD_CALL
6623
- && callable_ast -> child [2 ]-> kind == ZEND_AST_CALLABLE_CONVERT ) {
6624
- fcall_ast = zend_ast_create (ZEND_AST_METHOD_CALL ,
6625
- callable_ast -> child [0 ], callable_ast -> child [1 ], arg_list_ast );
6626
6617
/* Turn $foo |> PFA into plain function call if possible */
6627
- } else if ((pfa_arg_list_ast = zend_partial_apply (callable_ast , arg ))) {
6618
+ if ((pfa_arg_list_ast = zend_partial_apply (callable_ast , arg ))) {
6628
6619
switch (callable_ast -> kind ) {
6629
6620
case ZEND_AST_CALL :
6630
6621
fcall_ast = zend_ast_create (ZEND_AST_CALL ,
@@ -6644,6 +6635,7 @@ static void zend_compile_pipe(znode *result, zend_ast *ast)
6644
6635
}
6645
6636
/* Turn $foo |> $expr into ($expr)($foo) */
6646
6637
} else {
6638
+ zend_ast * arg_list_ast = zend_ast_create_list (1 , ZEND_AST_ARG_LIST , arg );
6647
6639
zend_compile_expr (& callable_result , callable_ast );
6648
6640
callable_ast = zend_ast_create_znode (& callable_result );
6649
6641
fcall_ast = zend_ast_create (ZEND_AST_CALL ,
@@ -11570,6 +11562,13 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr)
11570
11562
if ((* args_ast )-> kind != ZEND_AST_CALLABLE_CONVERT ) {
11571
11563
zend_error_noreturn (E_COMPILE_ERROR , "Constant expression contains invalid operations" );
11572
11564
}
11565
+
11566
+ zend_ast_list * args = zend_ast_get_list (((zend_ast_fcc * )* args_ast )-> args );
11567
+ if (args -> children != 1 || args -> child [0 ]-> attr != _IS_PLACEHOLDER_VARIADIC ) {
11568
+ // TODO: PFAs
11569
+ zend_error_noreturn (E_COMPILE_ERROR , "Constant expression contains invalid operations" );
11570
+ }
11571
+
11573
11572
ZEND_MAP_PTR_NEW (((zend_ast_fcc * )* args_ast )-> fptr );
11574
11573
11575
11574
switch ((* ast_ptr )-> kind ) {
0 commit comments