Fix phpstan/phpstan#13247: iterable is equal to array|Traversable#5142
Closed
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Closed
Fix phpstan/phpstan#13247: iterable is equal to array|Traversable#5142phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
iterable is equal to array|Traversable#5142phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- Fixed IterableType::isSubTypeOf to decompose iterable<K,V> into array<K,V>|GenericObjectType(Traversable<K,V>) instead of array<K,V>|(ObjectType(Traversable)&iterable<K,V>), preserving generic type information for proper subtype checking - Fixed UnionType::inferTemplateTypes to decompose IterableType into array|Traversable union before template inference, allowing template types to be correctly resolved from iterable arguments - Added regression test for phpstan/phpstan#13247 Closes phpstan/phpstan#13247
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 passing an
iterable<K, V>to a function expectingarray<K, V>|Traversable<K, V>, PHPStan incorrectly reported a type error and failed to resolve template types, even thoughiterable<K, V>is semantically equivalent toarray<K, V>|Traversable<K, V>.Changes
src/Type/IterableType.php: ChangedisSubTypeOf()to decomposeiterable<K,V>intoarray<K,V> | Traversable<K,V>(usingGenericObjectType) instead ofarray<K,V> | (ObjectType(Traversable) & iterable<K,V>). The old intersection-based decomposition lost generic type information because the unparameterizedObjectType(Traversable)couldn't match againstGenericObjectType(Traversable<K,V>).src/Type/UnionType.php: Added early decomposition ofIterableTypeininferTemplateTypes()— when the received type isiterable<K,V>, it is decomposed intoarray<K,V> | Traversable<K,V>before template inference, allowing each union member to correctly infer template types from its matching component.phpstan-baseline.neon: Updatedinstanceof IterableTypeignore count from 1 to 2 forUnionType.php.tests/PHPStan/Rules/Functions/data/bug-13247.php: New regression test data file.tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php: AddedtestBug13247().Root cause
Two separate issues caused the bug:
Template inference failure:
UnionType::inferTemplateTypes()tried to infer template types by delegating to each union member (ArrayTypeandGenericObjectType(Traversable)). Neither could infer templates from anIterableType—ArrayType::inferTemplateTypesrejects non-array types, andGenericObjectType::inferTemplateTypesrequiresTypeWithClassName. With templates unresolved, the parameter type fell back to template bounds.Subtype check failure:
IterableType::isSubTypeOf()decomposediterable<K,V>intoarray<K,V> | (ObjectType(Traversable) & iterable<K,V>). The intersection used an unparameterizedObjectType(Traversable), which couldn't properly match againstGenericObjectType(Traversable<K,V>)in the target union, causing the subtype check to fail.Test
Added a regression test
testBug13247that verifies passingiterable<K, V>to a function expectingarray<K, V>|Traversable<K, V>produces no errors.Fixes phpstan/phpstan#13247