]> granicus.if.org Git - php/commitdiff
Support single class unions in gen stubs
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 15 Nov 2019 11:50:44 +0000 (12:50 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 15 Nov 2019 16:19:26 +0000 (17:19 +0100)
Zend/zend_API.h
Zend/zend_closures.stub.php
Zend/zend_types.h
ext/date/php_date.c
ext/date/php_date.stub.php
ext/date/php_date_arginfo.h
scripts/dev/gen_stub.php

index 85c2d495a6e7bce7720ab08eaf8860ffbe4094f3..7f33d61f0c2824235af1fec3a28da0571575d342 100644 (file)
@@ -128,6 +128,10 @@ typedef struct _zend_fcall_info_cache {
        static const zend_internal_arg_info name[] = { \
                { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_MASK(type | _ZEND_ARG_INFO_FLAGS(return_reference, 0)) },
 
+#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(name, return_reference, required_num_args, class_name, type) \
+       static const zend_internal_arg_info name[] = { \
+               { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CLASS_CONST_MASK(#class_name, type | _ZEND_ARG_INFO_FLAGS(return_reference, 0)) },
+
 #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
        static const zend_internal_arg_info name[] = { \
                { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(return_reference, 0)) },
index cc859b2b103e1f2515922e9263d659f4eeb8ece8..ad15daa526a6c96a993ca976a077d43ab41bd170 100644 (file)
@@ -12,6 +12,9 @@ Class Closure
 
     function call(object $newthis, ...$parameters) {}
 
-    /** @return Closure */
-    function fromCallable(callable $callable) {}
+    /**
+     * @param callable $callable Not a proper type annotation due to bug #78770
+     * @return Closure
+     */
+    function fromCallable($callable) {}
 }
index 4bfe335e0a667cba2593a779e2c38e8acd9304f2..3ff94eb574c27a6180803dd7a27c7f0635230ee2 100644 (file)
@@ -269,6 +269,9 @@ typedef struct {
        { (void *) (ptr), \
                (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
 
+#define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \
+       { (void *) (ptr), (type_mask) }
+
 #define ZEND_TYPE_INIT_CE(_ce, allow_null, extra_flags) \
        ZEND_TYPE_INIT_PTR(_ce, _ZEND_TYPE_CE_BIT, allow_null, extra_flags)
 
@@ -278,6 +281,9 @@ typedef struct {
 #define ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, extra_flags) \
        ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags)
 
+#define ZEND_TYPE_INIT_CLASS_CONST_MASK(class_name, type_mask) \
+       ZEND_TYPE_INIT_PTR_MASK(class_name, _ZEND_TYPE_NAME_BIT | (type_mask))
+
 typedef union _zend_value {
        zend_long         lval;                         /* long value */
        double            dval;                         /* double value */
index 59f5a5077f2a34b383520cfd61495ea3726dc2f7..7dcc212e210603a948fee34a60a07145d4a9e300 100644 (file)
@@ -93,9 +93,9 @@ static const zend_function_entry date_functions[] = {
 
        /* Advanced Interface */
        PHP_FE(date_create, arginfo_date_create)
-       PHP_FE(date_create_immutable, arginfo_date_create)
+       PHP_FE(date_create_immutable, arginfo_date_create_immutable)
        PHP_FE(date_create_from_format, arginfo_date_create_from_format)
-       PHP_FE(date_create_immutable_from_format, arginfo_date_create_from_format)
+       PHP_FE(date_create_immutable_from_format, arginfo_date_create_immutable_from_format)
        PHP_FE(date_parse, arginfo_date_parse)
        PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
        PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
index b76f0bd1df7ecd7030277af69d4cd609e3823ab2..17d9a848f097c9fd564ef6266cf6317f4d716213 100644 (file)
@@ -31,18 +31,16 @@ function localtime(int $timestamp = UNKNOWN, bool $associative = false): array {
 
 function getdate(int $timestamp = UNKNOWN): array {}
 
-/** @return DateTime|false */
-function date_create(string $time = "now", ?DateTimeZone $timezone = null) {}
+function date_create(string $time = "now", ?DateTimeZone $timezone = null): DateTime|false {}
 
-/** @return DateTime|false */
-function date_create_immutable(string $time = "now", ?DateTimeZone $timezone = null) {}
+function date_create_immutable(
+    string $time = "now", ?DateTimeZone $timezone = null): DateTimeImmutable|false {}
 
-/** @return DateTime|false */
-function date_create_from_format(string $format, string $time, ?DateTimeZone $timezone = null) {}
+function date_create_from_format(
+    string $format, string $time, ?DateTimeZone $timezone = null): DateTime|false {}
 
-/** @return DateTimeImmutable|false */
 function date_create_immutable_from_format(
-    string $format, string $time, ?DateTimeZone $timezone = null) {}
+    string $format, string $time, ?DateTimeZone $timezone = null): DateTimeImmutable|false {}
 
 function date_parse(string $date): array {}
 
@@ -52,15 +50,13 @@ function date_get_last_errors(): array|false {}
 
 function date_format(DateTimeInterface $object, string $format): string {}
 
-/** @return DateTime|false */
-function date_modify(DateTime $object, string $modify) {}
+function date_modify(DateTime $object, string $modify): DateTime|false {}
 
 function date_add(DateTime $object, DateInterval $interval): DateTime {}
 
 function date_sub(DateTime $object, DateInterval $interval): DateTime {}
 
-/** @return DateTimeZone|false */
-function date_timezone_get(DateTimeInterface $object) {}
+function date_timezone_get(DateTimeInterface $object): DateTimeZone|false {}
 
 function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone): DateTime {}
 
@@ -80,8 +76,7 @@ function date_timestamp_set(DateTime $object, int $timestamp): DateTime {}
 
 function date_timestamp_get(DateTimeInterface $object): int|false {}
 
-/** @return DateTimeZone|false */
-function timezone_open(string $timezone) {}
+function timezone_open(string $timezone): DateTimeZone|false {}
 
 function timezone_name_get(DateTimeZone $object): string {}
 
@@ -100,8 +95,7 @@ function timezone_abbreviations_list(): array {}
 
 function timezone_version_get(): string {}
 
-/** @return DateInterval|false */
-function date_interval_create_from_date_string(string $time) {}
+function date_interval_create_from_date_string(string $time): DateInterval|false {}
 
 function date_interval_format(DateInterval $object, string $format): string {}
 
index 15c4bd203d39500cd735ca3a174e8bc7c3fc6a18..183e3e0d30a30fe6ac1d2d2946590399f88ca95e 100644 (file)
@@ -53,20 +53,27 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getdate, 0, 0, IS_ARRAY, 0)
        ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_create, 0, 0, DateTime, MAY_BE_FALSE)
        ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
        ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
 ZEND_END_ARG_INFO()
 
-#define arginfo_date_create_immutable arginfo_date_create
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_create_immutable, 0, 0, DateTimeImmutable, MAY_BE_FALSE)
+       ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
+       ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
+ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_create_from_format, 0, 2, DateTime, MAY_BE_FALSE)
        ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
        ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
 ZEND_END_ARG_INFO()
 
-#define arginfo_date_create_immutable_from_format arginfo_date_create_from_format
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_create_immutable_from_format, 0, 2, DateTimeImmutable, MAY_BE_FALSE)
+       ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
+       ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
+ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_parse, 0, 1, IS_ARRAY, 0)
        ZEND_ARG_TYPE_INFO(0, date, IS_STRING, 0)
@@ -85,7 +92,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_format, 0, 2, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_modify, 0, 2, DateTime, MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
        ZEND_ARG_TYPE_INFO(0, modify, IS_STRING, 0)
 ZEND_END_ARG_INFO()
@@ -97,7 +104,7 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_date_sub arginfo_date_add
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_timezone_get, 0, 1, DateTimeZone, MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
 ZEND_END_ARG_INFO()
 
@@ -147,7 +154,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_date_timestamp_get, 0, 1, MAY_BE
        ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_timezone_open, 0, 1, DateTimeZone, MAY_BE_FALSE)
        ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
@@ -187,7 +194,7 @@ ZEND_END_ARG_INFO()
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_version_get, 0, 0, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_interval_create_from_date_string, 0, 1, DateInterval, MAY_BE_FALSE)
        ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
@@ -237,7 +244,10 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_DateTimeInterface___wakeup arginfo_class_DateTimeInterface_getTimezone
 
-#define arginfo_class_DateTime___construct arginfo_date_create
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime___construct, 0, 0, 0)
+       ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
+       ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
+ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime___set_state, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, array, IS_ARRAY, 0)
@@ -247,7 +257,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime_createFromImmutable, 0, 0, 1)
        ZEND_ARG_OBJ_INFO(0, object, DateTimeImmutable, 0)
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_DateTime_createFromFormat arginfo_date_create_from_format
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime_createFromFormat, 0, 0, 2)
+       ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
+       ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 1)
+ZEND_END_ARG_INFO()
 
 #define arginfo_class_DateTime_getLastErrors arginfo_class_DateTimeInterface_getTimezone
 
