Skip to content

Commit 532c60c

Browse files
committed
Add support for tentative return types of internal methods
RFC: https://wiki.php.net/rfc/internal_method_return_types Closses GH-6971
1 parent 008bfcc commit 532c60c

39 files changed

+668
-291
lines changed

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ PHP 8.1 UPGRADE NOTES
5757
This means that static variables in methods now behave the same way as
5858
static properties.
5959
RFC: https://wiki.php.net/rfc/static_variable_inheritance
60+
. Most non-final internal methods now require overriding methods to declare a
61+
compatible return type, otherwise a deprecated notice is emitted during
62+
inheritance validation.
63+
RFC: https://wiki.php.net/rfc/internal_method_return_types
6064

6165
- Fileinfo:
6266
. The fileinfo functions now accept and return, respectively, finfo objects

Zend/Optimizer/zend_func_info.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ ZEND_API uint32_t zend_get_func_info(
844844
#endif
845845

846846
ret = zend_get_return_info_from_signature_only(
847-
callee_func, /* script */ NULL, ce, ce_is_instanceof);
847+
callee_func, /* script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ !call_info->is_prototype);
848848

849849
#if ZEND_DEBUG
850850
if (internal_ret) {
@@ -884,7 +884,7 @@ ZEND_API uint32_t zend_get_func_info(
884884
}
885885
if (!ret) {
886886
ret = zend_get_return_info_from_signature_only(
887-
callee_func, /* TODO: script */ NULL, ce, ce_is_instanceof);
887+
callee_func, /* TODO: script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ !call_info->is_prototype);
888888
}
889889
}
890890
return ret;

Zend/Optimizer/zend_inference.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4001,9 +4001,11 @@ static int is_recursive_tail_call(const zend_op_array *op_array,
40014001

40024002
uint32_t zend_get_return_info_from_signature_only(
40034003
const zend_function *func, const zend_script *script,
4004-
zend_class_entry **ce, bool *ce_is_instanceof) {
4004+
zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info) {
40054005
uint32_t type;
4006-
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
4006+
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE &&
4007+
(use_tentative_return_info || !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1))
4008+
) {
40074009
zend_arg_info *ret_info = func->common.arg_info - 1;
40084010
type = zend_fetch_arg_info_type(script, ret_info, ce);
40094011
*ce_is_instanceof = ce != NULL;
@@ -4025,15 +4027,15 @@ uint32_t zend_get_return_info_from_signature_only(
40254027
ZEND_API void zend_init_func_return_info(
40264028
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
40274029
{
4028-
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
4029-
zend_ssa_range tmp_range = {0, 0, 0, 0};
4030-
bool is_instanceof = false;
4031-
ret->type = zend_get_return_info_from_signature_only(
4032-
(zend_function *) op_array, script, &ret->ce, &is_instanceof);
4033-
ret->is_instanceof = is_instanceof;
4034-
ret->range = tmp_range;
4035-
ret->has_range = 0;
4036-
}
4030+
ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE));
4031+
4032+
zend_ssa_range tmp_range = {0, 0, 0, 0};
4033+
bool is_instanceof = false;
4034+
ret->type = zend_get_return_info_from_signature_only(
4035+
(zend_function *) op_array, script, &ret->ce, &is_instanceof, /* use_tentative_return_info */ 1);
4036+
ret->is_instanceof = is_instanceof;
4037+
ret->range = tmp_range;
4038+
ret->has_range = 0;
40374039
}
40384040

40394041
void zend_func_return_info(const zend_op_array *op_array,

Zend/Optimizer/zend_inference.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ ZEND_API void zend_init_func_return_info(
271271
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret);
272272
uint32_t zend_get_return_info_from_signature_only(
273273
const zend_function *func, const zend_script *script,
274-
zend_class_entry **ce, bool *ce_is_instanceof);
274+
zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info);
275275
void zend_func_return_info(const zend_op_array *op_array,
276276
const zend_script *script,
277277
int recursive,

Zend/tests/parameter_default_values/internal_declaration_error_class_const.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ The default value is a class constant in the parent class method's signature.
44
<?php
55
class MyDateTimeZone extends DateTimeZone
66
{
7-
public static function listIdentifiers()
7+
public static function listIdentifiers(): array
88
{
99
}
1010
}
1111
?>
1212
--EXPECTF--
13-
Fatal error: Declaration of MyDateTimeZone::listIdentifiers() must be compatible with DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null) in %s on line %d
13+
Fatal error: Declaration of MyDateTimeZone::listIdentifiers(): array must be compatible with DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array in %s on line %d

Zend/tests/parameter_default_values/internal_declaration_error_const.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ The default value is a constant in the parent class method's signature.
44
<?php
55
class MyDateTimeZone extends DateTimeZone
66
{
7-
public function getTransitions()
7+
public function getTransitions(): array|false
88
{
99
}
1010
}
1111
?>
1212
--EXPECTF--
13-
Fatal error: Declaration of MyDateTimeZone::getTransitions() must be compatible with DateTimeZone::getTransitions(int $timestampBegin = PHP_INT_MIN, int $timestampEnd = PHP_INT_MAX) in %s on line %d
13+
Fatal error: Declaration of MyDateTimeZone::getTransitions(): array|false must be compatible with DateTimeZone::getTransitions(int $timestampBegin = PHP_INT_MIN, int $timestampEnd = PHP_INT_MAX): array|false in %s on line %d

Zend/tests/parameter_default_values/internal_declaration_error_false.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ The default value is false in the parent class method's signature.
55

66
interface MyDateTimeInterface extends DateTimeInterface
77
{
8-
public function diff();
8+
public function diff(): DateInterval;
99
}
1010
?>
1111
--EXPECTF--
12-
Fatal error: Declaration of MyDateTimeInterface::diff() must be compatible with DateTimeInterface::diff(DateTimeInterface $targetObject, bool $absolute = false) in %s on line %d
12+
Fatal error: Declaration of MyDateTimeInterface::diff(): DateInterval must be compatible with DateTimeInterface::diff(DateTimeInterface $targetObject, bool $absolute = false): DateInterval in %s on line %d

Zend/tests/parameter_default_values/internal_declaration_error_int.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ The default value is an integer in the parent class method's signature.
44
<?php
55
class MyDateTime extends DateTime
66
{
7-
public function setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false)
7+
public function setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false): DateTime
88
{
99
}
1010
}
1111
?>
1212
--EXPECTF--
13-
Fatal error: Declaration of MyDateTime::setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false) must be compatible with DateTime::setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0) in %s on line %d
13+
Fatal error: Declaration of MyDateTime::setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false): DateTime must be compatible with DateTime::setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): DateTime in %s on line %d

Zend/tests/parameter_default_values/internal_declaration_error_null.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ The default value is null in the parent class method's signature.
44
<?php
55
class MyDateTime extends DateTime
66
{
7-
public static function createFromFormat()
7+
public static function createFromFormat(): DateTime|false
88
{
99
}
1010
}
1111
?>
1212
--EXPECTF--
13-
Fatal error: Declaration of MyDateTime::createFromFormat() must be compatible with DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null) in %s on line %d
13+
Fatal error: Declaration of MyDateTime::createFromFormat(): DateTime|false must be compatible with DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null): DateTime|false in %s on line %d

Zend/tests/type_declarations/variance/internal_parent.phpt

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)