Fix phpstan/phpstan#14348: TemplateIntersectionType is lost inside TypeCombinator::intersect#5275
Merged
staabm merged 4 commits intophpstan:2.1.xfrom Mar 23, 2026
Conversation
Contributor
|
confirmed this fix, also fixes the problem we see in #4441 (comment) |
staabm
requested changes
Mar 23, 2026
Contributor
staabm
left a comment
There was a problem hiding this comment.
Add a new test-case into the TypeCombinatorTest::testIntersect data-provider which reproduces the origin problem before the fix
Collaborator
Author
|
Already handled — |
staabm
approved these changes
Mar 23, 2026
VincentLanglet
approved these changes
Mar 23, 2026
staabm
requested changes
Mar 23, 2026
Contributor
staabm
left a comment
There was a problem hiding this comment.
Add a regression test for
Collaborator
Author
|
Already handled — |
- TemplateIntersectionType extends IntersectionType, so the flattening logic in TypeCombinator::intersect was unwrapping it into its inner types, losing the template context - Added a TemplateType check to skip flattening for template types - New regression test in tests/PHPStan/Analyser/nsrt/bug-14348.php Closes phpstan/phpstan#14348
…pe preservation Adds a test case that verifies intersecting a TemplateIntersectionType (T of A&B) with MixedType preserves the template wrapper instead of flattening it to a plain IntersectionType. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both issues involve template intersection types being lost during type narrowing, which is fixed by the TemplateIntersectionType preservation in TypeCombinator::intersect. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6a11602 to
00ddb87
Compare
staabm
approved these changes
Mar 23, 2026
VincentLanglet
approved these changes
Mar 23, 2026
This was referenced Mar 23, 2026
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 accessing elements of
non-empty-array<T>whereT of A&B(template with intersection bound), the template type was lost and reduced to justA&B. This happened becauseTypeCombinator::intersectflattenedTemplateIntersectionTypeas if it were a plainIntersectionType.Changes
!$type instanceof TemplateTypeguard to theIntersectionTypeflattening logic insrc/Type/TypeCombinator.php:1215tests/PHPStan/Analyser/nsrt/bug-14348.phpRoot cause
TemplateIntersectionTypeextendsIntersectionType, so the code atTypeCombinator::intersectthat transformsA & (B & C)intoA & B & Cwas also unwrapping template intersection types. For example, whenIntersectionType::getOffsetValueTypecomputedTypeCombinator::intersect(T, MixedType)for a non-empty array access, the template typeTwas flattened into its inner types (A & B), losing the template wrapper. The fix skips flattening when theIntersectionTypeis actually aTemplateType.Test
Added
tests/PHPStan/Analyser/nsrt/bug-14348.phpwhich verifies that accessing$tgs[0]onnon-empty-array<T>whereT of PositionEntityInterface&TgEntityInterfacepreserves the full template type.Fixes phpstan/phpstan#14348
Closes phpstan/phpstan#9961
Closes phpstan/phpstan#13577