Skip to content

Commit 2f70d9f

Browse files
authored
Merge branch refs/heads/1.12.x into 2.0.x
2 parents 753fc4d + fd6a0f2 commit 2f70d9f

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,10 @@ private function processStmtNode(
13611361
}
13621362

13631363
$bodyScope = $bodyScope->mergeWith($initScope);
1364+
1365+
$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
13641366
if ($lastCondExpr !== null) {
1367+
$alwaysIterates = $alwaysIterates->and($bodyScope->getType($lastCondExpr)->toBoolean()->isTrue());
13651368
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
13661369
}
13671370

@@ -1377,9 +1380,7 @@ private function processStmtNode(
13771380
}
13781381
$finalScope = $finalScope->generalizeWith($loopScope);
13791382

1380-
$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
13811383
if ($lastCondExpr !== null) {
1382-
$alwaysIterates = $alwaysIterates->and($finalScope->getType($lastCondExpr)->toBoolean()->isTrue());
13831384
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
13841385
}
13851386

tests/PHPStan/Analyser/StatementResultTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,14 @@ public function dataIsAlwaysTerminating(): array
298298
'for (; "a", "";) { }',
299299
false,
300300
],
301+
[
302+
'for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) { }',
303+
false,
304+
],
305+
[
306+
'for ($i = 0; $i < 10; $i++) { $i = 5; }',
307+
true,
308+
],
301309
[
302310
'do { } while (doFoo());',
303311
false,

tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,10 @@ public function testBug11179(): void
224224
$this->analyse([__DIR__ . '/data/bug-11179.php'], []);
225225
}
226226

227+
public function testBug11992(): void
228+
{
229+
$this->treatPhpDocTypesAsCertain = false;
230+
$this->analyse([__DIR__ . '/data/bug-11992.php'], []);
231+
}
232+
227233
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11992;
4+
5+
// valid
6+
function exampleA(): void {
7+
$bc = 0;
8+
for ($i = 0; $i < 3; ++$i) {
9+
$bc++;
10+
}
11+
printf("bc: %d\n", $bc);
12+
}
13+
14+
// not valid? Why? this is deterministic even from a static standpoint
15+
function exampleB(): void {
16+
$bc = 0;
17+
for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) {
18+
$bc++;
19+
}
20+
printf("bc: %d\n", $bc);
21+
}
22+
23+
// invalid because valid() is theoretically infinite?
24+
function exampleC(): void {
25+
for (
26+
$it = new \DirectoryIterator('/tmp');
27+
$it->valid();
28+
$it->next()
29+
) {
30+
printf("name: %s\n", $it->getFilename());
31+
}
32+
printf("done\n");
33+
}
34+
35+
exampleA();
36+
exampleB();
37+
exampleC();

0 commit comments

Comments
 (0)