Skip to content

Commit 05723db

Browse files
committed
Fix an additional variance bug
1 parent 9e9de43 commit 05723db

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
@@ -628,6 +628,7 @@ static inheritance_status zend_perform_covariant_type_check(
628628
* as the child can add types, however none of them can be a supertype of
629629
* a parent type. */
630630
if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
631+
bool parent_union_has_unresolved = false;
631632
/* First try to check whether we can succeed without resolving anything */
632633
ZEND_TYPE_FOREACH(proto_type, single_type) {
633634
inheritance_status status;
@@ -649,14 +650,33 @@ static inheritance_status zend_perform_covariant_type_check(
649650
proto_scope, proto_class_name, proto_ce,
650651
fe_scope, fe_type, /* register_unresolved */ false);
651652

652-
if (status == INHERITANCE_ERROR) {
653-
return NHERITANCE_ERROR;
654-
}
655-
if (status != INHERITANCE_SUCCESS) {
656-
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
657-
all_success = false;
653+
/* If the parent is a union type then the intersection type must only be
654+
* a subtype of one of them */
655+
if (ZEND_TYPE_IS_UNION(proto_type)) {
656+
if (status == INHERITANCE_SUCCESS) {
657+
return INHERITANCE_SUCCESS;
658+
}
659+
if (status == INHERITANCE_UNRESOLVED) {
660+
all_success = false;
661+
}
662+
} else {
663+
if (status == INHERITANCE_ERROR) {
664+
return INHERITANCE_ERROR;
665+
}
666+
if (status != INHERITANCE_SUCCESS) {
667+
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
668+
parent_union_has_unresolved = true;
669+
all_success = false;
670+
}
658671
}
659672
} ZEND_TYPE_FOREACH_END();
673+
674+
/* Reaching this means either the child intersection type is a valid/unresolved
675+
* subtype of a parent single/intersection type, either it is an INvalid subtype
676+
* when the parent is a union or it is unresolved, we check which case this is */
677+
if (ZEND_TYPE_IS_UNION(proto_type) && !parent_union_has_unresolved) {
678+
return tentative ? INHERITANCE_WARNING : INHERITANCE_ERROR;
679+
}
660680
} else {
661681
/* First try to check whether we can succeed without resolving anything */
662682
ZEND_TYPE_FOREACH(fe_type, single_type) {

0 commit comments

Comments
 (0)