@@ -1194,15 +1194,62 @@ 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
+ zend_string * name = ZEND_TYPE_NAME (* single_type );
1209
+
1210
+ if (ZSTR_HAS_CE_CACHE (name )
1211
+ && ZSTR_GET_CE_CACHE (name )) {
1212
+ zend_class_entry * ce = ZSTR_GET_CE_CACHE (name );
1213
+ /* Can this happen? */
1214
+ if (ce -> ce_flags & ZEND_ACC_ANON_CLASS ) {
1215
+ zend_string * tmp = zend_string_init (ZSTR_VAL (ce -> name ), strlen (ZSTR_VAL (ce -> name )), 0 );
1216
+ str = add_type_string (str , tmp , is_intersection );
1217
+ } else {
1218
+ str = add_type_string (str , ce -> name , is_intersection );
1219
+ }
1220
+ } else {
1221
+ zend_string * resolved = resolve_class_name (name , scope );
1222
+ str = add_type_string (str , resolved , is_intersection );
1223
+ zend_string_release (resolved );
1224
+ }
1225
+ }
1226
+ /* Following types are part of the intersection */
1227
+ is_intersection = true;
1228
+ } ZEND_TYPE_LIST_FOREACH_END ();
1229
+
1230
+ return str ;
1231
+ }
1232
+
1197
1233
zend_string * zend_type_to_string_resolved (zend_type type , zend_class_entry * scope ) {
1198
1234
zend_string * str = NULL ;
1199
1235
1200
- if (ZEND_TYPE_HAS_LIST (type )) {
1236
+ /* Pure intersection type */
1237
+ if (ZEND_TYPE_IS_INTERSECTION (type )) {
1238
+ ZEND_ASSERT (!ZEND_TYPE_IS_UNION (type ));
1239
+ str = resolve_intersection_type (str , ZEND_TYPE_LIST (type ), scope );
1240
+ }
1241
+
1242
+ if (ZEND_TYPE_IS_UNION (type )) {
1201
1243
zend_type * list_type ;
1202
- bool is_intersection = ZEND_TYPE_IS_INTERSECTION (type );
1203
1244
ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (type ), list_type ) {
1245
+ /* Type within the union is an intersection */
1246
+ if (ZEND_TYPE_IS_INTERSECTION (* list_type )) {
1247
+ str = resolve_intersection_type (str , ZEND_TYPE_LIST (* list_type ), scope );
1248
+ continue ;
1249
+ }
1250
+
1204
1251
if (ZEND_TYPE_HAS_CE (* list_type )) {
1205
- str = add_type_string (str , ZEND_TYPE_CE (* list_type )-> name , is_intersection );
1252
+ str = add_type_string (str , ZEND_TYPE_CE (* list_type )-> name , /* is_intersection */ false );
1206
1253
} else {
1207
1254
zend_string * name = ZEND_TYPE_NAME (* list_type );
1208
1255
@@ -1211,13 +1258,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
1211
1258
zend_class_entry * ce = ZSTR_GET_CE_CACHE (name );
1212
1259
if (ce -> ce_flags & ZEND_ACC_ANON_CLASS ) {
1213
1260
zend_string * tmp = zend_string_init (ZSTR_VAL (ce -> name ), strlen (ZSTR_VAL (ce -> name )), 0 );
1214
- str = add_type_string (str , tmp , is_intersection );
1261
+ str = add_type_string (str , tmp , /* is_intersection */ false );
1215
1262
} else {
1216
- str = add_type_string (str , ce -> name , is_intersection );
1263
+ str = add_type_string (str , ce -> name , /* is_intersection */ false );
1217
1264
}
1218
1265
} else {
1219
1266
zend_string * resolved = resolve_class_name (name , scope );
1220
- str = add_type_string (str , resolved , is_intersection );
1267
+ str = add_type_string (str , resolved , /* is_intersection */ false );
1221
1268
zend_string_release (resolved );
1222
1269
}
1223
1270
}
@@ -6236,8 +6283,31 @@ static zend_type zend_compile_typename(
6236
6283
6237
6284
for (uint32_t i = 0 ; i < list -> children ; i ++ ) {
6238
6285
zend_ast * type_ast = list -> child [i ];
6239
- zend_type single_type = zend_compile_single_typename (type_ast );
6240
- uint32_t single_type_mask = ZEND_TYPE_PURE_MASK (single_type );
6286
+ zend_type single_type ;
6287
+ uint32_t single_type_mask ;
6288
+
6289
+ if (type_ast -> kind == ZEND_AST_TYPE_INTERSECTION ) {
6290
+ /* The first class type can be stored directly as the type ptr payload. */
6291
+ if (ZEND_TYPE_IS_COMPLEX (type ) && !ZEND_TYPE_HAS_LIST (type )) {
6292
+ /* Switch from single name to name list. */
6293
+ type_list -> num_types = 1 ;
6294
+ type_list -> types [0 ] = type ;
6295
+ /* Reset flags for first type */
6296
+ ZEND_TYPE_FULL_MASK (type_list -> types [0 ]) &= ~_ZEND_TYPE_MAY_BE_MASK ;
6297
+ ZEND_TYPE_SET_LIST (type , type_list );
6298
+ }
6299
+
6300
+ single_type = zend_compile_typename (type_ast , false);
6301
+ ZEND_ASSERT (ZEND_TYPE_IS_INTERSECTION (single_type ));
6302
+
6303
+ type_list -> types [type_list -> num_types ++ ] = single_type ;
6304
+
6305
+ /* TODO Check for trivially redundant class types? */
6306
+ continue ;
6307
+ }
6308
+
6309
+ single_type = zend_compile_single_typename (type_ast );
6310
+ single_type_mask = ZEND_TYPE_PURE_MASK (single_type );
6241
6311
6242
6312
if (single_type_mask == MAY_BE_ANY ) {
6243
6313
zend_error_noreturn (E_COMPILE_ERROR , "Type mixed can only be used as a standalone type" );
@@ -6271,6 +6341,9 @@ static zend_type zend_compile_typename(
6271
6341
6272
6342
/* Check for trivially redundant class types */
6273
6343
for (size_t i = 0 ; i < type_list -> num_types - 1 ; i ++ ) {
6344
+ if (ZEND_TYPE_IS_INTERSECTION (type_list -> types [i ])) {
6345
+ continue ;
6346
+ }
6274
6347
if (zend_string_equals_ci (
6275
6348
ZEND_TYPE_NAME (type_list -> types [i ]), ZEND_TYPE_NAME (single_type ))) {
6276
6349
zend_string * single_type_str = zend_type_to_string (single_type );
0 commit comments