Skip to content

Commit e907b0e

Browse files
committed
Zend: Make Closure covariant to callable
1 parent 4360aa7 commit e907b0e

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

Zend/tests/type_declarations/callable/callable_variance_closure.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ class B extends A {
1010
public function foo(callable $c): Closure {}
1111
}
1212
?>
13-
--EXPECTF--
14-
Fatal error: Declaration of B::foo(callable $c): Closure must be compatible with A::foo(Closure $c): callable in %s on line %d
13+
OK
14+
--EXPECT--
15+
OK

Zend/zend_inheritance.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "zend_execute.h"
2424
#include "zend_inheritance.h"
2525
#include "zend_interfaces.h"
26+
#include "zend_closures.h"
2627
#include "zend_smart_str.h"
2728
#include "zend_operators.h"
2829
#include "zend_exceptions.h"
@@ -478,6 +479,19 @@ static inheritance_status zend_is_class_subtype_of_type(
478479
}
479480
}
480481

482+
/* If the parent has 'callable' as a return type, then Closure satisfies the co-variant check */
483+
if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
484+
if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
485+
if (!fe_ce) {
486+
have_unresolved = 1;
487+
} else if (fe_ce == zend_ce_closure) {
488+
track_class_dependency(fe_ce, fe_class_name);
489+
return INHERITANCE_SUCCESS;
490+
} else {
491+
return INHERITANCE_ERROR;
492+
}
493+
}
494+
481495
zend_type *single_type;
482496

483497
/* Traverse the list of parent types and check if the current child (FE)

0 commit comments

Comments
 (0)