Mark return.type, return.empty, return.void, and return.never errors as non-ignorable when native return type is violated#5628
Open
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
Conversation
… errors as non-ignorable when native return type is violated - Add optional `?Type $nativeReturnType` parameter to `FunctionReturnTypeCheck::checkReturnType()` - When the native return type is provided and the return value violates it, call `->nonIgnorable()` on the error builder - For non-strict mode, allow scalar-to-scalar coercion to remain ignorable (int→string etc. don't cause TypeErrors at runtime) - Pass native return type from `Methods\ReturnTypeRule`, `Functions\ReturnTypeRule`, `Functions\ClosureReturnTypeRule`, and `Functions\ArrowFunctionReturnTypeRule` - Fix pre-existing native type violation in `ResolvedPhpDocBlock::getNameScope()` (now correctly caught as non-ignorable) - Remove corresponding baseline entry that was suppressing the violation
aaa96d4 to
67cfcda
Compare
ondrejmirtes
requested changes
May 10, 2026
| $returnValueType->describe($verbosityLevel), | ||
| )) | ||
| ->line($returnNode->getStartLine()) | ||
| ->identifier('return.type') |
Member
There was a problem hiding this comment.
I disagree about making return.type non-ignorable, it's too squishy and dependent on surrounding code. I still want people to be able to ignore this (for now).
Collaborator
Author
There was a problem hiding this comment.
Done. Removed the non-ignorable marking for return.type errors per the reviewer's request. The other three identifiers (return.empty, return.void, return.never) still become non-ignorable when the native return type is violated. All tests pass and make phpstan reports no errors.
…iolated Only `return.empty`, `return.void`, and `return.never` are marked non-ignorable when the native return type is violated. `return.type` remains ignorable as requested in review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a function/method has a native return type declaration (e.g.,
function foo(): array) and the code returns a value that violates that native type (e.g.,return null), this causes a runtime TypeError. Such errors should not be ignorable via baseline or@phpstan-ignorecomments, because suppressing them masks guaranteed runtime fatal errors.This PR makes return type violation errors (
return.type,return.empty,return.void,return.never) non-ignorable when the violation is against the native return type specifically. Violations that only affect PHPDoc types (but not the native type) remain ignorable.Changes
src/Rules/FunctionReturnTypeCheck.php: Added?Type $nativeReturnTypeparameter andisNativeTypeViolated()helper method. When native type is violated, errors are marked non-ignorable. In non-strict mode, scalar-to-scalar coercion is allowed to remain ignorable since PHP coerces those at runtime without a TypeError.src/Rules/Methods/ReturnTypeRule.php: Pass$method->getNativeReturnType()tocheckReturnType()src/Rules/Functions/ReturnTypeRule.php: Pass$function->getNativeReturnType()tocheckReturnType()src/Rules/Functions/ClosureReturnTypeRule.php: Resolve native return type from closure AST node viaParserNodeTypeToPHPStanTypeand pass tocheckReturnType()src/Rules/Functions/ArrowFunctionReturnTypeRule.php: Same approach as closuressrc/PhpDoc/ResolvedPhpDocBlock.php: Fix pre-existing native type violation ingetNameScope()by addingassert($this->nameScope !== null)phpstan-baseline.neon: Remove baseline entry for the now-fixedResolvedPhpDocBlock::getNameScope()violationRoot cause
Return type errors were unconditionally ignorable regardless of whether they represented a native type violation (guaranteed runtime TypeError) or just a PHPDoc-level violation. The
FunctionReturnTypeCheck::checkReturnType()method had no knowledge of the native return type, only the combined (native + PHPDoc) type.Test
tests/PHPStan/Rules/Methods/data/bug-9833.php+ReturnTypeRuleTest::testBug9833()andtestBug9833NonIgnorable(): Tests method return type violations, verifying native type violations are non-ignorable while PHPDoc-only violations remain ignorable.tests/PHPStan/Rules/Functions/data/bug-9833.php+ReturnTypeRuleTest::testBug9833()andtestBug9833NonIgnorable(): Same for standalone functions.tests/PHPStan/Rules/Functions/data/bug-9833-closure.php+ClosureReturnTypeRuleTest::testBug9833()andtestBug9833NonIgnorable(): Same for closures.tests/PHPStan/Rules/Functions/data/bug-9833-arrow.php+ArrowFunctionReturnTypeRuleTest::testBug9833()andtestBug9833NonIgnorable(): Same for arrow functions.Fixes phpstan/phpstan#9833