Fix phpstan/phpstan#9634: Cannot use "T is never" in conditional return#5082
Conversation
- Added TemplateType handling in NonAcceptingNeverType::isSuperTypeOf() and NeverType::isSuperTypeOf() to return Maybe instead of No, since a template type can be instantiated to never - New regression tests in tests/PHPStan/Rules/PhpDoc/data/bug-9634.php and tests/PHPStan/Analyser/nsrt/bug-9634.php Closes phpstan/phpstan#9634
8118609 to
42c3d05
Compare
VincentLanglet
left a comment
There was a problem hiding this comment.
- Add test for the issue phpstan/phpstan#10938
- Use
nsrt/bug-9634file intestBug9634and delete the duplicate - Be sure both NeverType and NonAcceptingNeverType are necessary/tested
…uplicate data file The rule test now references tests/PHPStan/Analyser/nsrt/bug-9634.php instead of maintaining a separate duplicate in tests/PHPStan/Rules/PhpDoc/data/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds nsrt and rule test coverage for the related issue where checking if a collection is empty using (TValue is never ? true : bool) conditional return type was not working. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…TemplateType Tests both NeverType and NonAcceptingNeverType return Maybe when checking isSuperTypeOf against a TemplateType, since a template type can be instantiated to never. Tests with both unbound and bounded template types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
All three review points have been addressed:
All tests pass ( |
Summary
When using
(T is never ? false : bool)as a conditional return type on a generic interface method, PHPStan incorrectly reported "Condition 'T is never' in conditional return type is always false." The fix allowsneverto correctly recognize that a template typeTmight be instantiated tonever.Changes
TemplateTypehandling insrc/Type/NonAcceptingNeverType.php—isSuperTypeOf()now returnsMaybefor template types instead ofNoTemplateTypehandling insrc/Type/NeverType.phpfor consistencytests/PHPStan/Rules/PhpDoc/data/bug-9634.phpand test method intests/PHPStan/Rules/PhpDoc/MethodConditionalReturnTypeRuleTest.phptests/PHPStan/Analyser/nsrt/bug-9634.phpverifying thatOption<never>::isSome()resolves tofalseandOption<int>::isSome()resolves toboolRoot cause
NonAcceptingNeverType::isSuperTypeOf()(the type used for explicitly writtenneverin PHPDoc) returnedNofor all types exceptNeverTypeandNonAcceptingNeverType. WhenConditionalReturnTypeRuleHelperchecked whether the conditionT is nevercould ever be true by calling$targetType->isSuperTypeOf($subjectType), thenevertarget returnedNofor the template typeT, causing the rule to report the condition as "always false". However, a template typeTcan be instantiated tonever(sinceneveris a subtype of any bound), so the correct answer isMaybe.Test
(T is never ? false : bool)no longer produces a false positive errorTis bound tonever, the conditional resolves tofalse, and whenTis bound toint, it resolves toboolFixes phpstan/phpstan#9634
Fixes phpstan/phpstan#10938