@@ -1194,28 +1194,73 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
1194
1194
return zend_string_copy (name );
1195
1195
}
1196
1196
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
+
1197
1231
zend_string * zend_type_to_string_resolved (zend_type type , zend_class_entry * scope ) {
1198
1232
zend_string * str = NULL ;
1199
1233
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 )) {
1201
1241
zend_type * list_type ;
1202
- bool is_intersection = ZEND_TYPE_IS_INTERSECTION (type );
1203
1242
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
+
1204
1249
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 );
1206
1251
} else {
1207
1252
if (ZEND_TYPE_HAS_CE_CACHE (* list_type )
1208
1253
&& ZEND_TYPE_CE_CACHE (* list_type )) {
1209
1254
zend_class_entry * ce = ZEND_TYPE_CE_CACHE (* list_type );
1210
1255
if (ce -> ce_flags & ZEND_ACC_ANON_CLASS ) {
1211
1256
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 );
1213
1258
} else {
1214
- str = add_type_string (str , ce -> name , is_intersection );
1259
+ str = add_type_string (str , ce -> name , /* is_intersection */ false );
1215
1260
}
1216
1261
} else {
1217
1262
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 );
1219
1264
zend_string_release (resolved );
1220
1265
}
1221
1266
}
@@ -6232,8 +6277,31 @@ static zend_type zend_compile_typename(
6232
6277
6233
6278
for (uint32_t i = 0 ; i < list -> children ; i ++ ) {
6234
6279
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
+ /* The first class type can be stored directly as the type ptr payload. */
6285
+ if (ZEND_TYPE_IS_COMPLEX (type ) && !ZEND_TYPE_HAS_LIST (type )) {
6286
+ /* Switch from single name to name list. */
6287
+ type_list -> num_types = 1 ;
6288
+ type_list -> types [0 ] = type ;
6289
+ /* Reset flags for first type */
6290
+ ZEND_TYPE_FULL_MASK (type_list -> types [0 ]) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6291
+ ZEND_TYPE_SET_LIST (type , type_list );
6292
+ }
6293
+
6294
+ single_type = zend_compile_typename (type_ast , false);
6295
+ ZEND_ASSERT (ZEND_TYPE_IS_INTERSECTION (single_type ));
6296
+
6297
+ type_list -> types [type_list -> num_types ++ ] = single_type ;
6298
+
6299
+ /* TODO Check for trivially redundant class types? */
6300
+ continue ;
6301
+ }
6302
+
6303
+ single_type = zend_compile_single_typename (type_ast );
6304
+ single_type_mask = ZEND_TYPE_PURE_MASK (single_type );
6237
6305
6238
6306
if (single_type_mask == MAY_BE_ANY ) {
6239
6307
zend_error_noreturn (E_COMPILE_ERROR , "Type mixed can only be used as a standalone type" );
@@ -6267,6 +6335,9 @@ static zend_type zend_compile_typename(
6267
6335
6268
6336
/* Check for trivially redundant class types */
6269
6337
for (size_t i = 0 ; i < type_list -> num_types - 1 ; i ++ ) {
6338
+ if (ZEND_TYPE_IS_INTERSECTION (type_list -> types [i ])) {
6339
+ continue ;
6340
+ }
6270
6341
if (zend_string_equals_ci (
6271
6342
ZEND_TYPE_NAME (type_list -> types [i ]), ZEND_TYPE_NAME (single_type ))) {
6272
6343
zend_string * single_type_str = zend_type_to_string (single_type );
0 commit comments