Skip to content

Add return types to internal methods #6548

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -4003,7 +4003,7 @@ uint32_t zend_get_return_info_from_signature_only(
const zend_function *func, const zend_script *script,
zend_class_entry **ce, bool *ce_is_instanceof) {
uint32_t type;
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1)) {
zend_arg_info *ret_info = func->common.arg_info - 1;
type = zend_fetch_arg_info_type(script, ret_info, ce);
*ce_is_instanceof = ce != NULL;
Expand All @@ -4025,15 +4025,16 @@ uint32_t zend_get_return_info_from_signature_only(
ZEND_API void zend_init_func_return_info(
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
{
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_ssa_range tmp_range = {0, 0, 0, 0};
bool is_instanceof = false;
ret->type = zend_get_return_info_from_signature_only(
(zend_function *) op_array, script, &ret->ce, &is_instanceof);
ret->is_instanceof = is_instanceof;
ret->range = tmp_range;
ret->has_range = 0;
}
ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE));
ZEND_ASSERT(!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) op_array)->common.arg_info[-1]));

zend_ssa_range tmp_range = {0, 0, 0, 0};
bool is_instanceof = false;
ret->type = zend_get_return_info_from_signature_only(
(zend_function *) op_array, script, &ret->ce, &is_instanceof);
ret->is_instanceof = is_instanceof;
ret->range = tmp_range;
ret->has_range = 0;
}

