diff --git a/src/Psalm/Internal/Analyzer/MethodComparator.php b/src/Psalm/Internal/Analyzer/MethodComparator.php index 16ff2d9d98b..480d0ecedec 100644 --- a/src/Psalm/Internal/Analyzer/MethodComparator.php +++ b/src/Psalm/Internal/Analyzer/MethodComparator.php @@ -27,6 +27,7 @@ use Psalm\Issue\ParamNameMismatch; use Psalm\Issue\TraitMethodSignatureMismatch; use Psalm\IssueBuffer; +use Psalm\Storage\AttributeStorage; use Psalm\Storage\ClassLikeStorage; use Psalm\Storage\FunctionLikeParameter; use Psalm\Storage\MethodStorage; @@ -35,6 +36,7 @@ use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; +use function array_filter; use function in_array; use function strpos; use function strtolower; @@ -113,6 +115,27 @@ public static function compare( ); } + if (!$guide_classlike_storage->user_defined + && $implementer_classlike_storage->user_defined + && $codebase->analysis_php_version_id >= 8_01_00 + && ($guide_method_storage->return_type + || $guide_method_storage->signature_return_type + ) + && !$implementer_method_storage->signature_return_type + && !array_filter( + $implementer_method_storage->attributes, + fn (AttributeStorage $s) => $s->fq_class_name === 'ReturnTypeWillChange' + ) + ) { + IssueBuffer::maybeAdd( + new MethodSignatureMismatch( + 'Method ' . $cased_implementer_method_id . ' is missing a return type signature!', + $implementer_method_storage->location ?: $code_location + ), + $suppressed_issues + $implementer_classlike_storage->suppressed_issues + ); + } + if ($guide_method_storage->return_type && $implementer_method_storage->return_type && !$implementer_method_storage->inherited_return_type @@ -862,7 +885,11 @@ private static function compareMethodSignatureReturnTypes( $implementer_signature_return_type, $guide_signature_return_type ) - : UnionTypeComparator::isContainedByInPhp($implementer_signature_return_type, $guide_signature_return_type); + : (!$implementer_signature_return_type + && $guide_signature_return_type->isMixed() + ? false + : UnionTypeComparator::isContainedByInPhp($implementer_signature_return_type, $guide_signature_return_type) + ); if (!$is_contained_by) { if ($codebase->php_major_version >= 8 diff --git a/tests/MethodSignatureTest.php b/tests/MethodSignatureTest.php index 11f217b172f..9862b94633e 100644 --- a/tests/MethodSignatureTest.php +++ b/tests/MethodSignatureTest.php @@ -1569,6 +1569,37 @@ public function bar(string ...$_args): void {} ', 'error_message' => 'MethodSignatureMismatch', ], + 'noMixedTypehintInDescendant' => [ + ' 'MethodSignatureMismatch', + [], + false, + '8.0' + ], + 'noTypehintInNativeDescendant' => [ + ' 'MethodSignatureMismatch', + [], + false, + '8.1' + ], ]; } }