diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 4cec2bf409..99c5d7b7d3 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -693,6 +693,20 @@ public function getOffsetValueType(Type $offsetType): Type public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type { + if ($offsetType !== null) { + $constantScalars = $offsetType->getConstantScalarTypes(); + $constantScalarsCount = count($constantScalars); + if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { + $arrays = []; + foreach ($constantScalars as $constantScalar) { + $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); + $builder->setOffsetValueType($constantScalar, $valueType); + $arrays[] = $builder->getArray(); + } + + return TypeCombinator::union(...$arrays); + } + } $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); $builder->setOffsetValueType($offsetType, $valueType); @@ -701,6 +715,19 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type { + $constantScalars = $offsetType->getConstantScalarTypes(); + $constantScalarsCount = count($constantScalars); + if ($constantScalarsCount > 1 && $constantScalarsCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { + $arrays = []; + foreach ($constantScalars as $constantScalar) { + $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); + $builder->setOffsetValueType($constantScalar, $valueType); + $arrays[] = $builder->getArray(); + } + + return TypeCombinator::union(...$arrays); + } + $builder = ConstantArrayTypeBuilder::createFromConstantArray($this); $builder->setOffsetValueType($offsetType, $valueType); diff --git a/tests/PHPStan/Analyser/nsrt/bug-11716.php b/tests/PHPStan/Analyser/nsrt/bug-11716.php index 3dced2a08d..66a2bd0108 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-11716.php +++ b/tests/PHPStan/Analyser/nsrt/bug-11716.php @@ -22,7 +22,7 @@ public function parse(string $glue): string $seenGlues[$glue] = true; assertType("'&'|'|'", $glue); - assertType("array{'|': bool, '&': bool}", $seenGlues); + assertType("array{'|': false, '&': true}|array{'|': true, '&': false}", $seenGlues); } else { assertType("''", $glue); } diff --git a/tests/PHPStan/Analyser/nsrt/constant-array-type-set.php b/tests/PHPStan/Analyser/nsrt/constant-array-type-set.php index 9ae0b88828..90e13929f0 100644 --- a/tests/PHPStan/Analyser/nsrt/constant-array-type-set.php +++ b/tests/PHPStan/Analyser/nsrt/constant-array-type-set.php @@ -33,7 +33,7 @@ public function doFoo(int $i) /** @var 0|1|2|3 $offset3 */ $offset3 = doFoo(); $e[$offset3] = true; - assertType('non-empty-array<0|1|2|3, bool>', $e); + assertType('array{0: bool, 1: bool, 2: bool, 3?: true}', $e); $f = [false, false, false]; /** @var 0|1 $offset4 */ diff --git a/tests/PHPStan/Analyser/nsrt/set-constant-union-offset-on-constant-array.php b/tests/PHPStan/Analyser/nsrt/set-constant-union-offset-on-constant-array.php new file mode 100644 index 0000000000..4b862c6750 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/set-constant-union-offset-on-constant-array.php @@ -0,0 +1,20 @@ +