Skip to content

Fix phpstan/phpstan#13247: iterable is equal to array|Traversable#5144

Merged
VincentLanglet merged 5 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-4xsqx2g
Mar 8, 2026
Merged

Fix phpstan/phpstan#13247: iterable is equal to array|Traversable#5144
VincentLanglet merged 5 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-4xsqx2g

Conversation

@phpstan-bot
Copy link
Collaborator

@phpstan-bot phpstan-bot commented Mar 7, 2026

Fixes phpstan/phpstan#13247

I merged this strategy with the previous one #5143

@VincentLanglet VincentLanglet requested a review from staabm March 7, 2026 22:35
@VincentLanglet
Copy link
Contributor

I made bunch of test, i ran multiple times the bot on the issue.
This is the best I have for now ; I'd like your opinion on it @staabm

Comment on lines +141 to +143
new GenericObjectType(Traversable::class, [
$this->keyType,
$this->itemType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +200 to +206
return $this->accepts(new UnionType([
new ArrayType($type->getIterableKeyType(), $type->getIterableValueType()),
new GenericObjectType(Traversable::class, [
$type->getIterableKeyType(),
$type->getIterableValueType(),
]),
]), $strictTypes);
Copy link
Contributor

@staabm staabm Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could/should have a IterableType->toTraversable() method (name to be discussed), so we don't repeat this logic in so many places?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added toTraversable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not precise enough. I thought about a method which turns iterable into array|Traversable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then should it be toArrayOrTraversable ?
Because toTraversable is unclear (and should be the method I introduced).

Also, the current ToTraversable can be used in the tryRemove method

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. So maybe add another method

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified and just added toArrayOrTraversable for now.

@@ -138,9 +138,9 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
if ($otherType instanceof IntersectionType || $otherType instanceof UnionType) {
Copy link
Contributor

@staabm staabm Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this case here is guarded also on IntersectionType. does it mean we need a similar fix you do on UnionType->accepts() also in IntersectionType->accepts()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added by the bot as a fix in a95e598 in order to fix

Parameter #1 $input of function Bug13247\as_array expects array<int, int>|Traversable<int, int>, iterable<int, int> given.

I don't have in mind something where an IntersectionType make sens ; but feel free to provide some case I'll add to my tests.

@VincentLanglet VincentLanglet force-pushed the create-pull-request/patch-4xsqx2g branch 2 times, most recently from 29af204 to 54cae34 Compare March 8, 2026 10:34
VincentLanglet and others added 5 commits March 8, 2026 11:35
- Fixed IterableType::isSubTypeOf() to use GenericObjectType for the Traversable
  part of the decomposition instead of IntersectionType with plain ObjectType
- The plain ObjectType(Traversable) lost generic type parameters, causing subtype
  checks against GenericObjectType(Traversable, [K, V]) to return maybe instead of yes
- Consistent with how IterableType::tryRemove() already decomposes iterable
- New regression test in tests/PHPStan/Rules/Functions/data/bug-13247.php
@VincentLanglet VincentLanglet force-pushed the create-pull-request/patch-4xsqx2g branch from 54cae34 to 0201f7a Compare March 8, 2026 10:35
@VincentLanglet VincentLanglet merged commit a3fb8e9 into phpstan:2.1.x Mar 8, 2026
639 of 648 checks passed
@staabm staabm deleted the create-pull-request/patch-4xsqx2g branch March 8, 2026 11:12
uekann pushed a commit to uekann/phpstan-src that referenced this pull request Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants