diff --git a/src/Type/Constant/ConstantArrayTypeBuilder.php b/src/Type/Constant/ConstantArrayTypeBuilder.php index 525b65caed..a306833e8d 100644 --- a/src/Type/Constant/ConstantArrayTypeBuilder.php +++ b/src/Type/Constant/ConstantArrayTypeBuilder.php @@ -199,8 +199,6 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt return; } - $this->isList = TrinaryLogic::createNo(); - $scalarTypes = $offsetType->getConstantScalarTypes(); if (count($scalarTypes) === 0) { $integerRanges = TypeUtils::getIntegerRanges($offsetType); @@ -257,6 +255,8 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt return; } } + + $this->isList = TrinaryLogic::createNo(); } if ($offsetType === null) { diff --git a/tests/PHPStan/Analyser/nsrt/array-is-list-offset.php b/tests/PHPStan/Analyser/nsrt/array-is-list-offset.php new file mode 100644 index 0000000000..911490fac7 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/array-is-list-offset.php @@ -0,0 +1,19 @@ + $key + */ + public function test(array $array, int $key) { + assertType('int<0, 1>', $key); + assertType('true', array_is_list($array)); + + $array[$key] = false; + assertType('true', array_is_list($array)); + } +} diff --git a/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php b/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php index 0b8bff2efb..2d1aaa237c 100644 --- a/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php +++ b/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php @@ -5,6 +5,7 @@ use PHPStan\Type\BooleanType; use PHPStan\Type\NullType; use PHPStan\Type\StringType; +use PHPStan\Type\TypeCombinator; use PHPStan\Type\VerbosityLevel; use PHPUnit\Framework\TestCase; @@ -128,4 +129,37 @@ public function testIsList(): void $this->assertFalse($builder->isList()); } + public function testIsListWithUnion(): void + { + $builder = ConstantArrayTypeBuilder::createEmpty(); + + $builder->setOffsetValueType(null, new ConstantIntegerType(0)); + $this->assertTrue($builder->isList()); + + $builder->setOffsetValueType(new ConstantIntegerType(0), new NullType()); + $this->assertTrue($builder->isList()); + + $builder->setOffsetValueType(new ConstantIntegerType(1), new NullType()); + $this->assertTrue($builder->isList()); + + $builder->setOffsetValueType(new ConstantIntegerType(2), new NullType()); + $this->assertTrue($builder->isList()); + + $oneOrZero = TypeCombinator::union( + new ConstantIntegerType(0), + new ConstantIntegerType(1), + ); + + $builder->setOffsetValueType($oneOrZero, new NullType()); + $this->assertTrue($builder->isList()); + + $oneOrFour = TypeCombinator::union( + new ConstantIntegerType(1), + new ConstantIntegerType(4), + ); + + $builder->setOffsetValueType($oneOrFour, new NullType()); + $this->assertFalse($builder->isList()); + } + }