mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Covariance on inheriting classes with iterable
This commit is contained in:
parent
bea9df5281
commit
4da3e77b4c
2 changed files with 40 additions and 8 deletions
|
@ -1253,17 +1253,20 @@ static void zend_mark_function_as_generator() /* {{{ */
|
|||
}
|
||||
|
||||
if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
|
||||
const char *msg = "Generators may only declare a return type of Generator, Iterator or Traversable, %s is not permitted";
|
||||
zend_arg_info return_info = CG(active_op_array)->arg_info[-1];
|
||||
|
||||
if (!return_info.class_name) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, msg, zend_get_type_by_const(return_info.type_hint));
|
||||
}
|
||||
if (return_info.type_hint != IS_ITERABLE) {
|
||||
const char *msg = "Generators may only declare a return type of Generator, Iterator, Traversable, or iterable, %s is not permitted";
|
||||
|
||||
if (!return_info.class_name) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, msg, zend_get_type_by_const(return_info.type_hint));
|
||||
}
|
||||
|
||||
if (!zend_string_equals_literal_ci(return_info.class_name, "Traversable")
|
||||
&& !zend_string_equals_literal_ci(return_info.class_name, "Iterator")
|
||||
&& !zend_string_equals_literal_ci(return_info.class_name, "Generator")) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, msg, ZSTR_VAL(return_info.class_name));
|
||||
if (!zend_string_equals_literal_ci(return_info.class_name, "Traversable")
|
||||
&& !zend_string_equals_literal_ci(return_info.class_name, "Iterator")
|
||||
&& !zend_string_equals_literal_ci(return_info.class_name, "Generator")) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, msg, ZSTR_VAL(return_info.class_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "zend_compile.h"
|
||||
#include "zend_execute.h"
|
||||
#include "zend_inheritance.h"
|
||||
#include "zend_interfaces.h"
|
||||
#include "zend_smart_str.h"
|
||||
#include "zend_inheritance.h"
|
||||
|
||||
|
@ -167,6 +168,26 @@ char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_bool zend_iterable_type_check(zend_arg_info *arg_info) /* {{{ */
|
||||
{
|
||||
if (arg_info->class_name) {
|
||||
zend_class_entry *ce;
|
||||
|
||||
ce = zend_lookup_class(arg_info->class_name);
|
||||
|
||||
if (ce && instanceof_function(ce, zend_ce_traversable)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_info->type_hint == IS_ITERABLE || arg_info->type_hint == IS_ARRAY) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */
|
||||
{
|
||||
if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
|
||||
|
@ -314,6 +335,10 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
|
|||
} else {
|
||||
proto_arg_info = &proto->common.arg_info[proto->common.num_args];
|
||||
}
|
||||
|
||||
if (fe_arg_info->type_hint == IS_ITERABLE && zend_iterable_type_check(proto_arg_info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) {
|
||||
return 0;
|
||||
|
@ -338,6 +363,10 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
|
|||
if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (proto->common.arg_info[-1].type_hint == IS_ITERABLE && zend_iterable_type_check(fe->common.arg_info - 1)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) {
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue