@@ -1194,28 +1194,73 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
11941194 return zend_string_copy (name );
11951195}
11961196
1197+ static zend_string * resolve_intersection_type (zend_string * str ,
1198+ zend_type_list * intersection_type_list , zend_class_entry * scope )
1199+ {
1200+ zend_type * single_type ;
1201+ /* First type is not part of an intersection with the previous type */
1202+ bool is_intersection = false;
1203+
1204+ ZEND_TYPE_LIST_FOREACH (intersection_type_list , single_type ) {
1205+ if (ZEND_TYPE_HAS_CE (* single_type )) {
1206+ str = add_type_string (str , ZEND_TYPE_CE (* single_type )-> name , is_intersection );
1207+ } else {
1208+ if (ZEND_TYPE_HAS_CE_CACHE (* single_type )
1209+ && ZEND_TYPE_CE_CACHE (* single_type )) {
1210+ zend_class_entry * ce = ZEND_TYPE_CE_CACHE (* single_type );
1211+
1212+ // TODO Can this happen?
1213+ if (ce -> ce_flags & ZEND_ACC_ANON_CLASS ) {
1214+ zend_string * tmp = zend_string_init (ZSTR_VAL (ce -> name ), strlen (ZSTR_VAL (ce -> name )), 0 );
1215+ str = add_type_string (str , tmp , is_intersection );
1216+ } else {
1217+ str = add_type_string (str , ce -> name , is_intersection );
1218+ }
1219+ } else {
1220+ zend_string * resolved = resolve_class_name (ZEND_TYPE_NAME (* single_type ), scope );
1221+ str = add_type_string (str , resolved , is_intersection );
1222+ zend_string_release (resolved );
1223+ }
1224+ }
1225+ is_intersection = true;
1226+ } ZEND_TYPE_LIST_FOREACH_END ();
1227+
1228+ return str ;
1229+ }
1230+
11971231zend_string * zend_type_to_string_resolved (zend_type type , zend_class_entry * scope ) {
11981232 zend_string * str = NULL ;
11991233
1200- if (ZEND_TYPE_HAS_LIST (type )) {
1234+ /* Pure intersection type */
1235+ if (ZEND_TYPE_IS_INTERSECTION (type )) {
1236+ ZEND_ASSERT (!ZEND_TYPE_IS_UNION (type ));
1237+ str = resolve_intersection_type (str , ZEND_TYPE_LIST (type ), scope );
1238+ }
1239+
1240+ if (ZEND_TYPE_IS_UNION (type )) {
12011241 zend_type * list_type ;
1202- bool is_intersection = ZEND_TYPE_IS_INTERSECTION (type );
12031242 ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (type ), list_type ) {
1243+ /* Type within the union is an intersection */
1244+ if (ZEND_TYPE_IS_INTERSECTION (* list_type )) {
1245+ str = resolve_intersection_type (str , ZEND_TYPE_LIST (* list_type ), scope );
1246+ continue ;
1247+ }
1248+
12041249 if (ZEND_TYPE_HAS_CE (* list_type )) {
1205- str = add_type_string (str , ZEND_TYPE_CE (* list_type )-> name , is_intersection );
1250+ str = add_type_string (str , ZEND_TYPE_CE (* list_type )-> name , /* is_intersection */ false );
12061251 } else {
12071252 if (ZEND_TYPE_HAS_CE_CACHE (* list_type )
12081253 && ZEND_TYPE_CE_CACHE (* list_type )) {
12091254 zend_class_entry * ce = ZEND_TYPE_CE_CACHE (* list_type );
12101255 if (ce -> ce_flags & ZEND_ACC_ANON_CLASS ) {
12111256 zend_string * tmp = zend_string_init (ZSTR_VAL (ce -> name ), strlen (ZSTR_VAL (ce -> name )), 0 );
1212- str = add_type_string (str , tmp , is_intersection );
1257+ str = add_type_string (str , tmp , /* is_intersection */ false );
12131258 } else {
1214- str = add_type_string (str , ce -> name , is_intersection );
1259+ str = add_type_string (str , ce -> name , /* is_intersection */ false );
12151260 }
12161261 } else {
12171262 zend_string * resolved = resolve_class_name (ZEND_TYPE_NAME (* list_type ), scope );
1218- str = add_type_string (str , resolved , is_intersection );
1263+ str = add_type_string (str , resolved , /* is_intersection */ false );
12191264 zend_string_release (resolved );
12201265 }
12211266 }
@@ -6232,8 +6277,29 @@ static zend_type zend_compile_typename(
62326277
62336278 for (uint32_t i = 0 ; i < list -> children ; i ++ ) {
62346279 zend_ast * type_ast = list -> child [i ];
6235- zend_type single_type = zend_compile_single_typename (type_ast );
6236- uint32_t single_type_mask = ZEND_TYPE_PURE_MASK (single_type );
6280+ zend_type single_type ;
6281+ uint32_t single_type_mask ;
6282+
6283+ if (type_ast -> kind == ZEND_AST_TYPE_INTERSECTION ) {
6284+ if (type_list -> num_types == 0 ) {
6285+ /* The first class type can be stored directly as the type ptr payload. */
6286+ if (ZEND_TYPE_IS_COMPLEX (type )) {
6287+ /* Switch from single name to name list. */
6288+ type_list -> num_types = 1 ;
6289+ type_list -> types [0 ] = type ;
6290+ ZEND_TYPE_FULL_MASK (type_list -> types [0 ]) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6291+ }
6292+ /* TODO Check for trivially redundant class types? */
6293+ ZEND_TYPE_SET_LIST (type , type_list );
6294+ }
6295+
6296+ single_type = zend_compile_typename (type_ast , false);
6297+ type_list -> types [type_list -> num_types ++ ] = single_type ;
6298+ continue ;
6299+ }
6300+
6301+ single_type = zend_compile_single_typename (type_ast );
6302+ single_type_mask = ZEND_TYPE_PURE_MASK (single_type );
62376303
62386304 if (single_type_mask == MAY_BE_ANY ) {
62396305 zend_error_noreturn (E_COMPILE_ERROR , "Type mixed can only be used as a standalone type" );
0 commit comments