Skip to content

Commit cf43e1f

Browse files
herndlmondrejmirtes
authored andcommitted
Fix ConstantArrayTypeBuilder optional keys via setOffsetValueType
1 parent 8084ab3 commit cf43e1f

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

src/Type/Constant/ConstantArrayTypeBuilder.php

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
8383

8484
$this->valueTypes[$i] = TypeCombinator::union($this->valueTypes[$i], $valueType);
8585

86+
if (!$hasOptional && !$optional) {
87+
$this->optionalKeys = array_values(array_filter($this->optionalKeys, static fn (int $index): bool => $index !== $i));
88+
}
89+
8690
/** @var int|float $newAutoIndex */
8791
$newAutoIndex = $keyType->getValue() + 1;
8892
if (is_float($newAutoIndex)) {

tests/PHPStan/Analyser/data/constant-array-optional-set.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public function doFoo()
108108
assertType('array{0: \'lorem\', 1: stdClass, 2: 1, 3: 1|2, 4: 1|3, 5?: 2|3, 6?: 3}', $unshiftedConditionalArray + $conditionalArray);
109109

110110
$conditionalArray[] = 4;
111-
assertType('array{0: 1, 1: 1, 2: 1, 3?: 2|4, 4?: 3, 5?: 4}', $conditionalArray);
111+
assertType('array{0: 1, 1: 1, 2: 1, 3: 2|4, 4?: 3, 5?: 4}', $conditionalArray);
112112
}
113113

114114
}

tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php

+20-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Type\Constant;
44

5+
use PHPStan\Type\BooleanType;
6+
use PHPStan\Type\NullType;
57
use PHPStan\Type\VerbosityLevel;
68
use PHPUnit\Framework\TestCase;
79

@@ -27,7 +29,7 @@ public function testOptionalKeysNextAutoIndex(): void
2729
$builder->setOffsetValueType(null, new ConstantIntegerType(3));
2830
$array3 = $builder->getArray();
2931
$this->assertInstanceOf(ConstantArrayType::class, $array3);
30-
$this->assertSame('array{0: 1, 1?: 2|3, 2?: 3}', $array3->describe(VerbosityLevel::precise()));
32+
$this->assertSame('array{0: 1, 1: 2|3, 2?: 3}', $array3->describe(VerbosityLevel::precise()));
3133
$this->assertSame([2, 3], $array3->getNextAutoIndexes());
3234

3335
$this->assertTrue($array3->isKeysSupersetOf($array2));
@@ -38,19 +40,19 @@ public function testOptionalKeysNextAutoIndex(): void
3840
$builder->setOffsetValueType(null, new ConstantIntegerType(4));
3941
$array4 = $builder->getArray();
4042
$this->assertInstanceOf(ConstantArrayType::class, $array4);
41-
$this->assertSame('array{0: 1, 1?: 2|3, 2?: 3|4, 3?: 4}', $array4->describe(VerbosityLevel::precise()));
43+
$this->assertSame('array{0: 1, 1: 2|3, 2: 3|4, 3?: 4}', $array4->describe(VerbosityLevel::precise()));
4244
$this->assertSame([3, 4], $array4->getNextAutoIndexes());
4345

4446
$builder->setOffsetValueType(new ConstantIntegerType(3), new ConstantIntegerType(5), true);
4547
$array5 = $builder->getArray();
4648
$this->assertInstanceOf(ConstantArrayType::class, $array5);
47-
$this->assertSame('array{0: 1, 1?: 2|3, 2?: 3|4, 3?: 4|5}', $array5->describe(VerbosityLevel::precise()));
49+
$this->assertSame('array{0: 1, 1: 2|3, 2: 3|4, 3?: 4|5}', $array5->describe(VerbosityLevel::precise()));
4850
$this->assertSame([3, 4], $array5->getNextAutoIndexes());
4951

5052
$builder->setOffsetValueType(new ConstantIntegerType(3), new ConstantIntegerType(6));
5153
$array6 = $builder->getArray();
5254
$this->assertInstanceOf(ConstantArrayType::class, $array6);
53-
$this->assertSame('array{0: 1, 1?: 2|3, 2?: 3|4, 3: 6}', $array6->describe(VerbosityLevel::precise()));
55+
$this->assertSame('array{1, 2|3, 3|4, 6}', $array6->describe(VerbosityLevel::precise()));
5456
$this->assertSame([4], $array6->getNextAutoIndexes());
5557
}
5658

@@ -82,4 +84,18 @@ public function testNextAutoIndexAnother(): void
8284
$this->assertSame([2], $array->getNextAutoIndexes());
8385
}
8486

87+
public function testAppendingOptionalKeys(): void
88+
{
89+
$builder = ConstantArrayTypeBuilder::createEmpty();
90+
91+
$builder->setOffsetValueType(null, new BooleanType(), true);
92+
$this->assertSame('array{0?: bool}', $builder->getArray()->describe(VerbosityLevel::precise()));
93+
94+
$builder->setOffsetValueType(null, new NullType(), true);
95+
$this->assertSame('array{0?: bool|null, 1?: null}', $builder->getArray()->describe(VerbosityLevel::precise()));
96+
97+
$builder->setOffsetValueType(null, new ConstantIntegerType(17));
98+
$this->assertSame('array{0: 17|bool|null, 1?: 17|null, 2?: 17}', $builder->getArray()->describe(VerbosityLevel::precise()));
99+
}
100+
85101
}

0 commit comments

Comments
 (0)