summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-01-06 16:06:51 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-01-12 10:14:41 +0100
commit973138f39da192b3948b981b442401c30c8b80bc (patch)
tree63b8736562bd830ebb988bcda942083c9dac6e08 /Zend/zend_API.c
parentbc0f78a2dae1dd3191440883c4f5b06f9bc03901 (diff)
downloadphp-git-973138f39da192b3948b981b442401c30c8b80bc.tar.gz
Add support for union types for internal functions
This closes the last hole in the supported types for internal function arginfo types. It's now possible to represent unions of multiple classes. This is done by storing them as TypeA|TypeB and PHP will then convert this into an appropriate union type list. Closes GH-6581.
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 58b743e641..11760d50f0 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2455,10 +2455,40 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
for (i = 0; i < num_args; i++) {
if (ZEND_TYPE_HAS_CLASS(new_arg_info[i].type)) {
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type)
- && "Only simple classes are currently supported");
+ && "Should be stored as simple name");
const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type);
- ZEND_TYPE_SET_PTR(new_arg_info[i].type,
- zend_string_init_interned(class_name, strlen(class_name), 1));
+
+ size_t num_types = 1;
+ const char *p = class_name;
+ while ((p = strchr(p, '|'))) {
+ num_types++;
+ p++;
+ }
+
+ if (num_types == 1) {
+ /* Simple class type */
+ ZEND_TYPE_SET_PTR(new_arg_info[i].type,
+ zend_string_init_interned(class_name, strlen(class_name), 1));
+ } else {
+ /* Union type */
+ zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types));
+ list->num_types = num_types;
+ ZEND_TYPE_SET_LIST(new_arg_info[i].type, list);
+
+ const char *start = class_name;
+ uint32_t j = 0;
+ while (true) {
+ const char *end = strchr(start, '|');
+ zend_string *str =
+ zend_string_init(start, end ? end - start : strlen(start), 1);
+ list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0);
+ if (!end) {
+ break;
+ }
+ start = end + 1;
+ j++;
+ }
+ }
}
}
}