Skip to content

Commit

Permalink
fix for big int-ranges v2 + test
Browse files Browse the repository at this point in the history
fix issue #6375
  • Loading branch information
voku committed Jan 24, 2022
1 parent 66d13eb commit cba6fa7
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
37 changes: 30 additions & 7 deletions src/Type/Constant/ConstantArrayTypeBuilder.php
Expand Up @@ -5,6 +5,7 @@
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Accessory\NonEmptyArrayType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\IntegerRangeType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
Expand Down Expand Up @@ -101,37 +102,59 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt

$scalarTypes = TypeUtils::getConstantScalars($offsetType);
if (count($scalarTypes) === 0) {
$integerRanges = TypeUtils::getIntegerRanges($offsetType);
$integerRangesBackup = TypeUtils::getIntegerRanges($offsetType);
$integerRanges = $integerRangesBackup;
if (count($integerRanges) > 0) {
foreach ($integerRanges as $integerRange) {
$minRange = $integerRange->getMin();
if ($minRange === null || $minRange <= -self::ARRAY_COUNT_LIMIT) {
if ($minRange === null) {
break;
}

$maxRange = $integerRange->getMax();
if ($maxRange === null || $maxRange >= self::ARRAY_COUNT_LIMIT) {
if ($maxRange === null) {
break;
}

foreach (range($minRange, $maxRange) as $rangeValue) {
$rangeValue = $minRange;
$rangeCount = 0;
do {
$rangeCount++;
if ($rangeCount > self::ARRAY_COUNT_LIMIT) {
$scalarTypes = $integerRangesBackup;

break;
}

$scalarTypes[] = new ConstantIntegerType($rangeValue);
}
$rangeValue++;
} while ($rangeValue <= $maxRange);
}
}
}

if (count($scalarTypes) > 0 && count($scalarTypes) < self::ARRAY_COUNT_LIMIT) {
$match = true;
$valueTypes = $this->valueTypes;
foreach ($scalarTypes as $scalarType) {
$scalarOffsetType = ArrayType::castToArrayKeyType($scalarType);
if (!$scalarOffsetType instanceof ConstantIntegerType && !$scalarOffsetType instanceof ConstantStringType) {
if (
!$scalarOffsetType instanceof ConstantIntegerType
&& !$scalarOffsetType instanceof ConstantStringType
&& !$scalarOffsetType instanceof IntegerRangeType
) {
throw new ShouldNotHappenException();
}
$offsetMatch = false;

/** @var ConstantIntegerType|ConstantStringType $keyType */
/** @var ConstantIntegerType|ConstantStringType|IntegerRangeType $keyType */
foreach ($this->keyTypes as $i => $keyType) {
if ($scalarOffsetType instanceof IntegerRangeType) {
$match = false;

break;
}

if ($keyType->getValue() !== $scalarOffsetType->getValue()) {
continue;
}
Expand Down
9 changes: 9 additions & 0 deletions tests/PHPStan/PhpDoc/TypeDescriptionTest.php
Expand Up @@ -79,6 +79,15 @@ public function dataTest(): iterable
);
$builder->setOffsetValueType(IntegerRangeType::fromInterval(-2147483648, 2147483647), new StringType());
yield ['non-empty-array<int<-2147483648, 2147483647>, string>', $builder->getArray()];

$builder = ConstantArrayTypeBuilder::createFromConstantArray(
new ConstantArrayType(
[new ConstantIntegerType(0), new ConstantIntegerType(20)],
[new StringType(), new StringType()],
),
);
$builder->setOffsetValueType(IntegerRangeType::fromInterval(1, 19), new StringType());
yield ['non-empty-array<int<0, 20>, string>', $builder->getArray()];
}

/**
Expand Down

0 comments on commit cba6fa7

Please sign in to comment.