summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_API.h4
-rw-r--r--Zend/zend_closures.stub.php7
-rw-r--r--Zend/zend_types.h6
-rw-r--r--ext/date/php_date.c4
-rw-r--r--ext/date/php_date.stub.php26
-rw-r--r--ext/date/php_date_arginfo.h46
-rwxr-xr-xscripts/dev/gen_stub.php76
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 {