]> granicus.if.org Git - php/commitdiff
Add support for generating properties with union type of multiple classes
authorMáté Kocsis <kocsismate@woohoolabs.com>
Tue, 16 Feb 2021 11:26:31 +0000 (12:26 +0100)
committerMáté Kocsis <kocsismate@woohoolabs.com>
Tue, 16 Feb 2021 14:50:13 +0000 (15:50 +0100)
Closes GH-6701

Zend/zend_exceptions_arginfo.h
build/gen_stub.php
ext/zend_test/test.c
ext/zend_test/test.stub.php
ext/zend_test/test_arginfo.h

index 8e8fb7c20bd9cbd3ccb5f53d2a89a4d3a22418f9..b1e4844717763b9fcca3122264099299eeeb3de8 100644 (file)
@@ -245,7 +245,7 @@ static zend_class_entry *register_class_Exception(zend_class_entry *class_entry_
        zval property_previous_default_value;
        ZVAL_NULL(&property_previous_default_value);
        zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1);
-       zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 1, 0));
+       zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 0, MAY_BE_NULL));
        zend_string_release(property_previous_name);
 
        return class_entry;
@@ -309,7 +309,7 @@ static zend_class_entry *register_class_Error(zend_class_entry *class_entry_Thro
        zval property_previous_default_value;
        ZVAL_NULL(&property_previous_default_value);
        zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1);
-       zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 1, 0));
+       zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 0, MAY_BE_NULL));
        zend_string_release(property_previous_name);
 
        return class_entry;
index ee4033ab1097e90d423e6ba7e4f5fc6dc765ad7a..084e142e3459830ecdc103d0ff218b63e7eee864 100755 (executable)
@@ -1047,16 +1047,30 @@ class PropertyInfo
         if ($this->type) {
             $arginfoType = $this->type->toArginfoType();
             if ($arginfoType->hasClassType()) {
-                $simpleType = $this->type->tryToSimpleType();
+                if (count($arginfoType->classTypes) >= 2) {
+                    foreach ($arginfoType->classTypes as $classType) {
+                        $className = $classType->name;
+                        $code .= "\tzend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\") - 1, 1);\n";
+                    }
 
-                $className = $arginfoType->classTypes[0]->name;
-                $code .= "     zend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\")-1, 1);\n";
-                if ($simpleType) {
-                    $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, " .  ((int) $this->type->isNullable()) . ", 0)";
-                } elseif (count($arginfoType->classTypes) === 1) {
-                    $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, " . $arginfoType->toTypeMask() . ")";
+                    $classTypeCount = count($arginfoType->classTypes);
+                    $code .= "\tzend_type_list *property_{$propertyName}_type_list = malloc(ZEND_TYPE_LIST_SIZE($classTypeCount));\n";
+                    $code .= "\tproperty_{$propertyName}_type_list->num_types = $classTypeCount;\n";
+
+                    foreach ($arginfoType->classTypes as $k => $classType) {
+                        $className = $classType->name;
+                        $code .= "\tproperty_{$propertyName}_type_list->types[$k] = (zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, 0);\n";
+                    }
+
+                    $typeMaskCode = $this->type->toArginfoType()->toTypeMask();
+
+                    $code .= "\tzend_type property_{$propertyName}_type = ZEND_TYPE_INIT_PTR(property_{$propertyName}_type_list, _ZEND_TYPE_LIST_BIT, 0, $typeMaskCode);\n";
+                    $typeCode = "property_{$propertyName}_type";
                 } else {
-                    throw new Exception("Property $this->name has an unsupported union type");
+                    $className = $arginfoType->classTypes[0]->name;
+                    $code .= "\tzend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\")-1, 1);\n";
+
+                    $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, " . $arginfoType->toTypeMask() . ")";
                 }
             } else {
                 $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $arginfoType->toTypeMask() . ")";
index e54c201891e467da9f0a45ef6d6cd2d5337969ef..27be53faea57433026004399f80586c16e0f9376 100644 (file)
@@ -366,21 +366,6 @@ PHP_MINIT_FUNCTION(zend_test)
        zend_test_class->create_object = zend_test_class_new;
        zend_test_class->get_static_method = zend_test_class_static_method_get;
 
-       {
-               zend_string *name = zend_string_init("classUnionProp", sizeof("classUnionProp") - 1, 1);
-               zend_string *class_name1 = zend_string_init("stdClass", sizeof("stdClass") - 1, 1);
-               zend_string *class_name2 = zend_string_init("Iterator", sizeof("Iterator") - 1, 1);
-               zend_type_list *type_list = malloc(ZEND_TYPE_LIST_SIZE(2));
-               type_list->num_types = 2;
-               type_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name1, 0, 0);
-               type_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name2, 0, 0);
-               zend_type type = ZEND_TYPE_INIT_PTR(type_list, _ZEND_TYPE_LIST_BIT, 1, 0);
-               zval val;
-               ZVAL_NULL(&val);
-               zend_declare_typed_property(zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, type);
-               zend_string_release(name);
-       }
-
        zend_test_child_class = register_class__ZendTestChildClass(zend_test_class);
 
        memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
