Skip to content

Commit 01af74c

Browse files
committed
Delay LSP warnings until runtime
1 parent 44e3a32 commit 01af74c

File tree

3 files changed

+43
-38
lines changed

3 files changed

+43
-38
lines changed

Zend/tests/type_declarations/variance/parent_in_class.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ class B4 extends A4 {
4040

4141
?>
4242
--EXPECTF--
43-
Warning: Declaration of B4::method(A4 $x) should be compatible with A4::method(P4 $x) in %s on line 35
44-
4543
Warning: Declaration of B::method(A $x) should be compatible with A::method(parent $x) in %s on line 8
44+
45+
Warning: Declaration of B4::method(A4 $x) should be compatible with A4::method(P4 $x) in %s on line 35

Zend/tests/type_declarations/variance/runtime_fail.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ class B extends A {
1616
}
1717

1818
?>
19-
--EXPECT--
20-
Should fail.
19+
--EXPECTF--
20+
Fatal error: Declaration of B::method(): Y must be compatible with A::method(): X in %s on line 12

Zend/zend_inheritance.c

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,6 @@ static inheritance_status zend_do_perform_implementation_check(
478478
}
479479
}
480480

481-
/*
482-
if (status == INHERITANCE_UNRESOLVED && CG(unverified_types)) {
483-
zend_string *key = zend_string_tolower(fe->common.scope->name);
484-
zend_hash_add_empty_element(CG(unverified_types), key);
485-
zend_string_release(key);
486-
}
487-
*/
488-
489481
return status;
490482
}
491483
/* }}} */
@@ -651,6 +643,21 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function
651643
}
652644
/* }}} */
653645

646+
static zend_bool lsp_fail_is_error(zend_function *child, zend_function *parent) {
647+
/* Failed verification against abstract method, error. */
648+
if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
649+
return 1;
650+
}
651+
/* Failed return type verification, error. */
652+
if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
653+
!check_inherited_return_type(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1)) {
654+
return 1;
655+
}
656+
657+
/* Legacy: Parameter verification failures against non-abstract methods are only warnings. */
658+
return 0;
659+
}
660+
654661
static zend_always_inline uint32_t func_lineno(zend_function *fn) {
655662
return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
656663
}
@@ -737,31 +744,31 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
737744
ZEND_FN_SCOPE_NAME(child), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
738745
}
739746

740-
if (UNEXPECTED(zend_do_perform_implementation_check(child, parent)) == INHERITANCE_ERROR) {
741-
int error_level;
742-
const char *error_verb;
743-
zend_string *method_prototype = zend_get_function_declaration(parent);
744-
zend_string *child_prototype = zend_get_function_declaration(child);
745-
746-
if (child->common.prototype && (
747-
child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT
748-
)) {
749-
error_level = E_COMPILE_ERROR;
750-
error_verb = "must";
751-
} else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
752-
!check_inherited_return_type(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1)) {
753-
error_level = E_COMPILE_ERROR;
754-
error_verb = "must";
747+
inheritance_status status = zend_do_perform_implementation_check(child, parent);
748+
if (UNEXPECTED(status == INHERITANCE_ERROR)) {
749+
if (lsp_fail_is_error(child, parent)) {
750+
zend_string *method_prototype = zend_get_function_declaration(parent);
751+
zend_string *child_prototype = zend_get_function_declaration(child);
752+
zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
753+
"Declaration of %s must be compatible with %s",
754+
ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype));
755+
zend_string_efree(child_prototype);
756+
zend_string_efree(method_prototype);
755757
} else {
756-
error_level = E_WARNING;
757-
error_verb = "should";
758+
/* Delay this warning until runtime, to avoid duplicate warnings. */
759+
status = INHERITANCE_UNRESOLVED;
758760
}
759-
zend_error_at(error_level, NULL, func_lineno(child),
760-
"Declaration of %s %s be compatible with %s",
761-
ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype));
762-
zend_string_efree(child_prototype);
763-
zend_string_efree(method_prototype);
764761
}
762+
763+
/* TODO Properly handle UNRESOLVED. */
764+
765+
/*
766+
if (status == INHERITANCE_UNRESOLVED && CG(unverified_types)) {
767+
zend_string *key = zend_string_tolower(fe->common.scope->name);
768+
zend_hash_add_empty_element(CG(unverified_types), key);
769+
zend_string_release(key);
770+
}
771+
*/
765772
}
766773
} while (0);
767774
}
@@ -2256,9 +2263,7 @@ ZEND_API void zend_verify_variance(zend_class_entry *ce)
22562263
inheritance_status status = check_inherited_return_type(
22572264
child, &child->common.arg_info[-1],
22582265
parent, &parent->common.arg_info[-1]);
2259-
/* TODO I don't think this is right -- what if the class now exists
2260-
* but has wrong variance? */
2261-
if (status == INHERITANCE_UNRESOLVED) {
2266+
if (status != INHERITANCE_SUCCESS) {
22622267
inheritance_runtime_error_msg(child, parent);
22632268
continue;
22642269
}
@@ -2295,7 +2300,7 @@ ZEND_API void zend_verify_variance(zend_class_entry *ce)
22952300
inheritance_status status = check_inherited_parameter_type(
22962301
child, child_arg_info,
22972302
parent, parent_arg_info);
2298-
if (status == INHERITANCE_UNRESOLVED) {
2303+
if (status != INHERITANCE_SUCCESS) {
22992304
inheritance_runtime_error_msg(child, parent);
23002305
continue;
23012306
}

0 commit comments

Comments
 (0)