Skip to content

Commit 418ecc5

Browse files
staabmphpstan-bot
authored andcommitted
Fix assignment inside match arm condition not recognized
- Variable assignments in match arm conditions (e.g. `is_dir($baseDir = ...)`) were lost after commit 3beb8c6 replaced processExprNode with filterByTruthyValue - filterByTruthyValue only narrows types without walking the AST, so assignments within condition expressions were not discovered for the arm body scope - Fix transfers newly-defined variables from the condition processing scope to the body scope after applying truthiness filtering - New regression test in tests/PHPStan/Rules/Variables/data/bug-13981.php Closes phpstan/phpstan#13981
1 parent 925f29c commit 418ecc5

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
use UnhandledMatchError;
209209
use function array_fill_keys;
210210
use function array_filter;
211+
use function array_flip;
211212
use function array_key_exists;
212213
use function array_key_last;
213214
use function array_keys;
@@ -4386,6 +4387,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
43864387
$filteringExprs = [];
43874388
$armCondScope = $matchScope;
43884389
$condNodes = [];
4390+
$armCondResultScope = $matchScope;
43894391
foreach ($arm->conds as $j => $armCond) {
43904392
if (isset($armCondsToSkip[$i][$j])) {
43914393
continue;
@@ -4407,6 +4409,30 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
44074409

44084410
$filteringExpr = $this->getFilteringExprForMatchArm($expr, $filteringExprs);
44094411
$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+
}
44104436
$matchArmBody = new MatchExpressionArmBody($bodyScope, $arm->body);
44114437
$armNodes[$i] = new MatchExpressionArm($matchArmBody, $condNodes, $arm->getStartLine());
44124438

tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,4 +1257,15 @@ public function testBug12944(): void
12571257
$this->analyse([__DIR__ . '/data/bug-12944.php'], []);
12581258
}
12591259

1260+
#[RequiresPhp('>= 8.0')]
1261+
public function testBug13981(): void
1262+
{
1263+
$this->cliArgumentsVariablesRegistered = true;
1264+
$this->polluteScopeWithLoopInitialAssignments = true;
1265+
$this->checkMaybeUndefinedVariables = true;
1266+
$this->polluteScopeWithAlwaysIterableForeach = true;
1267+
1268+
$this->analyse([__DIR__ . '/data/bug-13981.php'], []);
1269+
}
1270+
12601271
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug13981;
6+
7+
function foo(): string
8+
{
9+
$path = match (true) {
10+
is_dir($baseDir = dirname(__DIR__).'/lang') => $baseDir,
11+
default => '/translations',
12+
};
13+
14+
return $path;
15+
}

0 commit comments

Comments
 (0)