diff --git a/src/Type/Constant/ConstantArrayTypeBuilder.php b/src/Type/Constant/ConstantArrayTypeBuilder.php index 46b4064377..8547fa39a9 100644 --- a/src/Type/Constant/ConstantArrayTypeBuilder.php +++ b/src/Type/Constant/ConstantArrayTypeBuilder.php @@ -163,7 +163,11 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt $min = min($this->nextAutoIndexes); $max = max($this->nextAutoIndexes); if ($offsetType->getValue() > $min) { - $this->isList = TrinaryLogic::createNo(); + if ($offsetType->getValue() <= $max) { + $this->isList = $this->isList->and(TrinaryLogic::createMaybe()); + } else { + $this->isList = TrinaryLogic::createNo(); + } } if ($offsetType->getValue() >= $max) { /** @var int|float $newAutoIndex */ diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 8eb31110b6..f931d1fd59 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -161,6 +161,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Comparison/data/bug-2550.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2899.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/preg_split.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/array-shape-list-optional.php'); if (PHP_VERSION_ID < 80000) { yield from $this->gatherAssertTypes(__DIR__ . '/data/bcmath-dynamic-return-php7.php'); diff --git a/tests/PHPStan/Analyser/data/array-shape-list-optional.php b/tests/PHPStan/Analyser/data/array-shape-list-optional.php new file mode 100644 index 0000000000..0eaa4471d2 --- /dev/null +++ b/tests/PHPStan/Analyser/data/array-shape-list-optional.php @@ -0,0 +1,26 @@ + but returns array{0?: 'foo', 1?: 'bar'}.", 10, - "array{0?: 'foo', 1?: 'bar'} is not a list.", + "array{0?: 'foo', 1?: 'bar'} might not be a list.", ], [ "Method ReturnList\Foo::getList2() should return list but returns array{0?: 'foo', 1?: 'bar'}.", 19, - "array{0?: 'foo', 1?: 'bar'} is not a list.", + "array{0?: 'foo', 1?: 'bar'} might not be a list.", ], ]); }