index 98dba6a396586b0561405b43674e00405c97de6d..624ba1195f3cdf0a1af759781b65ddc9787e1e59 100644 (file)
@@ -16,7 +16,7 @@ class _ZendTestClass implements _ZendTestInterface {
 
     public int $intProp = 123;
     public ?stdClass $classProp = null;
-    //public stdClass|Iterator|null $classUnionProp = null;
+    public stdClass|Iterator|null $classUnionProp = null;
 
     public static function is_object(): int {}
 
index b7dd3dbe28386a77f83d412d341ecebe898e581d..dc040a568043fe255df74e4a8c148fccf130a5d1 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: cfe2668e6d45a45dafb313cc8b053e2c81ef053a */
+ * Stub hash: cf8958513064fb7257203b3304c8dc67c8e008b9 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
 ZEND_END_ARG_INFO()
@@ -201,9 +201,22 @@ static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_e
        zval property_classProp_default_value;
        ZVAL_NULL(&property_classProp_default_value);
        zend_string *property_classProp_name = zend_string_init("classProp", sizeof("classProp") - 1, 1);
-       zend_declare_typed_property(class_entry, property_classProp_name, &property_classProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_classProp_class_stdClass, 1, 0));
+       zend_declare_typed_property(class_entry, property_classProp_name, &property_classProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_classProp_class_stdClass, 0, MAY_BE_NULL));
        zend_string_release(property_classProp_name);
 
+       zend_string *property_classUnionProp_class_stdClass = zend_string_init("stdClass", sizeof("stdClass") - 1, 1);
+       zend_string *property_classUnionProp_class_Iterator = zend_string_init("Iterator", sizeof("Iterator") - 1, 1);
+       zend_type_list *property_classUnionProp_type_list = malloc(ZEND_TYPE_LIST_SIZE(2));
+       property_classUnionProp_type_list->num_types = 2;
+       property_classUnionProp_type_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(property_classUnionProp_class_stdClass, 0, 0);
+       property_classUnionProp_type_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(property_classUnionProp_class_Iterator, 0, 0);
+       zend_type property_classUnionProp_type = ZEND_TYPE_INIT_PTR(property_classUnionProp_type_list, _ZEND_TYPE_LIST_BIT, 0, MAY_BE_NULL);
+       zval property_classUnionProp_default_value;
+       ZVAL_NULL(&property_classUnionProp_default_value);
+       zend_string *property_classUnionProp_name = zend_string_init("classUnionProp", sizeof("classUnionProp") - 1, 1);
+       zend_declare_typed_property(class_entry, property_classUnionProp_name, &property_classUnionProp_default_value, ZEND_ACC_PUBLIC, NULL, property_classUnionProp_type);
+       zend_string_release(property_classUnionProp_name);
+
        return class_entry;
 }