Skip to content

Commit 42d2acd

Browse files
committed
Infer non-empty-ness after count($a) == count($b)
1 parent 193d801 commit 42d2acd

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2260,7 +2260,7 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
22602260

22612261
$rightType = $scope->getType($rightExpr);
22622262

2263-
// (count($a) === $b)
2263+
// (count($a) === $expr)
22642264
if (
22652265
!$context->null()
22662266
&& $unwrappedLeftExpr instanceof FuncCall
@@ -2269,6 +2269,28 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
22692269
&& in_array(strtolower((string) $unwrappedLeftExpr->name), ['count', 'sizeof'], true)
22702270
&& $rightType->isInteger()->yes()
22712271
) {
2272+
// count($a) === count($b)
2273+
if (
2274+
$context->true()
2275+
&& $unwrappedRightExpr instanceof FuncCall
2276+
&& $unwrappedRightExpr->name instanceof Name
2277+
&& in_array($unwrappedRightExpr->name->toLowerString(), ['count', 'sizeof'], true)
2278+
&& count($unwrappedRightExpr->getArgs()) >= 1
2279+
) {
2280+
$leftArrayType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value);
2281+
$rightArrayType = $scope->getType($unwrappedRightExpr->getArgs()[0]->value);
2282+
2283+
if (
2284+
$leftArrayType->isArray()->yes() && $rightArrayType->isArray()->yes()
2285+
&& ($leftArrayType->isIterableAtLeastOnce()->yes() || $rightArrayType->isIterableAtLeastOnce()->yes())
2286+
) {
2287+
$arrayTypes = $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NonEmptyArrayType(), $context, $scope)->setRootExpr($expr);
2288+
return $arrayTypes->unionWith(
2289+
$this->create($unwrappedRightExpr->getArgs()[0]->value, new NonEmptyArrayType(), $context, $scope)->setRootExpr($expr),
2290+
);
2291+
}
2292+
}
2293+
22722294
if (IntegerRangeType::fromInterval(null, -1)->isSuperTypeOf($rightType)->yes()) {
22732295
return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($expr);
22742296
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
namespace ListCount2;
4+
5+
use function PHPStan\dumpType;
6+
use function PHPStan\debugScope;
7+
use function PHPStan\Testing\assertType;
8+
9+
class HelloWorld
10+
{
11+
/**
12+
* @param non-empty-list<int> $listA
13+
* @param list<int> $listB
14+
*/
15+
public function sayIdenticalLists($listA, array $listB): void
16+
{
17+
if (count($listA) === count($listB)) {
18+
assertType('non-empty-list<int>', $listB);
19+
}
20+
assertType('list<int>', $listB);
21+
}
22+
23+
/**
24+
* @param non-empty-list<int> $listA
25+
*/
26+
public function sayIdenticalList($listA, array $arrB): void
27+
{
28+
if (count($listA) === count($arrB)) {
29+
assertType('non-empty-array', $arrB);
30+
}
31+
assertType('array', $arrB);
32+
}
33+
34+
/**
35+
* @param non-empty-array<int> $arrA
36+
*/
37+
public function sayEqualArray($arrA, array $arrB): void
38+
{
39+
if (count($arrA) == count($arrB)) {
40+
assertType('non-empty-array', $arrB);
41+
}
42+
assertType('array', $arrB);
43+
}
44+
45+
/**
46+
* @param non-empty-array<int> $arrA
47+
* @param array<int> $arrB
48+
*/
49+
public function sayEqualIntArray($arrA, array $arrB): void
50+
{
51+
if (count($arrA) == count($arrB)) {
52+
assertType('non-empty-array<int>', $arrB);
53+
}
54+
assertType('array<int>', $arrB);
55+
}
56+
57+
/**
58+
* @param non-empty-array<int> $arrA
59+
* @param array<string> $arrB
60+
*/
61+
public function sayEqualStringArray($arrA, array $arrB): void
62+
{
63+
if (count($arrA) == count($arrB)) {
64+
assertType('non-empty-array<string>', $arrB);
65+
}
66+
assertType('array<string>', $arrB);
67+
}
68+
69+
/**
70+
* @param array<int> $arrA
71+
* @param array<string> $arrB
72+
*/
73+
public function sayUnknownArray($arrA, array $arrB): void
74+
{
75+
if (count($arrA) == count($arrB)) {
76+
assertType('array<int>', $arrA);
77+
assertType('array<string>', $arrB);
78+
}
79+
assertType('array<string>', $arrB);
80+
}
81+
}

0 commit comments

Comments
 (0)