Fix self inheritance type checks for traits

Fixes GH-18295
Closes GH-18296
This commit is contained in:
Ilija Tovilo 2025-04-10 16:36:32 +02:00
parent c97bdce962
commit 03d2226f45
No known key found for this signature in database
GPG key ID: 5050C66BFCD1015A
9 changed files with 40 additions and 12 deletions

View file

@ -19,4 +19,4 @@ class B extends Foo
} }
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Declaration of T::bar() must be compatible with Foo::bar($a = 'Foo') in %s on line %d Fatal error: Declaration of B::bar() must be compatible with Foo::bar($a = 'Foo') in %s on line %d

View file

@ -25,4 +25,4 @@ B::createApp();
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Cannot make non static method A::createApp() static in class C in %s on line %d Fatal error: Cannot make non static method A::createApp() static in class B in %s on line %d

View file

@ -17,4 +17,4 @@ class B extends A {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Declaration of T::foo(): string must be compatible with A::foo(): int in %sbug81192_trait.inc on line 4 Fatal error: Declaration of B::foo(): string must be compatible with A::foo(): int in %sbug81192_trait.inc on line 4

View file

@ -22,4 +22,4 @@ class TraitsTest1 {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d Fatal error: Declaration of TraitsTest1::hello() must be compatible with THelloA::hello($a) in %s on line %d

View file

@ -23,4 +23,4 @@ class TraitsTest1 {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d Fatal error: Declaration of TraitsTest1::hello() must be compatible with THelloA::hello($a) in %s on line %d

View file

@ -0,0 +1,21 @@
--TEST--
GH-18295: Parent self is substitutable with child self through trait
--FILE--
<?php
class A {
public function create(): ?A {}
}
trait T {
public function create(): self {}
}
class B extends A {
use T;
}
?>
===DONE===
--EXPECT--
===DONE===

View file

@ -35,4 +35,4 @@ $o->sayHello(array());
--EXPECTF-- --EXPECTF--
World! World!
Fatal error: Declaration of SayWorld::sayHello(Base $d) must be compatible with Base::sayHello(array $a) in %s on line %d Fatal error: Declaration of MyHelloWorld::sayHello(Base $d) must be compatible with Base::sayHello(array $a) in %s on line %d

View file

@ -17,4 +17,4 @@ class U extends X {
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Could not check compatibility between T::method($r): B and X::method($a): A, because class B is not available in %s on line %d Fatal error: Could not check compatibility between U::method($r): B and X::method($a): A, because class B is not available in %s on line %d

View file

@ -3608,6 +3608,11 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods); zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
zend_do_traits_constant_binding(ce, traits_and_interfaces); zend_do_traits_constant_binding(ce, traits_and_interfaces);
zend_do_traits_property_binding(ce, traits_and_interfaces); zend_do_traits_property_binding(ce, traits_and_interfaces);
zend_function *fn;
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
zend_fixup_trait_method(fn, ce);
} ZEND_HASH_FOREACH_END();
} }
if (parent) { if (parent) {
if (!(parent->ce_flags & ZEND_ACC_LINKED)) { if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
@ -3618,6 +3623,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
if (ce->num_traits) { if (ce->num_traits) {
if (trait_contains_abstract_methods) { if (trait_contains_abstract_methods) {
zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, true, &trait_contains_abstract_methods); zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, true, &trait_contains_abstract_methods);
/* New abstract methods may have been added, make sure to add
* ZEND_ACC_IMPLICIT_ABSTRACT_CLASS to ce. */
zend_function *fn;
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
zend_fixup_trait_method(fn, ce);
} ZEND_HASH_FOREACH_END();
} }
if (trait_exclude_tables) { if (trait_exclude_tables) {
@ -3634,11 +3646,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
if (trait_aliases) { if (trait_aliases) {
efree(trait_aliases); efree(trait_aliases);
} }
zend_function *fn;
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
zend_fixup_trait_method(fn, ce);
} ZEND_HASH_FOREACH_END();
} }
if (ce->num_interfaces) { if (ce->num_interfaces) {
/* Also copy the parent interfaces here, so we don't need to reallocate later. */ /* Also copy the parent interfaces here, so we don't need to reallocate later. */