Skip to content

Commit ebce7de

Browse files
committed
Fixed bug with uncertain variables merging in root scope
1 parent 7a4b50d commit ebce7de

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

src/Analyser/MutatingScope.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,14 +335,19 @@ private function getVariableTypes(): array
335335
return $this->variableTypes;
336336
}
337337

338+
private function isRootScope(): bool
339+
{
340+
return $this->function === null && !$this->isInAnonymousFunction();
341+
}
342+
338343
public function hasVariableType(string $variableName): TrinaryLogic
339344
{
340345
if ($this->isGlobalVariable($variableName)) {
341346
return TrinaryLogic::createYes();
342347
}
343348

344349
if (!isset($this->variableTypes[$variableName])) {
345-
if ($this->function === null && !$this->isInAnonymousFunction()) {
350+
if ($this->isRootScope()) {
346351
return TrinaryLogic::createMaybe();
347352
}
348353

@@ -3200,6 +3205,18 @@ public function mergeWith(?self $otherScope): self
32003205
return new VariableTypeHolder($type, TrinaryLogic::createYes());
32013206
};
32023207

3208+
$ourVariableTypes = $this->getVariableTypes();
3209+
$theirVariableTypes = $otherScope->getVariableTypes();
3210+
if ($this->isRootScope()) {
3211+
foreach (array_keys($theirVariableTypes) as $name) {
3212+
if (array_key_exists($name, $ourVariableTypes)) {
3213+
continue;
3214+
}
3215+
3216+
$ourVariableTypes[$name] = VariableTypeHolder::createMaybe(new MixedType());
3217+
}
3218+
}
3219+
32033220
return $this->scopeFactory->create(
32043221
$this->context,
32053222
$this->isDeclareStrictTypes(),
@@ -3209,7 +3226,7 @@ public function mergeWith(?self $otherScope): self
32093226
)),
32103227
$this->getFunction(),
32113228
$this->getNamespace(),
3212-
$this->mergeVariableHolders($this->getVariableTypes(), $otherScope->getVariableTypes()),
3229+
$this->mergeVariableHolders($ourVariableTypes, $theirVariableTypes),
32133230
$this->mergeVariableHolders($this->moreSpecificTypes, $otherScope->moreSpecificTypes),
32143231
$this->inClosureBindScopeClass,
32153232
$this->anonymousFunctionReflection,

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10136,6 +10136,11 @@ public function dataBug1014(): array
1013610136
return $this->gatherAssertTypes(__DIR__ . '/data/bug-1014.php');
1013710137
}
1013810138

10139+
public function dataBugFromPr339(): array
10140+
{
10141+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-pr-339.php');
10142+
}
10143+
1013910144
/**
1014010145
* @dataProvider dataBug2574
1014110146
* @dataProvider dataBug2577
@@ -10211,6 +10216,7 @@ public function dataBug1014(): array
1021110216
* @dataProvider dataBug3548
1021210217
* @dataProvider dataBug3866
1021310218
* @dataProvider dataBug1014
10219+
* @dataProvider dataBugFromPr339
1021410220
* @param string $assertType
1021510221
* @param string $file
1021610222
* @param mixed ...$args
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace BugPr339;
4+
5+
use PHPStan\TrinaryLogic;
6+
use function PHPStan\Analyser\assertType;
7+
use function PHPStan\Analyser\assertVariableCertainty;
8+
9+
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
10+
assertVariableCertainty(TrinaryLogic::createMaybe(), $c);
11+
assertType('mixed', $a);
12+
assertType('mixed', $c);
13+
14+
if ($a || $c) {
15+
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
16+
assertVariableCertainty(TrinaryLogic::createMaybe(), $c);
17+
assertType('mixed', $a);
18+
assertType('mixed', $c);
19+
if ($a) {
20+
assertType("mixed~0|0.0|''|'0'|array()|false|null", $a);
21+
assertType('mixed', $c);
22+
assertVariableCertainty(TrinaryLogic::createYes(), $a);
23+
}
24+
25+
if ($c) {
26+
assertType('mixed', $a);
27+
assertType("mixed~0|0.0|''|'0'|array()|false|null", $c);
28+
assertVariableCertainty(TrinaryLogic::createYes(), $c);
29+
}
30+
} else {
31+
assertType("0|0.0|''|'0'|array()|false|null", $a);
32+
assertType("0|0.0|''|'0'|array()|false|null", $c);
33+
}

0 commit comments

Comments
 (0)