Skip to content

Commit 802394b

Browse files
committed
Fix an additional variance bug
1 parent f49e9fd commit 802394b

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Replacing union type by intersection type
3+
--FILE--
4+
<?php
5+
6+
interface X {}
7+
interface Y {}
8+
interface Z {}
9+
10+
class A {
11+
public function test(): X|Z {}
12+
}
13+
class B extends A {
14+
public function test(): X&Y {}
15+
}
16+
17+
?>
18+
===DONE===
19+
--EXPECT--
20+
===DONE===

Zend/zend_inheritance.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ static inheritance_status zend_perform_covariant_type_check(
616616
* as the child can add types, however none of them can be a supertype of
617617
* a parent type. */
618618
if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
619+
bool parent_union_has_unresolved = false;
619620
/* First try to check whether we can succeed without resolving anything */
620621
ZEND_TYPE_FOREACH(proto_type, single_type) {
621622
inheritance_status status;
@@ -637,14 +638,33 @@ static inheritance_status zend_perform_covariant_type_check(
637638
proto_scope, proto_class_name, proto_ce,
638639
fe_scope, fe_type, /* register_unresolved */ false);
639640

640-
if (status == INHERITANCE_ERROR) {
641-
return tentative ? INHERITANCE_WARNING : INHERITANCE_ERROR;
642-
}
643-
if (status != INHERITANCE_SUCCESS) {
644-
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
645-
all_success = false;
641+
/* If the parent is a union type then the intersection type must only be
642+
* a subtype of one of them */
643+
if (ZEND_TYPE_IS_UNION(proto_type)) {
644+
if (status == INHERITANCE_SUCCESS) {
645+
return INHERITANCE_SUCCESS;
646+
}
647+
if (status == INHERITANCE_UNRESOLVED) {
648+
all_success = false;
649+
}
650+
} else {
651+
if (status == INHERITANCE_ERROR) {
652+
return tentative ? INHERITANCE_WARNING : INHERITANCE_ERROR;
653+
}
654+
if (status != INHERITANCE_SUCCESS) {
655+
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
656+
parent_union_has_unresolved = true;
657+
all_success = false;
658+
}
646659
}
647660
} ZEND_TYPE_FOREACH_END();
661+
662+
/* Reaching this means either the child intersection type is a valid/unresolved
663+
* subtype of a parent single/intersection type, either it is an INvalid subtype
664+
* when the parent is a union or it is unresolved, we check which case this is */
665+
if (ZEND_TYPE_IS_UNION(proto_type) && !parent_union_has_unresolved) {
666+
return tentative ? INHERITANCE_WARNING : INHERITANCE_ERROR;
667+
}
648668
} else {
649669
/* First try to check whether we can succeed without resolving anything */
650670
ZEND_TYPE_FOREACH(fe_type, single_type) {

0 commit comments

Comments
 (0)