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)) },
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) {}
}
{ (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)
#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 */
/* 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)
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 {}
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 {}
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 {}
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 {}
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)
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()
#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()
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()
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()
#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)
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
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
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
#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
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
}
}
+ public function toEscapedName(): string {
+ return str_replace('\\', '\\\\', $this->name);
+ }
+
public function equals(SimpleType $other) {
return $this->name === $other->name
&& $this->isBuiltin === $other->isBuiltin;
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();
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 {
}
}
+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;
$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",
$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');
}
$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 {