@@ -1862,6 +1862,31 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
1862
1862
}
1863
1863
/* }}} */
1864
1864
1865
+ /* {{{ */
1866
+ void zend_do_function_return_hint (const znode * return_hint , zend_bool allow_null TSRMLS_DC ) {
1867
+ if (return_hint -> op_type != IS_UNUSED ) {
1868
+ CG (active_op_array )-> return_hint .used = 1 ;
1869
+ CG (active_op_array )-> return_hint .allow_null = allow_null ;
1870
+
1871
+ if (return_hint -> op_type == IS_CONST ) {
1872
+ if (Z_TYPE (return_hint -> u .constant ) == IS_STRING ) {
1873
+ CG (active_op_array )-> return_hint .type = IS_OBJECT ;
1874
+ CG (active_op_array )-> return_hint .class_name_len = Z_STRLEN (return_hint -> u .constant );
1875
+ CG (active_op_array )-> return_hint .class_name = zend_new_interned_string
1876
+ (Z_STRVAL (return_hint -> u .constant ), Z_STRLEN (return_hint -> u .constant )+ 1 , 1 TSRMLS_CC );
1877
+ } else {
1878
+ CG (active_op_array )-> return_hint .type = Z_TYPE (return_hint -> u .constant );
1879
+ }
1880
+ } else {
1881
+ printf ("non constant return hint\n" );
1882
+ CG (active_op_array )-> return_hint .type = IS_OBJECT ;
1883
+ CG (active_op_array )-> return_hint .class_name_len = Z_STRLEN (return_hint -> u .constant );
1884
+ CG (active_op_array )-> return_hint .class_name = zend_new_interned_string
1885
+ (Z_STRVAL (return_hint -> u .constant ), Z_STRLEN (return_hint -> u .constant )+ 1 , 1 TSRMLS_CC );
1886
+ }
1887
+ }
1888
+ } /* }}} */
1889
+
1865
1890
void zend_do_receive_param (zend_uchar op , znode * varname , const znode * initialization , znode * class_type , zend_uchar pass_by_reference , zend_bool is_variadic TSRMLS_DC ) /* {{{ */
1866
1891
{
1867
1892
zend_op * opline ;
@@ -2806,6 +2831,20 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
2806
2831
2807
2832
start_op_number = get_next_op_number (CG (active_op_array ));
2808
2833
2834
+ if (CG (active_op_array )-> return_hint .used && expr ) {
2835
+ if (expr -> op_type == IS_UNUSED && !CG (active_op_array )-> return_hint .allow_null ) {
2836
+ zend_error (E_COMPILE_ERROR , "return hint error in %s" , CG (active_op_array )-> function_name );
2837
+ } else {
2838
+ if (expr -> op_type == IS_CONST ) {
2839
+ if (Z_TYPE (expr -> u .constant ) & ~IS_CONSTANT_TYPE_MASK != CG (active_op_array )-> return_hint .type ) {
2840
+ zend_error (E_COMPILE_ERROR , "return type mismatch" );
2841
+ }
2842
+ }
2843
+
2844
+ /* work out if we can do anything else */
2845
+ }
2846
+ }
2847
+
2809
2848
#ifdef ZTS
2810
2849
zend_stack_apply_with_argument (& CG (switch_cond_stack ), ZEND_STACK_APPLY_TOPDOWN , (int (* )(void * element , void * )) generate_free_switch_expr TSRMLS_CC );
2811
2850
zend_stack_apply_with_argument (& CG (foreach_copy_stack ), ZEND_STACK_APPLY_TOPDOWN , (int (* )(void * element , void * )) generate_free_foreach_copy TSRMLS_CC );
@@ -3512,7 +3551,38 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
3512
3551
REALLOC_BUF_IF_EXCEED (buf , offset , length , 32 );
3513
3552
}
3514
3553
}
3554
+
3515
3555
* (offset ++ ) = ')' ;
3556
+
3557
+ if (fptr -> common .return_hint .used ) {
3558
+ REALLOC_BUF_IF_EXCEED (buf , offset , length , 4 );
3559
+ * (offset ++ ) = ' ' ;
3560
+ * (offset ++ ) = ':' ;
3561
+ * (offset ++ ) = ' ' ;
3562
+
3563
+ if (fptr -> common .return_hint .allow_null ) {
3564
+ * (offset ++ ) = '?' ;
3565
+ }
3566
+
3567
+ switch (fptr -> common .return_hint .type ) {
3568
+ case IS_OBJECT :
3569
+ REALLOC_BUF_IF_EXCEED (buf , offset , length , fptr -> common .return_hint .class_name_len );
3570
+ memcpy (offset , fptr -> common .return_hint .class_name , fptr -> common .return_hint .class_name_len );
3571
+ offset += fptr -> common .return_hint .class_name_len ;
3572
+ break ;
3573
+
3574
+ default : {
3575
+ char * type = zend_get_type_by_const (fptr -> common .return_hint .type );
3576
+ if (type ) {
3577
+ size_t type_len = strlen (type );
3578
+ REALLOC_BUF_IF_EXCEED (buf , offset , length , type_len );
3579
+ memcpy (offset , type , type_len );
3580
+ offset += type_len ;
3581
+ }
3582
+ }
3583
+ }
3584
+ }
3585
+
3516
3586
* offset = '\0' ;
3517
3587
3518
3588
return buf ;
@@ -3588,6 +3658,51 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
3588
3658
efree (method_prototype );
3589
3659
}
3590
3660
}
3661
+
3662
+ if (parent -> common .return_hint .used ) {
3663
+
3664
+ if (!child -> common .return_hint .used ) {
3665
+ char * method_prototype = zend_get_function_declaration (parent TSRMLS_CC );
3666
+ zend_error (E_COMPILE_ERROR , "Delcaration of %s::%s should be compatible with %s, return type missing" , ZEND_FN_SCOPE_NAME (child ), child -> common .function_name , method_prototype );
3667
+ efree (method_prototype );
3668
+ return ;
3669
+ }
3670
+
3671
+ if (child -> common .return_hint .type != parent -> common .return_hint .type ) {
3672
+ char * method_prototype = zend_get_function_declaration (parent TSRMLS_CC );
3673
+ zend_error (E_COMPILE_ERROR , "Delcaration of %s::%s should be compatible with %s, return type mismatch" , ZEND_FN_SCOPE_NAME (child ), child -> common .function_name , method_prototype );
3674
+ efree (method_prototype );
3675
+ return ;
3676
+ }
3677
+
3678
+ if (child -> common .return_hint .type == IS_OBJECT ) {
3679
+ zend_class_entry * * pce = NULL , * * cce = NULL ;
3680
+
3681
+ if (zend_lookup_class (child -> common .return_hint .class_name , child -> common .return_hint .class_name_len , & cce TSRMLS_CC ) != SUCCESS ) {
3682
+ char * method_prototype = zend_get_function_declaration (parent TSRMLS_CC );
3683
+ zend_error (E_COMPILE_ERROR , "Delcaration of %s::%s declares return type %s, which could not be found" ,
3684
+ ZEND_FN_SCOPE_NAME (child ), child -> common .function_name , child -> common .return_hint .class_name );
3685
+ efree (method_prototype );
3686
+ return ;
3687
+ }
3688
+
3689
+ if (zend_lookup_class (parent -> common .return_hint .class_name , parent -> common .return_hint .class_name_len , & pce TSRMLS_CC ) != SUCCESS ) {
3690
+ char * method_prototype = zend_get_function_declaration (parent TSRMLS_CC );
3691
+ zend_error (E_COMPILE_ERROR , "Delcaration of %s::%s declares return type %s, which could not be found" ,
3692
+ ZEND_FN_SCOPE_NAME (parent ), parent -> common .function_name , parent -> common .return_hint .class_name );
3693
+ efree (method_prototype );
3694
+ return ;
3695
+ }
3696
+
3697
+ if (!instanceof_function (* cce , * pce TSRMLS_CC )) {
3698
+ char * method_prototype = zend_get_function_declaration (parent TSRMLS_CC );
3699
+ zend_error (E_COMPILE_ERROR , "Delcaration of %s::%s should be compatible with %s, return type mismatch" ,
3700
+ ZEND_FN_SCOPE_NAME (child ), child -> common .function_name , method_prototype );
3701
+ efree (method_prototype );
3702
+ return ;
3703
+ }
3704
+ }
3705
+ }
3591
3706
}
3592
3707
/* }}} */
3593
3708
0 commit comments