Skip to content

Commit

Permalink
TypeSpecifier - support IntegerRangeType with count()
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Apr 2, 2021
1 parent 9cc7734 commit 7b417c7
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 5 deletions.
12 changes: 7 additions & 5 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public function specifyTypesInCondition(
$newContext = $newContext->negate();
}
$argType = $scope->getType($exprNode->args[0]->value);
if ((new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($argType)->yes()) {
if ($argType->isArray()->yes()) {
return $this->create($exprNode->args[0]->value, new NonEmptyArrayType(), $newContext, false, $scope);
}
}
Expand Down Expand Up @@ -389,7 +389,6 @@ public function specifyTypesInCondition(
&& count($expr->left->args) === 1
&& $expr->left->name instanceof Name
&& strtolower((string) $expr->left->name) === 'count'
&& $rightType instanceof ConstantIntegerType
&& (
!$expr->right instanceof FuncCall
|| !$expr->right->name instanceof Name
Expand All @@ -415,11 +414,14 @@ public function specifyTypesInCondition(
&& count($expr->right->args) === 1
&& $expr->right->name instanceof Name
&& strtolower((string) $expr->right->name) === 'count'
&& $leftType instanceof ConstantIntegerType
&& (new IntegerType())->isSuperTypeOf($leftType)->yes()
) {
if ($context->truthy() || $leftType->getValue() + $offset === 1) {
if (
$context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes())
|| ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes())
) {
$argType = $scope->getType($expr->right->args[0]->value);
if ((new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($argType)->yes()) {
if ($argType->isArray()->yes()) {
$result = $result->unionWith($this->create($expr->right->args[0]->value, new NonEmptyArrayType(), $context, false, $scope));
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10336,6 +10336,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4434.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4231.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4287.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4700.php');
}

/**
Expand Down
49 changes: 49 additions & 0 deletions tests/PHPStan/Analyser/data/bug-4700.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Bug4700;

use function PHPStan\Analyser\assertType;

function(array $array, int $count): void {
if ($count < 1) {
return;
}

assertType('int<1, max>', $count);

$a = [];
if (isset($array['a'])) $a[] = $array['a'];
if (isset($array['b'])) $a[] = $array['b'];
if (isset($array['c'])) $a[] = $array['c'];
if (isset($array['d'])) $a[] = $array['d'];
if (isset($array['e'])) $a[] = $array['e'];
if (count($a) >= $count) {
assertType('1|2|3|4|5', count($a));
assertType('array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
} else {
assertType('0|1|2|3|4|5', count($a));
assertType('array()|array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
}
};

function(array $array, int $count): void {
if ($count < 1) {
return;
}

assertType('int<1, max>', $count);

$a = [];
if (isset($array['a'])) $a[] = $array['a'];
if (isset($array['b'])) $a[] = $array['b'];
if (isset($array['c'])) $a[] = $array['c'];
if (isset($array['d'])) $a[] = $array['d'];
if (isset($array['e'])) $a[] = $array['e'];
if (count($a) > $count) {
assertType('2|3|4|5', count($a));
assertType('array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
} else {
assertType('0|1|2|3|4|5', count($a));
assertType('array()|array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
}
};

0 comments on commit 7b417c7

Please sign in to comment.