Skip to content

Commit 65b60be

Browse files
authored
Merge branch refs/heads/1.12.x into 2.0.x
2 parents 1b4997e + 5f064dd commit 65b60be

File tree

3 files changed

+61
-11
lines changed

3 files changed

+61
-11
lines changed

src/Analyser/MutatingScope.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
use PHPStan\Node\Printer\ExprPrinter;
4545
use PHPStan\Node\PropertyAssignNode;
4646
use PHPStan\Parser\ArrayMapArgVisitor;
47-
use PHPStan\Parser\ImmediatelyInvokedClosureVisitor;
4847
use PHPStan\Parser\NewAssignedToPropertyVisitor;
4948
use PHPStan\Parser\Parser;
5049
use PHPStan\Php\PhpVersion;
@@ -4760,7 +4759,6 @@ private function processFinallyScopeVariableTypeHolders(
47604759
* @param Node\ClosureUse[] $byRefUses
47614760
*/
47624761
public function processClosureScope(
4763-
Expr\Closure $expr,
47644762
self $closureScope,
47654763
?self $prevScope,
47664764
array $byRefUses,
@@ -4793,9 +4791,7 @@ public function processClosureScope(
47934791
$prevVariableType = $prevScope->getVariableType($variableName);
47944792
if (!$variableType->equals($prevVariableType)) {
47954793
$variableType = TypeCombinator::union($variableType, $prevVariableType);
4796-
if ($expr->getAttribute(ImmediatelyInvokedClosureVisitor::ATTRIBUTE_NAME) !== true) {
4797-
$variableType = self::generalizeType($variableType, $prevVariableType, 0);
4798-
}
4794+
$variableType = self::generalizeType($variableType, $prevVariableType, 0);
47994795
}
48004796
}
48014797

src/Analyser/NodeScopeResolver.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
use PHPStan\Node\VarTagChangedExpressionTypeNode;
119119
use PHPStan\Parser\ArrowFunctionArgVisitor;
120120
use PHPStan\Parser\ClosureArgVisitor;
121+
use PHPStan\Parser\ImmediatelyInvokedClosureVisitor;
121122
use PHPStan\Parser\Parser;
122123
use PHPStan\Php\PhpVersion;
123124
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
@@ -4228,7 +4229,7 @@ private function processClosureNode(
42284229
}
42294230

42304231
$closureScope = $scope->enterAnonymousFunction($expr, $callableParameters);
4231-
$closureScope = $closureScope->processClosureScope($expr, $scope, null, $byRefUses);
4232+
$closureScope = $closureScope->processClosureScope($scope, null, $byRefUses);
42324233
$closureType = $closureScope->getAnonymousFunctionReflection();
42334234
if (!$closureType instanceof ClosureType) {
42344235
throw new ShouldNotHappenException();
@@ -4273,6 +4274,7 @@ private function processClosureNode(
42734274

42744275
$gatheredReturnStatements[] = new ReturnStatement($scope, $node);
42754276
};
4277+
42764278
if (count($byRefUses) === 0) {
42774279
$statementResult = $this->processStmtNodes($expr, $expr->stmts, $closureScope, $closureStmtsCallback, StatementContext::createTopLevel());
42784280
$nodeCallback(new ClosureReturnStatementsNode(
@@ -4288,6 +4290,7 @@ private function processClosureNode(
42884290
}
42894291

42904292
$count = 0;
4293+
$closureResultScope = null;
42914294
do {
42924295
$prevScope = $closureScope;
42934296

@@ -4297,8 +4300,15 @@ private function processClosureNode(
42974300
foreach ($intermediaryClosureScopeResult->getExitPoints() as $exitPoint) {
42984301
$intermediaryClosureScope = $intermediaryClosureScope->mergeWith($exitPoint->getScope());
42994302
}
4303+
4304+
if ($expr->getAttribute(ImmediatelyInvokedClosureVisitor::ATTRIBUTE_NAME) === true) {
4305+
$closureResultScope = $intermediaryClosureScope;
4306+
break;
4307+
}
4308+
43004309
$closureScope = $scope->enterAnonymousFunction($expr, $callableParameters);
4301-
$closureScope = $closureScope->processClosureScope($expr, $intermediaryClosureScope, $prevScope, $byRefUses);
4310+
$closureScope = $closureScope->processClosureScope($intermediaryClosureScope, $prevScope, $byRefUses);
4311+
43024312
if ($closureScope->equals($prevScope)) {
43034313
break;
43044314
}
@@ -4308,6 +4318,10 @@ private function processClosureNode(
43084318
$count++;
43094319
} while ($count < self::LOOP_SCOPE_ITERATIONS);
43104320

4321+
if ($closureResultScope === null) {
4322+
$closureResultScope = $closureScope;
4323+
}
4324+
43114325
$statementResult = $this->processStmtNodes($expr, $expr->stmts, $closureScope, $closureStmtsCallback, StatementContext::createTopLevel());
43124326
$nodeCallback(new ClosureReturnStatementsNode(
43134327
$expr,
@@ -4318,7 +4332,7 @@ private function processClosureNode(
43184332
array_merge($statementResult->getImpurePoints(), $closureImpurePoints),
43194333
), $closureScope);
43204334

4321-
return new ProcessClosureResult($scope->processClosureScope($expr, $closureScope, null, $byRefUses), $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
4335+
return new ProcessClosureResult($scope->processClosureScope($closureResultScope, null, $byRefUses), $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
43224336
}
43234337

43244338
/**

tests/PHPStan/Analyser/nsrt/bug-11561.php

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ function main(mixed $c): void{
1212
assertType('array{date: DateTime, id: 1}', $c);
1313

1414
$x = (function() use (&$c) {
15-
assertType("array{date: DateTime, id: 1, name?: 'ruud'}", $c);
15+
assertType("array{date: DateTime, id: 1}", $c);
1616
$c['name'] = 'ruud';
1717
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
1818
return 'x';
1919
})();
2020

21-
assertType("array{date: DateTime, id: 1, name?: 'ruud'}", $c);
21+
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
2222
}
2323

2424

@@ -30,11 +30,51 @@ function main2(mixed $c): void{
3030
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
3131

3232
$x = (function() use (&$c) {
33-
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
33+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
3434
$c['name'] = 'ruud';
3535
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
3636
return 'x';
3737
})();
3838

39+
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
40+
}
41+
42+
/** @param array{date: DateTime} $c */
43+
function main3(mixed $c): void{
44+
assertType('array{date: DateTime}', $c);
45+
$c['id']=1;
46+
$c['name'] = 'staabm';
47+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
48+
49+
$x = (function() use (&$c) {
50+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
51+
if (rand(0,1)) {
52+
$c['name'] = 'ruud';
53+
}
54+
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
55+
return 'x';
56+
})();
57+
58+
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
59+
}
60+
61+
/** @param array{date: DateTime} $c */
62+
function main4(mixed $c): void{
63+
assertType('array{date: DateTime}', $c);
64+
$c['id']=1;
65+
$c['name'] = 'staabm';
66+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
67+
68+
$x = (function() use (&$c) {
69+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
70+
if (rand(0,1)) {
71+
$c['name'] = 'ruud';
72+
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
73+
return 'y';
74+
}
75+
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
76+
return 'x';
77+
})();
78+
3979
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
4080
}

0 commit comments

Comments
 (0)