From e9d65160e85fb08d9bd08202b60a8b19b446c646 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 6 Apr 2016 17:17:10 +0300 Subject: [PATCH] Fixed bug #71978 (Existence of return type hint affects other compatibility rules) --- NEWS | 2 ++ Zend/tests/return_types/bug71978.phpt | 21 +++++++++++++++ Zend/zend_inheritance.c | 38 ++++++++++++++++++--------- 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 Zend/tests/return_types/bug71978.phpt diff --git a/NEWS b/NEWS index 24da274e03..56e81c9d92 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ PHP NEWS ?? ??? 2016 PHP 7.0.6 - Core: + . Fixed bug #71978 (Existence of return type hint affects other compatibility + rules). (Dmitry) . Fixed bug #71930 (_zval_dtor_func: Assertion `(arr)->gc.refcount <= 1' failed). (Laruence) . Fixed bug #71922 (Crash on assert(new class{})). (Nikita) diff --git a/Zend/tests/return_types/bug71978.phpt b/Zend/tests/return_types/bug71978.phpt new file mode 100644 index 0000000000..e3c8440212 --- /dev/null +++ b/Zend/tests/return_types/bug71978.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #71978 (Existence of return type hint affects other compatibility rules) +--FILE-- + +--EXPECTF-- +Warning: Declaration of B::foo(string $a) should be compatible with A::foo(int $a) in %s on line %d + +Warning: Declaration of B1::foo(string $a): int should be compatible with A1::foo(int $a): int in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 55a9fdc909..e6721879ee 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -243,11 +243,6 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf return 0; } - if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) { - /* incompatible nullability */ - return 0; - } - return 1; } /* }}} */ @@ -324,6 +319,11 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c return 0; } + if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) { + /* incompatible nullability */ + return 0; + } + /* by-ref constraints on arguments are invariant */ if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) { return 0; @@ -570,17 +570,31 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * } if (child->common.prototype && ( - child->common.prototype->common.fn_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_HAS_RETURN_TYPE) + child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT )) { - if (UNEXPECTED(!zend_do_perform_implementation_check(child, child->common.prototype))) { - zend_string *method_prototype = zend_get_function_declaration(child->common.prototype); - zend_string *child_prototype = zend_get_function_declaration(child); - zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype)); + parent = child->common.prototype; + } + if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { + int error_level; + const char *error_verb; + + if (child->common.prototype && ( + child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT + )) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && + (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1))) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else { + error_level = E_WARNING; + error_verb = "should"; } - } else if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { zend_string *method_prototype = zend_get_function_declaration(parent); zend_string *child_prototype = zend_get_function_declaration(child); - zend_error(E_WARNING, "Declaration of %s should be compatible with %s", ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype)); + zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype)); zend_string_free(child_prototype); zend_string_free(method_prototype); } -- 2.50.1