Fix phpstan/phpstan#14281: Regression: type arrowed too much after identical comparison#5221
Closed
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Closed
Fix phpstan/phpstan#14281: Regression: type arrowed too much after identical comparison#5221phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
…parison - Root cause: commit a063119 introduced parent constructor template inference that resolved TElement to *NEVER* from empty default array parameters - When new TestCollection() was called without arguments, TElement was inferred as *NEVER* (from default []), causing get() to return null instead of mixed - This made assert($data[1] === $collection->get(1)) resolve as assert(0 === null), narrowing $data to *NEVER* (dead code) - Fix: skip NeverType when mapping parent constructor template types to child class - New regression test in tests/PHPStan/Analyser/nsrt/bug-14281.php
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 generic child class (e.g.,
TestCollection extends Collection) was instantiated without constructor arguments, and the constructor was defined in the parent class with a default empty array parameter (array $elements = []), PHPStan resolved the template type to*NEVER*instead ofmixed. This caused method return types likeTElement|nullto resolve tonull, which then made===comparisons with known non-null values impossible, narrowing the compared array to*NEVER*(dead code).Changes
NeverTypecheck insrc/Analyser/ExprHandler/NewHandler.php(line ~550) when mapping parent constructor resolved template types to the child class. When a resolved template isNeverType(typically from an empty default array), it is now skipped, allowing the template to fall back to its bound (usuallymixed).tests/PHPStan/Analyser/nsrt/bug-14281.phpRoot cause
Commit
a063119ee("Fix inferring type ofnewwith generic type with constructor in parent class") added logic to simulatenew ParentClass(args)and map the resolved parent template types back to the child class. When called with no arguments (e.g.,new TestCollection()), the parent constructor's default[]parameter resolvedTElementto*NEVER*(since an empty array has element typenever). This was then mapped to the child, makingTestCollection<*NEVER*>instead of the pre-fix behavior ofTestCollection<mixed>.The fix skips
NeverTypeentries when building the resolved type map from the parent constructor, so templates resolved from empty defaults correctly fall back to their bounds.Test
The regression test reproduces the exact scenario from the issue: a
Collection<TElement>with aTestCollectionchild class, whereassert($data[X] === $collection->get(X))should not narrow$datato*NEVER*.Fixes phpstan/phpstan#14281