@@ -288,7 +302,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime_setTimestamp, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_DateTimeImmutable___construct arginfo_date_create
+#define arginfo_class_DateTimeImmutable___construct arginfo_class_DateTime___construct
 
 #define arginfo_class_DateTimeImmutable___set_state arginfo_class_DateTime___set_state
 
@@ -296,7 +310,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTimeImmutable_createFromMutable, 0, 0,
        ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_DateTimeImmutable_createFromFormat arginfo_date_create_from_format
+#define arginfo_class_DateTimeImmutable_createFromFormat arginfo_class_DateTime_createFromFormat
 
 #define arginfo_class_DateTimeImmutable_getLastErrors arginfo_class_DateTimeInterface_getTimezone
 
@@ -316,7 +330,9 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_DateTimeImmutable_setTimestamp arginfo_class_DateTime_setTimestamp
 
-#define arginfo_class_DateTimeZone___construct arginfo_timezone_open
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTimeZone___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)
+ZEND_END_ARG_INFO()
 
 #define arginfo_class_DateTimeZone_getName arginfo_class_DateTimeInterface_getTimezone
 
@@ -346,7 +362,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateInterval___construct, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, interval_spec, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_DateInterval_createFromDateString arginfo_date_interval_create_from_date_string
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateInterval_createFromDateString, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
+ZEND_END_ARG_INFO()
 
 #define arginfo_class_DateInterval_format arginfo_class_DateTimeInterface_format
 
