Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
use PHPStan\Node\Printer\ExprPrinter;
use PHPStan\Node\PropertyAssignNode;
use PHPStan\Parser\ArrayMapArgVisitor;
use PHPStan\Parser\ImmediatelyInvokedClosureVisitor;
use PHPStan\Parser\NewAssignedToPropertyVisitor;
use PHPStan\Parser\Parser;
use PHPStan\Php\PhpVersion;
Expand Down Expand Up @@ -4795,7 +4794,6 @@ private function processFinallyScopeVariableTypeHolders(
* @param Expr\ClosureUse[] $byRefUses
*/
public function processClosureScope(
Expr\Closure $expr,
self $closureScope,
?self $prevScope,
array $byRefUses,
Expand Down Expand Up @@ -4828,9 +4826,7 @@ public function processClosureScope(
$prevVariableType = $prevScope->getVariableType($variableName);
if (!$variableType->equals($prevVariableType)) {
$variableType = TypeCombinator::union($variableType, $prevVariableType);
if ($expr->getAttribute(ImmediatelyInvokedClosureVisitor::ATTRIBUTE_NAME) !== true) {
$variableType = self::generalizeType($variableType, $prevVariableType, 0);
}
$variableType = self::generalizeType($variableType, $prevVariableType, 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this file we effectively revert 8fbcf5b

}
}

Expand Down
25 changes: 22 additions & 3 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
use PHPStan\Node\VarTagChangedExpressionTypeNode;
use PHPStan\Parser\ArrowFunctionArgVisitor;
use PHPStan\Parser\ClosureArgVisitor;
use PHPStan\Parser\ImmediatelyInvokedClosureVisitor;
use PHPStan\Parser\Parser;
use PHPStan\Php\PhpVersion;
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
Expand Down Expand Up @@ -4232,7 +4233,7 @@ private function processClosureNode(
}

$closureScope = $scope->enterAnonymousFunction($expr, $callableParameters);
$closureScope = $closureScope->processClosureScope($expr, $scope, null, $byRefUses);
$closureScope = $closureScope->processClosureScope($scope, null, $byRefUses);
$closureType = $closureScope->getAnonymousFunctionReflection();
if (!$closureType instanceof ClosureType) {
throw new ShouldNotHappenException();
Expand Down Expand Up @@ -4291,6 +4292,24 @@ private function processClosureNode(
return new ProcessClosureResult($scope, $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
}

if ($expr->getAttribute(ImmediatelyInvokedClosureVisitor::ATTRIBUTE_NAME) === true) {
$intermediaryClosureScopeResult = $this->processStmtNodes($expr, $expr->stmts, $closureScope, static function (): void {
}, StatementContext::createTopLevel());
$intermediaryClosureScope = $intermediaryClosureScopeResult->getScope();

$statementResult = $this->processStmtNodes($expr, $expr->stmts, $closureScope, $closureStmtsCallback, StatementContext::createTopLevel());
$nodeCallback(new ClosureReturnStatementsNode(
$expr,
$gatheredReturnStatements,
$gatheredYieldStatements,
$statementResult,
$executionEnds,
array_merge($statementResult->getImpurePoints(), $closureImpurePoints),
), $closureScope);

return new ProcessClosureResult($scope->processClosureScope($intermediaryClosureScope, null, $byRefUses), $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
Copy link
Contributor Author

@staabm staabm Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case we agree this fix is correct, I think we should add new tests for IIFE regarding impure-points and throw-points

}

$count = 0;
do {
$prevScope = $closureScope;
Expand All @@ -4302,7 +4321,7 @@ private function processClosureNode(
$intermediaryClosureScope = $intermediaryClosureScope->mergeWith($exitPoint->getScope());
}
$closureScope = $scope->enterAnonymousFunction($expr, $callableParameters);
$closureScope = $closureScope->processClosureScope($expr, $intermediaryClosureScope, $prevScope, $byRefUses);
$closureScope = $closureScope->processClosureScope($intermediaryClosureScope, $prevScope, $byRefUses);
if ($closureScope->equals($prevScope)) {
break;
}
Expand All @@ -4322,7 +4341,7 @@ private function processClosureNode(
array_merge($statementResult->getImpurePoints(), $closureImpurePoints),
), $closureScope);

return new ProcessClosureResult($scope->processClosureScope($expr, $closureScope, null, $byRefUses), $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
return new ProcessClosureResult($scope->processClosureScope($closureScope, null, $byRefUses), $statementResult->getThrowPoints(), $statementResult->getImpurePoints(), $invalidateExpressions);
}

/**
Expand Down
25 changes: 22 additions & 3 deletions tests/PHPStan/Analyser/nsrt/bug-11561.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ function main(mixed $c): void{
assertType('array{date: DateTime, id: 1}', $c);

$x = (function() use (&$c) {
assertType("array{date: DateTime, id: 1, name?: 'ruud'}", $c);
assertType("array{date: DateTime, id: 1}", $c);
$c['name'] = 'ruud';
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
return 'x';
})();

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


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

$x = (function() use (&$c) {
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
$c['name'] = 'ruud';
assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
return 'x';
})();

assertType("array{date: DateTime, id: 1, name: 'ruud'}", $c);
}

/** @param array{date: DateTime} $c */
function main3(mixed $c): void{
assertType('array{date: DateTime}', $c);
$c['id']=1;
$c['name'] = 'staabm';
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);

$x = (function() use (&$c) {
assertType("array{date: DateTime, id: 1, name: 'staabm'}", $c);
if (rand(0,1)) {
$c['name'] = 'ruud';
}
assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
return 'x';
})();

assertType("array{date: DateTime, id: 1, name: 'ruud'|'staabm'}", $c);
}
Loading