Skip to content

Commit be995c2

Browse files
committed
Add for loop type inference tests
1 parent 2db5fd6 commit be995c2

File tree

4 files changed

+252
-0
lines changed

4 files changed

+252
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PHPStan\Testing\TypeInferenceTestCase;
6+
7+
class ForLoopNoScopePollutionTest extends TypeInferenceTestCase
8+
{
9+
10+
/** @return iterable<array<string, mixed[]>> */
11+
public function dataFileAsserts(): iterable
12+
{
13+
yield from $this->gatherAssertTypes(__DIR__ . '/data/for-loop-no-scope-pollution.php');
14+
}
15+
16+
/**
17+
* @dataProvider dataFileAsserts
18+
* @param mixed ...$args
19+
*/
20+
public function testFileAsserts(
21+
string $assertType,
22+
string $file,
23+
...$args,
24+
): void
25+
{
26+
$this->assertFileAsserts($assertType, $file, ...$args);
27+
}
28+
29+
public static function getAdditionalConfigFiles(): array
30+
{
31+
return [
32+
__DIR__ . '/forLoopNoScopePollution.neon',
33+
];
34+
}
35+
36+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ForLoopNoScopePollution;
4+
5+
6+
use PHPStan\TrinaryLogic;
7+
use function PHPStan\Testing\assertNativeType;
8+
use function PHPStan\Testing\assertType;
9+
use function PHPStan\Testing\assertVariableCertainty;
10+
11+
class ForLoop
12+
{
13+
14+
/** @param int $b */
15+
public function loopThatIteratesAtLeastOnce(int $a, $b): void
16+
{
17+
$j = 0;
18+
for ($i = 0, $j = 10; $i < 10; $i++, $j--) {
19+
$a = rand(0, 1);
20+
$b = rand(0, 1);
21+
$c = rand(0, 1);
22+
}
23+
24+
assertType('int<10, max>', $i);
25+
assertNativeType('int<10, max>', $i);
26+
assertVariableCertainty(TrinaryLogic::createMaybe(), $i);
27+
28+
assertType('int<min, 10>', $j);
29+
assertNativeType('int<min, 10>', $j);
30+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
31+
32+
assertType('int<0, 1>', $a);
33+
assertNativeType('int', $a);
34+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
35+
36+
assertType('int<0, 1>', $b);
37+
assertNativeType('int', $b);
38+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
39+
40+
assertType('int<0, 1>', $c);
41+
assertNativeType('int', $c);
42+
assertVariableCertainty(TrinaryLogic::createYes(), $c);
43+
}
44+
45+
/** @param int $b */
46+
public function loopThatMightIterateAtLeastOnce(int $a, $b): void
47+
{
48+
$j = 0;
49+
for ($i = 0, $j = 10; $i < rand(0, 1); $i++, $j--) {
50+
$a = rand(0, 1);
51+
$b = rand(0, 1);
52+
$c = rand(0, 1);
53+
}
54+
55+
assertType('int<0, max>', $i);
56+
assertNativeType('int<0, max>', $i);
57+
assertVariableCertainty(TrinaryLogic::createMaybe(), $i);
58+
59+
assertType('int<min, 10>', $j);
60+
assertNativeType('int<min, 10>', $j);
61+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
62+
63+
assertType('int', $a);
64+
assertNativeType('int', $a);
65+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
66+
67+
assertType('int', $b);
68+
assertNativeType('mixed', $b);
69+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
70+
71+
assertType('int<0, 1>', $c);
72+
assertNativeType('int', $c);
73+
assertVariableCertainty(TrinaryLogic::createMaybe(), $c);
74+
}
75+
76+
/** @param int $b */
77+
public function loopThatNeverIterates(int $a, $b): void
78+
{
79+
$j = 0;
80+
for ($i = 0, $j = 10; $i > 10; $i++, $j--) {
81+
$a = rand(0, 1);
82+
$b = rand(0, 1);
83+
$c = rand(0, 1);
84+
}
85+
86+
assertType('*ERROR*', $i);
87+
assertNativeType('*ERROR*', $i);
88+
assertVariableCertainty(TrinaryLogic::createNo(), $i);
89+
90+
assertType('0', $j);
91+
assertNativeType('0', $j);
92+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
93+
94+
assertType('int', $a);
95+
assertNativeType('int', $a);
96+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
97+
98+
assertType('int', $b);
99+
assertNativeType('mixed', $b);
100+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
101+
102+
assertType('*ERROR*', $c);
103+
assertNativeType('*ERROR*', $c);
104+
assertVariableCertainty(TrinaryLogic::createNo(), $c);
105+
}
106+
107+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
parameters:
2+
polluteScopeWithLoopInitialAssignments: false
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ForLoop;
4+
5+
6+
use PHPStan\TrinaryLogic;
7+
use function PHPStan\Testing\assertNativeType;
8+
use function PHPStan\Testing\assertType;
9+
use function PHPStan\Testing\assertVariableCertainty;
10+
11+
class ForLoop
12+
{
13+
14+
/** @param int $b */
15+
public function loopThatIteratesAtLeastOnce(int $a, $b): void
16+
{
17+
$j = 0;
18+
for ($i = 0, $j = 10; $i < 10; $i++, $j--) {
19+
$a = rand(0, 1);
20+
$b = rand(0, 1);
21+
$c = rand(0, 1);
22+
}
23+
24+
assertType('int<10, max>', $i);
25+
assertNativeType('int<10, max>', $i);
26+
assertVariableCertainty(TrinaryLogic::createYes(), $i);
27+
28+
assertType('int<min, 10>', $j);
29+
assertNativeType('int<min, 10>', $j);
30+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
31+
32+
assertType('int<0, 1>', $a);
33+
assertNativeType('int', $a);
34+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
35+
36+
assertType('int<0, 1>', $b);
37+
assertNativeType('int', $b);
38+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
39+
40+
assertType('int<0, 1>', $c);
41+
assertNativeType('int', $c);
42+
assertVariableCertainty(TrinaryLogic::createYes(), $c);
43+
}
44+
45+
/** @param int $b */
46+
public function loopThatMightIterateAtLeastOnce(int $a, $b): void
47+
{
48+
$j = 0;
49+
for ($i = 0, $j = 10; $i < rand(0, 1); $i++, $j--) {
50+
$a = rand(0, 1);
51+
$b = rand(0, 1);
52+
$c = rand(0, 1);
53+
}
54+
55+
assertType('int<0, max>', $i);
56+
assertNativeType('int<0, max>', $i);
57+
assertVariableCertainty(TrinaryLogic::createYes(), $i);
58+
59+
assertType('int<min, 10>', $j);
60+
assertNativeType('int<min, 10>', $j);
61+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
62+
63+
assertType('int', $a);
64+
assertNativeType('int', $a);
65+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
66+
67+
assertType('int', $b);
68+
assertNativeType('mixed', $b);
69+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
70+
71+
assertType('int<0, 1>', $c);
72+
assertNativeType('int', $c);
73+
assertVariableCertainty(TrinaryLogic::createMaybe(), $c);
74+
}
75+
76+
/** @param int $b */
77+
public function loopThatNeverIterates(int $a, $b): void
78+
{
79+
$j = 0;
80+
for ($i = 0, $j = 10; $i > 10; $i++, $j--) {
81+
$a = rand(0, 1);
82+
$b = rand(0, 1);
83+
$c = rand(0, 1);
84+
}
85+
86+
assertType('0', $i);
87+
assertNativeType('0', $i);
88+
assertVariableCertainty(TrinaryLogic::createYes(), $i);
89+
90+
assertType('10', $j);
91+
assertNativeType('10', $j);
92+
assertVariableCertainty(TrinaryLogic::createYes(), $j);
93+
94+
assertType('int', $a);
95+
assertNativeType('int', $a);
96+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
97+
98+
assertType('int', $b);
99+
assertNativeType('mixed', $b);
100+
assertVariableCertainty(TrinaryLogic::createYes(), $b);
101+
102+
assertType('*ERROR*', $c);
103+
assertNativeType('*ERROR*', $c);
104+
assertVariableCertainty(TrinaryLogic::createNo(), $c);
105+
}
106+
107+
}

0 commit comments

Comments
 (0)