Skip to content

Commit 27f8e02

Browse files
committed
fix checking covariant on override static with self & add tests for overriding static with self in non-final classes
1 parent 4ec78c1 commit 27f8e02

4 files changed

+82
-7
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Overriding static return types with self in non-final class with abstract class
3+
--FILE--
4+
<?php
5+
6+
abstract class B
7+
{
8+
abstract public function method2(): static;
9+
}
10+
11+
class Foo extends B
12+
{
13+
public function method2(): self
14+
{
15+
return $this;
16+
}
17+
}
18+
19+
$foo = new Foo();
20+
21+
var_dump($foo->method2());
22+
?>
23+
--EXPECT--
24+
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
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Overriding static return types with self in non-final class with interface
3+
--FILE--
4+
<?php
5+
6+
interface A
7+
{
8+
public function method1(): static;
9+
}
10+
11+
class Foo implements A
12+
{
13+
public function method1(): self
14+
{
15+
return $this;
16+
}
17+
}
18+
19+
$foo = new Foo();
20+
21+
var_dump($foo->method1());
22+
?>
23+
--EXPECT--
24+
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
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Overriding static return types with self in non-final class with trait
3+
--FILE--
4+
<?php
5+
6+
trait C
7+
{
8+
abstract public function method3(): static;
9+
}
10+
11+
class Foo
12+
{
13+
use C;
14+
15+
public function method3(): self
16+
{
17+
return $this;
18+
}
19+
}
20+
21+
$foo = new Foo();
22+
23+
var_dump($foo->method3());
24+
?>
25+
--EXPECT--
26+
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

Zend/zend_inheritance.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -677,20 +677,21 @@ ZEND_API inheritance_status zend_perform_covariant_type_check(
677677
uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
678678
uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
679679
uint32_t added_types = fe_type_mask & ~proto_type_mask;
680+
681+
if (proto_type_mask & MAY_BE_STATIC && fe_type_mask | MAY_BE_STATIC &&
682+
fe_scope->ce_flags & ZEND_ACC_FINAL &&
683+
instanceof_function(fe_scope, proto_scope)) {
684+
/* Replacing type that accepts static with self in final classes is okay */
685+
return INHERITANCE_SUCCESS;
686+
}
687+
680688
if (added_types) {
681689
if ((added_types & MAY_BE_STATIC)
682690
&& zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
683691
/* Replacing type that accepts self with static is okay */
684692
added_types &= ~MAY_BE_STATIC;
685693
}
686694

687-
if (proto_type_mask & MAY_BE_STATIC && fe_type_mask | MAY_BE_STATIC &&
688-
fe_scope->ce_flags & ZEND_ACC_FINAL &&
689-
zend_is_intersection_subtype_of_type(fe_scope, fe_type, proto_scope, proto_type) == INHERITANCE_SUCCESS) {
690-
/* Replacing type that accepts static with self in final classes is okay */
691-
return INHERITANCE_SUCCESS
692-
}
693-
694695
if (added_types == MAY_BE_NEVER) {
695696
/* never is the bottom type */
696697
return INHERITANCE_SUCCESS;

0 commit comments

Comments
 (0)