summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/return_types/bug71978.phpt21
-rw-r--r--Zend/zend_inheritance.c38
2 files changed, 47 insertions, 12 deletions
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--
+<?php
+class A {
+ function foo(int $a) {}
+}
+class B extends A {
+ function foo(string $a) {}
+}
+class A1 {
+ function foo(int $a): int {}
+}
+class B1 extends A1 {
+ function foo(string $a): int {}
+}
+?>
+--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 1243552d59..c4dbc879e8 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);
}