diff options
-rw-r--r-- | Zend/zend_API.h | 4 | ||||
-rw-r--r-- | Zend/zend_closures.stub.php | 7 | ||||
-rw-r--r-- | Zend/zend_types.h | 6 | ||||
-rw-r--r-- | ext/date/php_date.c | 4 | ||||
-rw-r--r-- | ext/date/php_date.stub.php | 26 | ||||
-rw-r--r-- | ext/date/php_date_arginfo.h | 46 | ||||
-rwxr-xr-x | scripts/dev/gen_stub.php | 76 |
7 files changed, 112 insertions, 57 deletions
diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 85c2d495a6..7f33d61f0c 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -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)) }, diff --git a/Zend/zend_closures.stub.php b/Zend/zend_closures.stub.php index cc859b2b10..ad15daa526 100644 --- a/Zend/zend_closures.stub.php +++ b/Zend/zend_closures.stub.php @@ -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) {} } diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 4bfe335e0a..3ff94eb574 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -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 */ diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 59f5a5077f..7dcc212e21 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -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) diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index b76f0bd1df..17d9a848f0 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -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 {} diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index 15c4bd203d..183e3e0d30 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -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 diff --git a/scripts/dev/gen_stub.php b/scripts/dev/gen_stub.php index a02e23b256..c6f9557fb4 100755 --- a/scripts/dev/gen_stub.php +++ b/scripts/dev/gen_stub.php @@ -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 { |