Skip to content

Commit

Permalink
fix checking covariant on override static with self & add tests for o…
Browse files Browse the repository at this point in the history
…verriding static with self in non-final classes
  • Loading branch information
rekmixa committed Feb 6, 2025
1 parent 4ec78c1 commit 27f8e02
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Overriding static return types with self in non-final class with abstract class
--FILE--
<?php

abstract class B
{
abstract public function method2(): static;
}

class Foo extends B
{
public function method2(): self
{
return $this;
}
}

$foo = new Foo();

var_dump($foo->method2());
?>
--EXPECT--
Fatal error: Declaration of Foo::method2(): Foo must be compatible with B::method2(): static in /app/Zend/tests/type_declarations/override_static_type_with_self_in_non_final_class_with_abstract_class.php on line 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Overriding static return types with self in non-final class with interface
--FILE--
<?php

interface A
{
public function method1(): static;
}

class Foo implements A
{
public function method1(): self
{
return $this;
}
}

$foo = new Foo();

var_dump($foo->method1());
?>
--EXPECT--
Fatal error: Declaration of Foo::method1(): Foo must be compatible with A::method1(): static in /app/Zend/tests/type_declarations/override_static_type_with_self_in_non_final_class_with_interface.php on line 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Overriding static return types with self in non-final class with trait
--FILE--
<?php

trait C
{
abstract public function method3(): static;
}

class Foo
{
use C;

public function method3(): self
{
return $this;
}
}

$foo = new Foo();

var_dump($foo->method3());
?>
--EXPECT--
Fatal error: Declaration of Foo::method3(): Foo must be compatible with C::method3(): static in /app/Zend/tests/type_declarations/override_static_type_with_self_in_non_final_class_with_trait.php on line 12
15 changes: 8 additions & 7 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,20 +677,21 @@ ZEND_API inheritance_status zend_perform_covariant_type_check(
uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
uint32_t added_types = fe_type_mask & ~proto_type_mask;

if (proto_type_mask & MAY_BE_STATIC && fe_type_mask | MAY_BE_STATIC &&
fe_scope->ce_flags & ZEND_ACC_FINAL &&
instanceof_function(fe_scope, proto_scope)) {
/* Replacing type that accepts static with self in final classes is okay */
return INHERITANCE_SUCCESS;
}

if (added_types) {
if ((added_types & MAY_BE_STATIC)
&& zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
/* Replacing type that accepts self with static is okay */
added_types &= ~MAY_BE_STATIC;
}

if (proto_type_mask & MAY_BE_STATIC && fe_type_mask | MAY_BE_STATIC &&
fe_scope->ce_flags & ZEND_ACC_FINAL &&
zend_is_intersection_subtype_of_type(fe_scope, fe_type, proto_scope, proto_type) == INHERITANCE_SUCCESS) {
/* Replacing type that accepts static with self in final classes is okay */
return INHERITANCE_SUCCESS
}

if (added_types == MAY_BE_NEVER) {
/* never is the bottom type */
return INHERITANCE_SUCCESS;
Expand Down

0 comments on commit 27f8e02

Please sign in to comment.