index a02e23b256f9f79b41031f844cb09bd310aaf4a2..c6f9557fb48b44a5a82cd6fcd2b8b996b33f53dd 100755 (executable)
@@ -131,6 +131,10 @@ class SimpleType {
         }
     }
 
+    public function toEscapedName(): string {
+        return str_replace('\\', '\\\\', $this->name);
+    }
+
     public function equals(SimpleType $other) {
         return $this->name === $other->name
             && $this->isBuiltin === $other->isBuiltin;
@@ -167,15 +171,6 @@ class Type {
         return false;
     }
 
-    public function isBuiltinOnly(): bool {
-        foreach ($this->types as $type) {
-            if (!$type->isBuiltin) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     public function getWithoutNull(): Type {
         return new Type(array_filter($this->types, function(SimpleType $type) {
             return !$type->isNull();
@@ -190,10 +185,20 @@ class Type {
         return null;
     }
 
-    public function toTypeMask(): string {
-        return implode('|', array_map(function(SimpleType $type) {
-            return $type->toTypeMask();
-        }, $this->types));
+    public function tryToRepresentableType(): ?RepresentableType {
+        $classType = null;
+        $builtinTypes = [];
+        foreach ($this->types as $type) {
+            if ($type->isBuiltin) {
+                $builtinTypes[] = $type;
+            } else if ($classType === null) {
+                $classType = $type;
+            } else {
+                // We can only represent a single class type.
+                return false;
+            }
+        }
+        return new RepresentableType($classType, $builtinTypes);
     }
 
     public static function equals(?Type $a, ?Type $b): bool {
@@ -215,6 +220,24 @@ class Type {
     }
 }
 
+class RepresentableType {
+    /** @var ?SimpleType $classType */
+    public $classType;
+    /** @var SimpleType[] $builtinTypes */
+    public $builtinTypes;
+
+    public function __construct(?SimpleType $classType, array $builtinTypes) {
+        $this->classType = $classType;
+        $this->builtinTypes = $builtinTypes;
+    }
+
+    public function toTypeMask(): string {
+        return implode('|', array_map(function(SimpleType $type) {
+            return $type->toTypeMask();
+        }, $this->builtinTypes));
+    }
+}
+
 class ArgInfo {
     const SEND_BY_VAL = 0;
     const SEND_BY_REF = 1;
@@ -467,8 +490,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
     $code = '';
     $returnType = $funcInfo->return->type;
     if ($returnType !== null) {
-        $simpleReturnType = $returnType->tryToSimpleType();
-        if ($simpleReturnType !== null) {
+        if (null !== $simpleReturnType = $returnType->tryToSimpleType()) {
             if ($simpleReturnType->isBuiltin) {
                 $code .= sprintf(
                     "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_%s, %d, %d, %s, %d)\n",
@@ -479,15 +501,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
                 $code .= sprintf(
                     "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_%s, %d, %d, %s, %d)\n",
                     $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs,
-                    str_replace('\\', '\\\\', $simpleReturnType->name), $returnType->isNullable()
+                    $simpleReturnType->toEscapedName(), $returnType->isNullable()
+                );
+            }
+        } else if (null !== $representableType = $returnType->tryToRepresentableType()) {
+            if ($representableType->classType !== null) {
+                $code .= sprintf(
+                    "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_%s, %d, %d, %s, %s)\n",
+                    $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs,
+                    $representableType->classType->toEscapedName(), $representableType->toTypeMask()
+                );
+            } else {
+                $code .= sprintf(
+                    "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_%s, %d, %d, %s)\n",
+                    $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs,
+                    $representableType->toTypeMask()
                 );
             }
-        } else if ($returnType->isBuiltinOnly()) {
-            $code .= sprintf(
-                "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_%s, %d, %d, %s)\n",
-                $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs,
-                $returnType->toTypeMask()
-            );
         } else {
             throw new Exception('Unimplemented');
         }
@@ -514,7 +544,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
                     $code .= sprintf(
                         "\tZEND_%s_OBJ_INFO(%s, %s, %s, %d)\n",
                         $argKind, $argInfo->getSendByString(), $argInfo->name,
-                        str_replace('\\', '\\\\', $simpleArgType->name), $argType->isNullable()
+                        $simpleArgType->toEscapedName(), $argType->isNullable()
                     );
                 }
             } else {