Skip to content

Commit 4d355da

Browse files
committed
Prevent explosion of types which turns into over-generalization
1 parent d3d3d8b commit 4d355da

File tree

2 files changed

+17
-15
lines changed

2 files changed

+17
-15
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ public function getOffsetValueType(Type $offsetType): Type
693693

694694
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
695695
{
696-
if ($offsetType !== null) {
696+
if ($offsetType !== null && $valueType->isConstantScalarValue()->yes()) {
697697
$constantScalars = $offsetType->getConstantScalarTypes();
698698
$constantScalarsCount = count($constantScalars);
699699
if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
@@ -715,17 +715,19 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni
715715

716716
public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
717717
{
718-
$constantScalars = $offsetType->getConstantScalarTypes();
719-
$constantScalarsCount = count($constantScalars);
720-
if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
721-
$arrays = [];
722-
foreach ($constantScalars as $constantScalar) {
723-
$builder = ConstantArrayTypeBuilder::createFromConstantArray($this);
724-
$builder->setOffsetValueType($constantScalar, $valueType);
725-
$arrays[] = $builder->getArray();
726-
}
718+
if ($valueType->isConstantScalarValue()->yes()) {
719+
$constantScalars = $offsetType->getConstantScalarTypes();
720+
$constantScalarsCount = count($constantScalars);
721+
if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
722+
$arrays = [];
723+
foreach ($constantScalars as $constantScalar) {
724+
$builder = ConstantArrayTypeBuilder::createFromConstantArray($this);
725+
$builder->setOffsetValueType($constantScalar, $valueType);
726+
$arrays[] = $builder->getArray();
727+
}
727728

728-
return TypeCombinator::union(...$arrays);
729+
return TypeCombinator::union(...$arrays);
730+
}
729731
}
730732

731733
$builder = ConstantArrayTypeBuilder::createFromConstantArray($this);

tests/PHPStan/Analyser/nsrt/constant-array-type-set.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public function doFoo(int $i)
2121
/** @var 0|1|2 $offset */
2222
$offset = doFoo();
2323
$c[$offset] = true;
24-
assertType('array{bool, bool, bool}', $c);
24+
assertType('array{false, false, true}|array{false, true, false}|array{true, false, false}', $c);
2525

2626
$d = [false, false, false];
2727
/** @var int<0, 2> $offset2 */
@@ -33,13 +33,13 @@ public function doFoo(int $i)
3333
/** @var 0|1|2|3 $offset3 */
3434
$offset3 = doFoo();
3535
$e[$offset3] = true;
36-
assertType('array{0: bool, 1: bool, 2: bool, 3?: true}', $e);
36+
assertType('array{false, false, false, true}|array{false, false, true}|array{false, true, false}|array{true, false, false}', $e);
3737

3838
$f = [false, false, false];
3939
/** @var 0|1 $offset4 */
4040
$offset4 = doFoo();
4141
$f[$offset4] = true;
42-
assertType('array{bool, bool, false}', $f);
42+
assertType('array{false, true, false}|array{true, false, false}', $f);
4343
}
4444

4545
/**
@@ -101,7 +101,7 @@ public function doBar6(bool $offset): void
101101
{
102102
$a = [false, false, false];
103103
$a[$offset] = true;
104-
assertType('array{bool, bool, false}', $a);
104+
assertType('array{false, true, false}|array{true, false, false}', $a);
105105
}
106106

107107
/**

0 commit comments

Comments
 (0)