Skip to content

Commit

Permalink
Simplify and improve :)
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm committed Jan 6, 2025
1 parent 66a0ccd commit ace9569
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 20 deletions.
37 changes: 19 additions & 18 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -984,75 +984,76 @@ private function specifyTypesForCountFuncCall(
$isNormalCount = (new ConstantIntegerType(COUNT_NORMAL))->isSuperTypeOf($mode)->result->or($type->getIterableValueType()->isArray()->negate());
}

if (!$isNormalCount->yes() || (!$type->isConstantArray()->yes() && !$type->isList()->yes())) {
$isList = $type->isList();
if (
!$isNormalCount->yes()
|| (!$type->isConstantArray()->yes() && !$isList->yes())
|| $type->isIterableAtLeastOnce()->no() // array{} cannot be used for further narrowing
) {
return null;
}

$resultTypes = [];
$innerTypes = $type instanceof UnionType ? $type->getTypes() : [$type];
foreach ($innerTypes as $innerType) {
$isSizeSuperTypeOfArraySize = $sizeType->isSuperTypeOf($innerType->getArraySize());
foreach ($type->getArrays() as $arrayType) {
$isSizeSuperTypeOfArraySize = $sizeType->isSuperTypeOf($arrayType->getArraySize());
if ($isSizeSuperTypeOfArraySize->no()) {
continue;
}

if ($context->falsey() && $isSizeSuperTypeOfArraySize->maybe()) {
continue;
}

if (
$innerType->isList()->yes()
$isList->yes()
&& $sizeType instanceof ConstantIntegerType
&& $sizeType->getValue() < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
) {
// turn optional offsets non-optional
$valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty();
for ($i = 0; $i < $sizeType->getValue(); $i++) {
$offsetType = new ConstantIntegerType($i);
$valueTypesBuilder->setOffsetValueType($offsetType, $innerType->getOffsetValueType($offsetType));
$valueTypesBuilder->setOffsetValueType($offsetType, $arrayType->getOffsetValueType($offsetType));
}
$resultTypes[] = $valueTypesBuilder->getArray();
continue;
}

if (
$innerType->isList()->yes()
$isList->yes()
&& $sizeType instanceof IntegerRangeType
&& $sizeType->getMin() !== null
) {
// turn optional offsets non-optional
$valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty();
for ($i = 0; $i < $sizeType->getMin(); $i++) {
$offsetType = new ConstantIntegerType($i);
$valueTypesBuilder->setOffsetValueType($offsetType, $innerType->getOffsetValueType($offsetType));
$valueTypesBuilder->setOffsetValueType($offsetType, $arrayType->getOffsetValueType($offsetType));
}
if ($sizeType->getMax() !== null) {
for ($i = $sizeType->getMin(); $i < $sizeType->getMax(); $i++) {
$offsetType = new ConstantIntegerType($i);
$valueTypesBuilder->setOffsetValueType($offsetType, $innerType->getOffsetValueType($offsetType), true);
$valueTypesBuilder->setOffsetValueType($offsetType, $arrayType->getOffsetValueType($offsetType), true);
}
} elseif ($innerType->isConstantArray()->yes()) {
} elseif ($arrayType->isConstantArray()->yes()) {
for ($i = $sizeType->getMin();; $i++) {
$offsetType = new ConstantIntegerType($i);
$hasOffset = $innerType->hasOffsetValueType($offsetType);
$hasOffset = $arrayType->hasOffsetValueType($offsetType);
if ($hasOffset->no()) {
break;
}
$valueTypesBuilder->setOffsetValueType($offsetType, $innerType->getOffsetValueType($offsetType), !$hasOffset->yes());
$valueTypesBuilder->setOffsetValueType($offsetType, $arrayType->getOffsetValueType($offsetType), !$hasOffset->yes());
}
} else {
$resultTypes[] = TypeCombinator::intersect($innerType, new NonEmptyArrayType());
$resultTypes[] = TypeCombinator::intersect($arrayType, new NonEmptyArrayType());
continue;
}

$resultTypes[] = $valueTypesBuilder->getArray();
continue;
}

if (!$context->truthy()) {
continue;
}

$resultTypes[] = $innerType;
$resultTypes[] = $arrayType;
}

return $this->create($countFuncCall->getArgs()[0]->value, TypeCombinator::union(...$resultTypes), $context, $scope)->setRootExpr($rootExpr);
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug11480.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public function intUnionCount(): void
if (count($x) >= $count) {
assertType("array{'xy'}|array{0: 'ab', 1?: 'xy'}", $x);
} else {
assertType("array{}|array{'xy'}|array{0: 'ab', 1?: 'xy'}", $x);
assertType("array{}", $x);
}
assertType("array{}|array{'xy'}|array{0: 'ab', 1?: 'xy'}", $x);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/list-count.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ protected function testOptionalKeysInUnionListWithIntRange($row, $twoOrThree, $t
if (count($row) >= $maxThree) {
assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row);
} else {
assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row);
assertType('list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row);
}
}

Expand Down

0 comments on commit ace9569

Please sign in to comment.