|
39 | 39 | #include "zend_call_stack.h" |
40 | 40 | #include "zend_frameless_function.h" |
41 | 41 | #include "zend_property_hooks.h" |
| 42 | +#include "zend_smart_str.h" |
42 | 43 |
|
43 | 44 | #define SET_NODE(target, src) do { \ |
44 | 45 | target ## _type = (src)->op_type; \ |
@@ -1484,6 +1485,29 @@ zend_string *zend_type_to_string_resolved(const zend_type type, const zend_class |
1484 | 1485 | if (ZEND_TYPE_IS_INTERSECTION(type)) { |
1485 | 1486 | ZEND_ASSERT(!ZEND_TYPE_IS_UNION(type)); |
1486 | 1487 | str = add_intersection_type(str, ZEND_TYPE_LIST(type), /* is_bracketed */ false); |
| 1488 | + } else if (ZEND_TYPE_IS_NAME_WITH_GENERIC_TYPES(type)) { |
| 1489 | + const zend_type *single_type; |
| 1490 | + bool is_class_name = true; |
| 1491 | + bool just_after_class_name = true; |
| 1492 | + |
| 1493 | + smart_str class_with_generic = {0}; |
| 1494 | + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), single_type) { |
| 1495 | + if (is_class_name) { |
| 1496 | + ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type)); |
| 1497 | + smart_str_append(&class_with_generic, resolve_class_name(ZEND_TYPE_NAME(*single_type), scope)); |
| 1498 | + smart_str_appendc(&class_with_generic, '<'); |
| 1499 | + is_class_name = false; |
| 1500 | + continue; |
| 1501 | + } |
| 1502 | + if (!just_after_class_name) { |
| 1503 | + smart_str_appends(&class_with_generic, ", "); |
| 1504 | + } |
| 1505 | + just_after_class_name = false; |
| 1506 | + smart_str_append(&class_with_generic, zend_type_to_string_resolved(*single_type, scope, bound_types_to_scope)); |
| 1507 | + } ZEND_TYPE_LIST_FOREACH_END(); |
| 1508 | + smart_str_appendc(&class_with_generic, '>'); |
| 1509 | + str = smart_str_extract(&class_with_generic); |
| 1510 | + smart_str_free(&class_with_generic); |
1487 | 1511 | } else if (ZEND_TYPE_HAS_LIST(type)) { |
1488 | 1512 | /* A union type might not be a list */ |
1489 | 1513 | const zend_type *list_type; |
@@ -7413,6 +7437,8 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */ |
7413 | 7437 | } |
7414 | 7438 | /* }}} */ |
7415 | 7439 |
|
| 7440 | +static zend_type zend_compile_typename(zend_ast *ast); |
| 7441 | + |
7416 | 7442 | static zend_type zend_compile_single_typename(zend_ast *ast) |
7417 | 7443 | { |
7418 | 7444 | const zend_class_entry *ce = CG(active_class_entry); |
@@ -7512,7 +7538,32 @@ static zend_type zend_compile_single_typename(zend_ast *ast) |
7512 | 7538 | class_name = zend_new_interned_string(class_name); |
7513 | 7539 | zend_alloc_ce_cache(class_name); |
7514 | 7540 | // TODO: use args_ast |
7515 | | - return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0); |
| 7541 | + if (args_ast) { |
| 7542 | + ZEND_ASSERT(args_ast->kind == ZEND_AST_GENERIC_ARG_LIST); |
| 7543 | + const zend_ast_list *list = zend_ast_get_list(args_ast); |
| 7544 | + |
| 7545 | + /* Allocate the type list directly on the arena as it must be a type |
| 7546 | + * list of the number of AST childs + 1 for the class name */ |
| 7547 | + zend_type_list *type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->children + 1)); |
| 7548 | + type_list->num_types = 0; |
| 7549 | + /* Add type to the type list */ |
| 7550 | + type_list->types[type_list->num_types++] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0); |
| 7551 | + |
| 7552 | + for (uint32_t i = 0; i < list->children; i++) { |
| 7553 | + zend_ast *generic_arg_type_ast = list->child[i]; |
| 7554 | + type_list->types[type_list->num_types++] = zend_compile_typename(generic_arg_type_ast); |
| 7555 | + } |
| 7556 | + ZEND_ASSERT(list->children+1 == type_list->num_types); |
| 7557 | + |
| 7558 | + zend_type type = ZEND_TYPE_INIT_NONE(0); |
| 7559 | + ZEND_TYPE_SET_LIST(type, type_list); |
| 7560 | + /* Inform that the type list is a class name with bound types */ |
| 7561 | + ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_WITH_BOUND_TYPES; |
| 7562 | + ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT; |
| 7563 | + return type; |
| 7564 | + } else { |
| 7565 | + return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0); |
| 7566 | + } |
7516 | 7567 | } |
7517 | 7568 | } |
7518 | 7569 | } |
@@ -7599,8 +7650,6 @@ static void zend_is_type_list_redundant_by_single_type(const zend_type_list *typ |
7599 | 7650 | } |
7600 | 7651 | } |
7601 | 7652 |
|
7602 | | -static zend_type zend_compile_typename(zend_ast *ast); |
7603 | | - |
7604 | 7653 | static zend_type zend_compile_typename_ex( |
7605 | 7654 | zend_ast *ast, bool force_allow_null, bool *forced_allow_null) /* {{{ */ |
7606 | 7655 | { |
|
0 commit comments