@@ -1354,10 +1354,10 @@ static zend_string *add_intersection_type(zend_string *str,
1354
1354
ZEND_TYPE_LIST_FOREACH (intersection_type_list , single_type ) {
1355
1355
ZEND_ASSERT (!ZEND_TYPE_HAS_LIST (* single_type ));
1356
1356
ZEND_ASSERT (ZEND_TYPE_HAS_NAME (* single_type ));
1357
- zend_string * name = ZEND_TYPE_NAME ( * single_type );
1358
- zend_string * resolved = resolve_class_name ( name , scope );
1359
- intersection_str = add_type_string ( intersection_str , resolved , /* is_intersection */ true);
1360
- zend_string_release ( resolved );
1357
+ ZEND_ASSERT (! ZEND_TYPE_IS_RELATIVE_SELF ( * single_type ) && "Compile time disallowed to have 'self' in intersection" );
1358
+ ZEND_ASSERT (! ZEND_TYPE_IS_RELATIVE_PARENT ( * single_type ) && "Compile time disallowed to have 'parent' in intersection" );
1359
+
1360
+ intersection_str = add_type_string ( intersection_str , ZEND_TYPE_NAME ( * single_type ), /* is_intersection */ true );
1361
1361
} ZEND_TYPE_LIST_FOREACH_END ();
1362
1362
1363
1363
ZEND_ASSERT (intersection_str );
@@ -1389,13 +1389,30 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
1389
1389
}
1390
1390
ZEND_ASSERT (!ZEND_TYPE_HAS_LIST (* list_type ));
1391
1391
ZEND_ASSERT (ZEND_TYPE_HAS_NAME (* list_type ));
1392
- zend_string * name = ZEND_TYPE_NAME (* list_type );
1393
- zend_string * resolved = resolve_class_name (name , scope );
1394
- str = add_type_string (str , resolved , /* is_intersection */ false);
1395
- zend_string_release (resolved );
1392
+
1393
+ /* We already have resolved types from compile time
1394
+ * Mimic unresolved types for BC with "self" and "parent" */
1395
+ if (!scope && ZEND_TYPE_IS_RELATIVE_SELF (* list_type )) {
1396
+ str = add_type_string (str , ZSTR_KNOWN (ZEND_STR_SELF ), /* is_intersection */ false);
1397
+ } else if (!scope && ZEND_TYPE_IS_RELATIVE_PARENT (* list_type )) {
1398
+ str = add_type_string (str , ZSTR_KNOWN (ZEND_STR_PARENT ), /* is_intersection */ false);
1399
+ } else {
1400
+ zend_string * name = ZEND_TYPE_NAME (* list_type );
1401
+ zend_string * resolved = resolve_class_name (name , scope );
1402
+ str = add_type_string (str , resolved , /* is_intersection */ false);
1403
+ zend_string_release (resolved );
1404
+ }
1396
1405
} ZEND_TYPE_LIST_FOREACH_END ();
1397
1406
} else if (ZEND_TYPE_HAS_NAME (type )) {
1398
- str = resolve_class_name (ZEND_TYPE_NAME (type ), scope );
1407
+ /* We already have resolved types from compile time
1408
+ * Mimic unresolved types for BC with "self" and "parent" */
1409
+ if (!scope && ZEND_TYPE_IS_RELATIVE_SELF (type )) {
1410
+ str = ZSTR_KNOWN (ZEND_STR_SELF );
1411
+ } else if (!scope && ZEND_TYPE_IS_RELATIVE_PARENT (type )) {
1412
+ str = ZSTR_KNOWN (ZEND_STR_PARENT );
1413
+ } else {
1414
+ str = resolve_class_name (ZEND_TYPE_NAME (type ), scope );
1415
+ }
1399
1416
}
1400
1417
1401
1418
uint32_t type_mask = ZEND_TYPE_PURE_MASK (type );
@@ -6592,14 +6609,14 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
6592
6609
6593
6610
return (zend_type ) ZEND_TYPE_INIT_CODE (ast -> attr , 0 , 0 );
6594
6611
} else {
6595
- zend_string * class_name = zend_ast_get_str (ast );
6596
- uint8_t type_code = zend_lookup_builtin_type_by_name (class_name );
6612
+ zend_string * type_name = zend_ast_get_str (ast );
6613
+ uint8_t type_code = zend_lookup_builtin_type_by_name (type_name );
6597
6614
6598
6615
if (type_code != 0 ) {
6599
6616
if ((ast -> attr & ZEND_NAME_NOT_FQ ) != ZEND_NAME_NOT_FQ ) {
6600
6617
zend_error_noreturn (E_COMPILE_ERROR ,
6601
6618
"Type declaration '%s' must be unqualified" ,
6602
- ZSTR_VAL (zend_string_tolower (class_name )));
6619
+ ZSTR_VAL (zend_string_tolower (type_name )));
6603
6620
}
6604
6621
6605
6622
/* Transform iterable into a type union alias */
@@ -6613,38 +6630,58 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
6613
6630
return (zend_type ) ZEND_TYPE_INIT_CODE (type_code , 0 , 0 );
6614
6631
} else {
6615
6632
const char * correct_name ;
6616
- zend_string * orig_name = zend_ast_get_str (ast );
6617
6633
uint32_t fetch_type = zend_get_class_fetch_type_ast (ast );
6634
+ uint32_t type_flags = 0 ;
6635
+ zend_string * class_name = type_name ;
6636
+
6618
6637
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT ) {
6619
6638
class_name = zend_resolve_class_name_ast (ast );
6620
6639
zend_assert_valid_class_name (class_name );
6621
6640
} else {
6641
+ ZEND_ASSERT (fetch_type == ZEND_FETCH_CLASS_SELF || fetch_type == ZEND_FETCH_CLASS_PARENT );
6642
+
6622
6643
zend_ensure_valid_class_fetch_type (fetch_type );
6644
+ if (fetch_type == ZEND_FETCH_CLASS_SELF ) {
6645
+ type_flags = _ZEND_TYPE_SELF_BIT ;
6646
+ /* Scope might be unknown for unbound closures and traits */
6647
+ if (zend_is_scope_known ()) {
6648
+ class_name = CG (active_class_entry )-> name ;
6649
+ ZEND_ASSERT (class_name && "must know class name when resolving self type at compile time" );
6650
+ }
6651
+ } else {
6652
+ ZEND_ASSERT (fetch_type == ZEND_FETCH_CLASS_PARENT );
6653
+ type_flags = _ZEND_TYPE_PARENT_BIT ;
6654
+ /* Scope might be unknown for unbound closures and traits */
6655
+ if (zend_is_scope_known ()) {
6656
+ class_name = CG (active_class_entry )-> parent_name ;
6657
+ ZEND_ASSERT (class_name && "must know class name when resolving parent type at compile time" );
6658
+ }
6659
+ }
6623
6660
zend_string_addref (class_name );
6624
6661
}
6625
6662
6626
6663
if (ast -> attr == ZEND_NAME_NOT_FQ
6627
- && zend_is_confusable_type (orig_name , & correct_name )
6628
- && zend_is_not_imported (orig_name )) {
6664
+ && zend_is_confusable_type (type_name , & correct_name )
6665
+ && zend_is_not_imported (type_name )) {
6629
6666
const char * extra =
6630
6667
FC (current_namespace ) ? " or import the class with \"use\"" : "" ;
6631
6668
if (correct_name ) {
6632
6669
zend_error (E_COMPILE_WARNING ,
6633
6670
"\"%s\" will be interpreted as a class name. Did you mean \"%s\"? "
6634
6671
"Write \"\\%s\"%s to suppress this warning" ,
6635
- ZSTR_VAL (orig_name ), correct_name , ZSTR_VAL (class_name ), extra );
6672
+ ZSTR_VAL (type_name ), correct_name , ZSTR_VAL (class_name ), extra );
6636
6673
} else {
6637
6674
zend_error (E_COMPILE_WARNING ,
6638
6675
"\"%s\" is not a supported builtin type "
6639
6676
"and will be interpreted as a class name. "
6640
6677
"Write \"\\%s\"%s to suppress this warning" ,
6641
- ZSTR_VAL (orig_name ), ZSTR_VAL (class_name ), extra );
6678
+ ZSTR_VAL (type_name ), ZSTR_VAL (class_name ), extra );
6642
6679
}
6643
6680
}
6644
6681
6645
6682
class_name = zend_new_interned_string (class_name );
6646
6683
zend_alloc_ce_cache (class_name );
6647
- return (zend_type ) ZEND_TYPE_INIT_CLASS (class_name , 0 , 0 );
6684
+ return (zend_type ) ZEND_TYPE_INIT_CLASS (class_name , /* allow null */ false, type_flags );
6648
6685
}
6649
6686
}
6650
6687
}
@@ -6726,7 +6763,34 @@ static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list
6726
6763
}
6727
6764
if (zend_string_equals_ci (ZEND_TYPE_NAME (type_list -> types [i ]), ZEND_TYPE_NAME (type ))) {
6728
6765
zend_string * single_type_str = zend_type_to_string (type );
6729
- zend_error_noreturn (E_COMPILE_ERROR , "Duplicate type %s is redundant" , ZSTR_VAL (single_type_str ));
6766
+ if (
6767
+ ZEND_TYPE_IS_RELATIVE_SELF (type )
6768
+ || ZEND_TYPE_IS_RELATIVE_PARENT (type )
6769
+ ) {
6770
+ if ( (
6771
+ ZEND_TYPE_FULL_MASK (type )
6772
+ & ZEND_TYPE_FULL_MASK (type_list -> types [i ])
6773
+ & (_ZEND_TYPE_SELF_BIT |_ZEND_TYPE_PARENT_BIT )) != 0
6774
+ ) {
6775
+ zend_error_noreturn (E_COMPILE_ERROR , "Duplicate type %s is redundant" , ZSTR_VAL (single_type_str ));
6776
+ }
6777
+ /* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6778
+ * ZEND_TYPE_NAME() */
6779
+ zend_error_noreturn (E_COMPILE_ERROR , "%s resolves to %s which is redundant" ,
6780
+ ZSTR_VAL (single_type_str ), ZSTR_VAL (ZEND_TYPE_NAME (type ))
6781
+ );
6782
+ } else if (
6783
+ ZEND_TYPE_IS_RELATIVE_SELF (type_list -> types [i ])
6784
+ || ZEND_TYPE_IS_RELATIVE_PARENT (type_list -> types [i ])
6785
+ ) {
6786
+ /* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6787
+ * ZEND_TYPE_NAME() */
6788
+ zend_error_noreturn (E_COMPILE_ERROR , "%s resolves to %s which is redundant" ,
6789
+ ZEND_TYPE_IS_RELATIVE_SELF (type_list -> types [i ]) ? "self" : "parent" , ZSTR_VAL (ZEND_TYPE_NAME (type ))
6790
+ );
6791
+ } else {
6792
+ zend_error_noreturn (E_COMPILE_ERROR , "Duplicate type %s is redundant" , ZSTR_VAL (single_type_str ));
6793
+ }
6730
6794
}
6731
6795
}
6732
6796
}
@@ -6767,6 +6831,7 @@ static zend_type zend_compile_typename_ex(
6767
6831
/* Switch from single name to name list. */
6768
6832
type_list -> num_types = 1 ;
6769
6833
type_list -> types [0 ] = type ;
6834
+ /* Clear MAY_BE_* type flags */
6770
6835
ZEND_TYPE_FULL_MASK (type_list -> types [0 ]) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6771
6836
}
6772
6837
/* Mark type as list type */
@@ -6813,20 +6878,26 @@ static zend_type zend_compile_typename_ex(
6813
6878
"Type contains both true and false, bool should be used instead" );
6814
6879
}
6815
6880
ZEND_TYPE_FULL_MASK (type ) |= ZEND_TYPE_PURE_MASK (single_type );
6881
+ /* Clear MAY_BE_* type flags */
6816
6882
ZEND_TYPE_FULL_MASK (single_type ) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6817
6883
6818
6884
if (ZEND_TYPE_IS_COMPLEX (single_type )) {
6819
6885
if (!ZEND_TYPE_IS_COMPLEX (type ) && !is_composite ) {
6820
6886
/* The first class type can be stored directly as the type ptr payload. */
6821
6887
ZEND_TYPE_SET_PTR (type , ZEND_TYPE_NAME (single_type ));
6822
6888
ZEND_TYPE_FULL_MASK (type ) |= _ZEND_TYPE_NAME_BIT ;
6889
+ /* Add flags indicating the named type is self/parent */
6890
+ ZEND_TYPE_FULL_MASK (type ) |= (ZEND_TYPE_FULL_MASK (single_type ) & _ZEND_TYPE_RELATIVE_TYPE_MASK );
6823
6891
} else {
6824
6892
if (type_list -> num_types == 0 ) {
6825
6893
/* Switch from single name to name list. */
6826
6894
type_list -> num_types = 1 ;
6827
6895
type_list -> types [0 ] = type ;
6896
+ /* Clear MAY_BE_* type flags */
6828
6897
ZEND_TYPE_FULL_MASK (type_list -> types [0 ]) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6829
6898
ZEND_TYPE_SET_LIST (type , type_list );
6899
+ /* Clear flags indicating the named type is self/parent */
6900
+ ZEND_TYPE_FULL_MASK (type ) &= ~_ZEND_TYPE_RELATIVE_TYPE_MASK ;
6830
6901
}
6831
6902
6832
6903
type_list -> types [type_list -> num_types ++ ] = single_type ;
@@ -6888,10 +6959,11 @@ static zend_type zend_compile_typename_ex(
6888
6959
zend_string_release_ex (standard_type_str , false);
6889
6960
}
6890
6961
/* Check for "self" and "parent" too */
6891
- if (zend_string_equals_literal_ci (ZEND_TYPE_NAME (single_type ), "self" )
6892
- || zend_string_equals_literal_ci (ZEND_TYPE_NAME (single_type ), "parent" )) {
6893
- zend_error_noreturn (E_COMPILE_ERROR ,
6894
- "Type %s cannot be part of an intersection type" , ZSTR_VAL (ZEND_TYPE_NAME (single_type )));
6962
+ if (ZEND_TYPE_IS_RELATIVE_SELF (single_type )) {
6963
+ zend_error_noreturn (E_COMPILE_ERROR , "Type self cannot be part of an intersection type" );
6964
+ }
6965
+ if (ZEND_TYPE_IS_RELATIVE_PARENT (single_type )) {
6966
+ zend_error_noreturn (E_COMPILE_ERROR , "Type parent cannot be part of an intersection type" );
6895
6967
}
6896
6968
6897
6969
/* Add type to the type list */
0 commit comments