Skip to content

Commit

Permalink
Fix ConstantArrayTypeBuilder optional keys via setOffsetValueType
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm authored and ondrejmirtes committed Apr 19, 2022
1 parent 8084ab3 commit cf43e1f
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/Type/Constant/ConstantArrayTypeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt

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

if (!$hasOptional && !$optional) {
$this->optionalKeys = array_values(array_filter($this->optionalKeys, static fn (int $index): bool => $index !== $i));
}

/** @var int|float $newAutoIndex */
$newAutoIndex = $keyType->getValue() + 1;
if (is_float($newAutoIndex)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public function doFoo()
assertType('array{0: \'lorem\', 1: stdClass, 2: 1, 3: 1|2, 4: 1|3, 5?: 2|3, 6?: 3}', $unshiftedConditionalArray + $conditionalArray);

$conditionalArray[] = 4;
assertType('array{0: 1, 1: 1, 2: 1, 3?: 2|4, 4?: 3, 5?: 4}', $conditionalArray);
assertType('array{0: 1, 1: 1, 2: 1, 3: 2|4, 4?: 3, 5?: 4}', $conditionalArray);
}

}
24 changes: 20 additions & 4 deletions tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PHPStan\Type\Constant;

use PHPStan\Type\BooleanType;
use PHPStan\Type\NullType;
use PHPStan\Type\VerbosityLevel;
use PHPUnit\Framework\TestCase;

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

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

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

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

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

public function testAppendingOptionalKeys(): void
{
$builder = ConstantArrayTypeBuilder::createEmpty();

$builder->setOffsetValueType(null, new BooleanType(), true);
$this->assertSame('array{0?: bool}', $builder->getArray()->describe(VerbosityLevel::precise()));

$builder->setOffsetValueType(null, new NullType(), true);
$this->assertSame('array{0?: bool|null, 1?: null}', $builder->getArray()->describe(VerbosityLevel::precise()));

$builder->setOffsetValueType(null, new ConstantIntegerType(17));
$this->assertSame('array{0: 17|bool|null, 1?: 17|null, 2?: 17}', $builder->getArray()->describe(VerbosityLevel::precise()));
}

}

0 comments on commit cf43e1f

Please sign in to comment.