void zend_func_return_info(const zend_op_array *op_array,
Expand Down
4 changes: 3 additions & 1 deletion Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,7 +1446,9 @@ ZEND_API int zend_optimize_script(zend_script *script, zend_long optimization_le
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info) {
func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
if ((call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) call_graph.op_arrays[i])->common.arg_info[-1])
) {
zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
}
}
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/bug21478.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Bug #21478 (Zend/zend_alloc.c :: shutdown_memory_manager produces segfault)
--FILE--
<?php
class debugfilter extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
function filter($in, $out, &$consumed, $closing): int {
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = strtoupper($bucket->data);
stream_bucket_append($out, $bucket);
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/bug78406.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (!class_exists(SampleFilter::class)) {
{
private $data = '';

public function filter($in, $out, &$consumed, $closing)
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in))
{
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/enum/json_encode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum StringFoo: string {
enum CustomFoo implements JsonSerializable {
case Bar;

public function jsonSerialize() {
public function jsonSerialize(): mixed {
return 'Custom ' . $this->name;
}
}
Expand Down
24 changes: 20 additions & 4 deletions Zend/tests/foreach_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,26 @@ class IT extends ArrayIterator {
}
}

function rewind() {$this->trap(__FUNCTION__); return parent::rewind();}
function valid() {$this->trap(__FUNCTION__); return parent::valid();}
function key() {$this->trap(__FUNCTION__); return parent::key();}
function next() {$this->trap(__FUNCTION__); return parent::next();}
function rewind(): void
{
$this->trap(__FUNCTION__);
parent::rewind();
}

function valid(): bool {
$this->trap(__FUNCTION__);
return parent::valid();
}

function key(): mixed {
$this->trap(__FUNCTION__);
return parent::key();
}

function next(): void {
$this->trap(__FUNCTION__);
parent::next();
}
}

foreach(['rewind', 'valid', 'key', 'next'] as $trap) {
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/iterator_key_by_ref.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Iterator::key() with by-ref return
--FILE--
<?php
class Test extends ArrayIterator {
function &key() {
function &key(): mixed {
return $foo;
}
}
Expand Down
8 changes: 4 additions & 4 deletions Zend/tests/ns_054.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
namespace test\ns1;

class Foo implements \SplObserver {
function update(\SplSubject $x) {
function update(\SplSubject $x): void {
echo "ok\n";
}
}

class Bar implements \SplSubject {
function attach(\SplObserver $x) {
function attach(\SplObserver $x): void {
echo "ok\n";
}
function notify() {
function notify(): void {
}
function detach(\SplObserver $x) {
function detach(\SplObserver $x): void {
}
}
$foo = new Foo();
Expand Down
8 changes: 4 additions & 4 deletions Zend/tests/ns_056.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ namespace test\ns1;
use \SplObserver;

class Foo implements SplObserver {
function update(\SplSubject $x) {
function update(\SplSubject $x): void {
echo "ok\n";
}
}

class Bar implements \SplSubject {
function attach(SplObserver $x) {
function attach(SplObserver $x): void {
echo "ok\n";
}
function notify() {
function notify(): void {
}
function detach(SplObserver $x) {
function detach(SplObserver $x): void {
}
}
$foo = new Foo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ The default value is a class constant in the parent class method's signature.
<?php
class MyDateTimeZone extends DateTimeZone
{
public static function listIdentifiers()
public static function listIdentifiers(): array
{
}
}
?>
--EXPECTF--
Fatal error: Declaration of MyDateTimeZone::listIdentifiers() must be compatible with DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null) in %s on line %d
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ The default value is a constant in the parent class method's signature.
<?php
class MyDateTimeZone extends DateTimeZone
{
public function getTransitions()
public function getTransitions(): array|false
{
}
}
?>
--EXPECTF--
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
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ The default value is false in the parent class method's signature.

interface MyDateTimeInterface extends DateTimeInterface
{
public function diff();
public function diff(): DateInterval|false;
}
?>
--EXPECTF--
Fatal error: Declaration of MyDateTimeInterface::diff() must be compatible with DateTimeInterface::diff(DateTimeInterface $targetObject, bool $absolute = false) in %s on line %d
Fatal error: Declaration of MyDateTimeInterface::diff(): DateInterval|false must be compatible with DateTimeInterface::diff(DateTimeInterface $targetObject, bool $absolute = false): DateInterval|false in %s on line %d
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ The default value is an integer in the parent class method's signature.
<?php
class MyDateTime extends DateTime
{
public function setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false)
public function setTime(int $hour, int $minute, int $second = 0, bool $microsecond = false): DateTime
{
}
}
?>
--EXPECTF--
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
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ The default value is null in the parent class method's signature.
<?php
class MyDateTime extends DateTime
{
public static function createFromFormat()
public static function createFromFormat(): DateTime|false
{
}
}
?>
--EXPECTF--
Fatal error: Declaration of MyDateTime::createFromFormat() must be compatible with DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null) in %s on line %d
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Test that no notice is emitted when the return type/value of the overriding method is compatible with the tentative return type/value of the overridden method
--FILE--
<?php
class MyDateTimeZone extends DateTimeZone
{
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array
{
return [];
}
}

var_dump(MyDateTimeZone::listIdentifiers());
?>
--EXPECT--
array(0) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Test that a notice is emitted when the return type/value of the overriding method is incompatible with the tentative return type/value of the overridden method
--FILE--
<?php
class MyDateTimeZone extends DateTimeZone
{
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): string
{
return "";
}
}

var_dump(MyDateTimeZone::listIdentifiers());
?>
--EXPECTF--
Deprecated: Declaration of MyDateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): string should be compatible with DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array in %s on line %d
string(0) ""
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ class Test extends DateTime {

?>
--EXPECTF--
Fatal error: Could not check compatibility between Test::createFromFormat($format, $datetime, ?Wrong $timezone = null) and DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null), because class Wrong is not available in %s on line %d
Fatal error: Could not check compatibility between Test::createFromFormat($format, $datetime, ?Wrong $timezone = null) and DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null): DateTime|false, because class Wrong is not available in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Internal class as parent
--FILE--
<?php

class Test extends DateTime {
public static function createFromFormat($format, $datetime, $timezone = null): Wrong { }
}

?>
--EXPECTF--
Fatal error: Could not check compatibility between Test::createFromFormat($format, $datetime, $timezone = null): Wrong and DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null): DateTime|false, because class Wrong is not available in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Test that a notice is emitted when the tentative return type of the overridden method is omitted
--FILE--
<?php
class MyDateTimeZone extends DateTimeZone
{
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null)
{
}
}
?>
--EXPECTF--
Deprecated: Declaration of MyDateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null) should be compatible with DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
Test that the notice can be suppressed when the return type/value of the overriding method is incompatible with the tentative return type/value of the overridden method
--FILE--
<?php

class MyDateTime extends DateTime
{
/**
* @return DateTime|false
*/
#[ReturnTypeWillChange]
public function modify(string $modifier) {
return false;
}
}

$date = new MyDateTime("2021-01-01 00:00:00");
var_dump($date->modify("+1 sec"));
?>
--EXPECT--
bool(false)
Loading