When performing an unlinked instanceof, we also need to consider
interfaces of parent classes, as they may not have been inherited
yet.
This commit is contained in:
Nikita Popov 2020-10-06 16:30:58 +02:00
parent c6e7969f05
commit 3b7c8bb973
4 changed files with 61 additions and 12 deletions

1
NEWS
View File

@ -7,6 +7,7 @@ PHP NEWS
(cmb)
. Fixed bug #79423 (copy command is limited to size of file it can copy).
(cmb)
. Fixed bug #80126 (Covariant return types failing compilation). (Nikita)
- MySQLnd:
. Fixed bug #80115 (mysqlnd.debug doesn't recognize absolute paths with

23
Zend/tests/bug80126.phpt Normal file
View File

@ -0,0 +1,23 @@
--TEST--
Bug #80126: Covariant return types failing compilation
--FILE--
<?php
interface I {
public function method(): I;
}
abstract class A implements I {
public function method(): I { }
}
class C extends A { }
class C2 extends C {
public function method(): C2 { }
}
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -0,0 +1,27 @@
--TEST--
Bug #80126: Covariant return types failing compilation (variation 2)
--FILE--
<?php
interface I {
public function method(): I;
}
abstract class A implements I {
public function method(): I {
return new static();
}
}
class C extends A { }
interface I2 { }
class C2 extends C implements I2 {
public function method(): C2 { }
}
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -259,8 +259,6 @@ static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name
/* Instanceof that's safe to use on unlinked classes. */
static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
zend_class_entry *ce;
if (ce1 == ce2) {
return 1;
}
@ -269,18 +267,18 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
return instanceof_function(ce1, ce2);
}
ce = ce1;
while (ce->parent) {
if (ce->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
ce = ce->parent;
if (ce1->parent) {
zend_class_entry *parent_ce;
if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
parent_ce = ce1->parent;
} else {
ce = zend_lookup_class_ex(ce->parent_name, NULL,
parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
if (!ce) {
break;
}
}
if (ce == ce2) {
/* It's not sufficient to only check the parent chain itself, as need to do a full
* recursive instanceof in case the parent interfaces haven't been copied yet. */
if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
return 1;
}
}
@ -297,7 +295,7 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
}
} else {
for (i = 0; i < ce1->num_interfaces; i++) {
ce = zend_lookup_class_ex(
zend_class_entry *ce = zend_lookup_class_ex(
ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
if (ce && unlinked_instanceof(ce, ce2)) {