Skip to content

Commit 2a92c7b

Browse files
committed
Defer invalidating expressions after all args are processed
1 parent c7ad25b commit 2a92c7b

3 files changed

Lines changed: 50 additions & 2 deletions

File tree

src/Analyser/NodeScopeResolver.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5549,6 +5549,8 @@ private function processArgs(
55495549
$throwPoints = [];
55505550
$impurePoints = [];
55515551
$isAlwaysTerminating = false;
5552+
/** @var list<array{InvalidateExprNode[], string[]}> $deferredInvalidateExpressions */
5553+
$deferredInvalidateExpressions = [];
55525554
foreach ($args as $i => $arg) {
55535555
$assignByReference = false;
55545556
$parameter = null;
@@ -5676,7 +5678,7 @@ private function processArgs(
56765678
$scope = $scope->restoreThis($restoreThisScope);
56775679
}
56785680

5679-
$scope = $this->processImmediatelyCalledCallable($scope, $invalidateExpressions, $uses);
5681+
$deferredInvalidateExpressions[] = [$invalidateExpressions, $uses];
56805682
} elseif ($arg->value instanceof Expr\ArrowFunction) {
56815683
if (
56825684
$closureBindScope === null
@@ -5717,7 +5719,7 @@ private function processArgs(
57175719
if ($exprType->isCallable()->yes()) {
57185720
$acceptors = $exprType->getCallableParametersAcceptors($scope);
57195721
if (count($acceptors) === 1) {
5720-
$scope = $this->processImmediatelyCalledCallable($scope, $acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables());
5722+
$deferredInvalidateExpressions[] = [$acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables()];
57215723
if ($this->callCallbackImmediately($parameter, $parameterType, $calleeReflection)) {
57225724
$callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : InternalThrowPoint::createImplicit($scope, $arg->value), $acceptors[0]->getThrowPoints());
57235725
if (!$this->implicitThrows) {
@@ -5747,6 +5749,10 @@ private function processArgs(
57475749
$scope = $scope->restoreOriginalScopeAfterClosureBind($originalScope);
57485750
}
57495751

5752+
foreach ($deferredInvalidateExpressions as [$invalidateExpressions, $uses]) {
5753+
$scope = $this->processImmediatelyCalledCallable($scope, $invalidateExpressions, $uses);
5754+
}
5755+
57505756
if ($parameters !== null) {
57515757
foreach ($args as $i => $arg) {
57525758
$assignByReference = false;

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3817,4 +3817,14 @@ public function testBug13993b(): void
38173817
$this->analyse([__DIR__ . '/../../Analyser/nsrt/closure-passed-to-type-fiberscope-php81.php'], []);
38183818
}
38193819

3820+
public function testDiscussion14038(): void
3821+
{
3822+
$this->checkThisOnly = false;
3823+
$this->checkNullables = true;
3824+
$this->checkUnionTypes = true;
3825+
$this->checkExplicitMixed = true;
3826+
$this->checkImplicitMixed = true;
3827+
$this->analyse([__DIR__ . '/data/discussion-14038.php'], []);
3828+
}
3829+
38203830
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Discussion14038;
4+
5+
use DateTime;
6+
use Exception;
7+
8+
class HelloWorld
9+
{
10+
private ?DateTime $d = null;
11+
12+
private function clo(callable $c, DateTime $d): void
13+
{
14+
}
15+
16+
protected function redirect(): void
17+
{
18+
}
19+
20+
public function sayHello(): void
21+
{
22+
if ($this->d === null) {
23+
throw new Exception;
24+
}
25+
$this->clo(
26+
function(): void {
27+
$this->redirect();
28+
},
29+
$this->d,
30+
);
31+
}
32+
}

0 commit comments

Comments
 (0)