Skip to content

Commit a9fb98b

Browse files
Rework
1 parent 418ecc5 commit a9fb98b

File tree

3 files changed

+70
-33
lines changed

3 files changed

+70
-33
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4388,6 +4388,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
43884388
$armCondScope = $matchScope;
43894389
$condNodes = [];
43904390
$armCondResultScope = $matchScope;
4391+
$bodyScope = null;
43914392
foreach ($arm->conds as $j => $armCond) {
43924393
if (isset($armCondsToSkip[$i][$j])) {
43934394
continue;
@@ -4403,36 +4404,17 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
44034404
if ($armCondType->isTrue()->yes()) {
44044405
$hasAlwaysTrueCond = true;
44054406
}
4406-
$armCondScope = $armCondResult->getScope()->filterByFalseyValue($armCondExpr);
4407+
$armCondScope = $armCondResultScope->filterByFalseyValue($armCondExpr);
4408+
if ($bodyScope === null) {
4409+
$bodyScope = $armCondResultScope->filterByTruthyValue($armCondExpr);
4410+
} else {
4411+
$bodyScope = $bodyScope->mergeWith($armCondResultScope->filterByTruthyValue($armCondExpr));
4412+
}
44074413
$filteringExprs[] = $armCond;
44084414
}
44094415

44104416
$filteringExpr = $this->getFilteringExprForMatchArm($expr, $filteringExprs);
4411-
$bodyScope = $matchScope->filterByTruthyValue($filteringExpr);
4412-
$condResultScope = $armCondResultScope;
4413-
$matchScopeKnownVars = array_flip(array_merge($matchScope->getDefinedVariables(), $matchScope->getMaybeDefinedVariables()));
4414-
foreach ($condResultScope->getDefinedVariables() as $varName) {
4415-
if (isset($matchScopeKnownVars[$varName])) {
4416-
continue;
4417-
}
4418-
$bodyScope = $bodyScope->assignVariable(
4419-
$varName,
4420-
$condResultScope->getVariableType($varName),
4421-
$condResultScope->getNativeType(new Variable($varName)),
4422-
$condResultScope->hasVariableType($varName),
4423-
);
4424-
}
4425-
foreach ($condResultScope->getMaybeDefinedVariables() as $varName) {
4426-
if (isset($matchScopeKnownVars[$varName])) {
4427-
continue;
4428-
}
4429-
$bodyScope = $bodyScope->assignVariable(
4430-
$varName,
4431-
$condResultScope->getVariableType($varName),
4432-
$condResultScope->getNativeType(new Variable($varName)),
4433-
$condResultScope->hasVariableType($varName),
4434-
);
4435-
}
4417+
$bodyScope ??= $matchScope->filterByTruthyValue($filteringExpr);
44364418
$matchArmBody = new MatchExpressionArmBody($bodyScope, $arm->body);
44374419
$armNodes[$i] = new MatchExpressionArm($matchArmBody, $condNodes, $arm->getStartLine());
44384420

@@ -4449,7 +4431,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
44494431
$hasYield = $hasYield || $armResult->hasYield();
44504432
$throwPoints = array_merge($throwPoints, $armResult->getThrowPoints());
44514433
$impurePoints = array_merge($impurePoints, $armResult->getImpurePoints());
4452-
$matchScope = $matchScope->filterByFalseyValue($filteringExpr);
4434+
$matchScope = $armCondScope->filterByFalseyValue($filteringExpr);
44534435
}
44544436

44554437
if (!$hasDefaultCond && !$hasAlwaysTrueCond && $condType->isBoolean()->yes() && $condType->isConstantScalarValue()->yes()) {

tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,36 +1236,45 @@ public function testBug10909(): void
12361236
}
12371237

12381238
#[RequiresPhp('>= 8.0')]
1239-
public function testBug7705(): void
1239+
public function testBug13981(): void
12401240
{
12411241
$this->cliArgumentsVariablesRegistered = true;
12421242
$this->polluteScopeWithLoopInitialAssignments = true;
12431243
$this->checkMaybeUndefinedVariables = true;
12441244
$this->polluteScopeWithAlwaysIterableForeach = true;
12451245

1246-
$this->analyse([__DIR__ . '/data/bug-7705.php'], []);
1246+
$this->analyse([__DIR__ . '/data/bug-13981.php'], [
1247+
[
1248+
'Undefined variable: $baseDir',
1249+
34,
1250+
],
1251+
[
1252+
'Variable $baseDir might not be defined.',
1253+
46,
1254+
],
1255+
]);
12471256
}
12481257

12491258
#[RequiresPhp('>= 8.0')]
1250-
public function testBug12944(): void
1259+
public function testBug7705(): void
12511260
{
12521261
$this->cliArgumentsVariablesRegistered = true;
12531262
$this->polluteScopeWithLoopInitialAssignments = true;
12541263
$this->checkMaybeUndefinedVariables = true;
12551264
$this->polluteScopeWithAlwaysIterableForeach = true;
12561265

1257-
$this->analyse([__DIR__ . '/data/bug-12944.php'], []);
1266+
$this->analyse([__DIR__ . '/data/bug-7705.php'], []);
12581267
}
12591268

12601269
#[RequiresPhp('>= 8.0')]
1261-
public function testBug13981(): void
1270+
public function testBug12944(): void
12621271
{
12631272
$this->cliArgumentsVariablesRegistered = true;
12641273
$this->polluteScopeWithLoopInitialAssignments = true;
12651274
$this->checkMaybeUndefinedVariables = true;
12661275
$this->polluteScopeWithAlwaysIterableForeach = true;
12671276

1268-
$this->analyse([__DIR__ . '/data/bug-13981.php'], []);
1277+
$this->analyse([__DIR__ . '/data/bug-12944.php'], []);
12691278
}
12701279

12711280
}

tests/PHPStan/Rules/Variables/data/bug-13981.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,49 @@ function foo(): string
1313

1414
return $path;
1515
}
16+
17+
function foo2(): string
18+
{
19+
if (rand(0, 1)) {
20+
$baseDir = '';
21+
}
22+
23+
$path = match (true) {
24+
is_dir($baseDir = dirname(__DIR__).'/lang') => $baseDir,
25+
default => '/translations',
26+
};
27+
28+
return $path;
29+
}
30+
31+
function foo3(): string
32+
{
33+
$path = match (true) {
34+
is_dir(dirname(__DIR__).'/lang2') => $baseDir,
35+
is_dir($baseDir = dirname(__DIR__).'/lang') => $baseDir,
36+
default => '/translations',
37+
};
38+
39+
return $path;
40+
}
41+
42+
function foo4(): string
43+
{
44+
$path = match (true) {
45+
is_dir(dirname(__DIR__).'/lang2'),
46+
is_dir($baseDir = dirname(__DIR__).'/lang') => $baseDir,
47+
default => '/translations',
48+
};
49+
50+
return $path;
51+
}
52+
53+
function foo5(): string
54+
{
55+
$path = match (true) {
56+
is_dir($baseDir = dirname(__DIR__).'/lang') => '$baseDir',
57+
default => $baseDir,
58+
};
59+
60+
return $path;
61+
}

0 commit comments

Comments
 (0)