22
33namespace PHPStan \Type \Php ;
44
5- use Override ;
6- use PhpParser \Node ;
75use PhpParser \Node \Arg ;
86use PhpParser \Node \Expr ;
97use PhpParser \Node \Expr \ArrowFunction ;
1513use PhpParser \Node \Expr \Variable ;
1614use PhpParser \Node \Name ;
1715use PhpParser \Node \Stmt \Return_ ;
18- use PhpParser \NodeTraverser ;
19- use PhpParser \NodeVisitor \CloningVisitor ;
20- use PhpParser \NodeVisitorAbstract ;
16+ use PHPStan \Analyser \MutatingScope ;
2117use PHPStan \Analyser \Scope ;
2218use PHPStan \DependencyInjection \AutowiredService ;
23- use PHPStan \Node \Expr \IdentifiedTypeExpr ;
2419use PHPStan \Php \PhpVersion ;
2520use PHPStan \Reflection \ReflectionProvider ;
2621use PHPStan \ShouldNotHappenException ;
22+ use PHPStan \TrinaryLogic ;
2723use PHPStan \Type \ArrayType ;
2824use PHPStan \Type \BenevolentUnionType ;
2925use PHPStan \Type \Constant \ConstantArrayType ;
@@ -196,6 +192,10 @@ private function removeFalsey(Type $type): Type
196192
197193 private function filterByTruthyValue (Scope $ scope , Error |Variable |null $ itemVar , Type $ arrayType , Error |Variable |null $ keyVar , Expr $ expr ): Type
198194 {
195+ if (!$ scope instanceof MutatingScope) {
196+ throw new ShouldNotHappenException ();
197+ }
198+
199199 $ constantArrays = $ arrayType ->getConstantArrays ();
200200 if (count ($ constantArrays ) > 0 ) {
201201 $ results = [];
@@ -235,56 +235,24 @@ private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar,
235235 /**
236236 * @return array{Type, Type, bool}
237237 */
238- private function processKeyAndItemType (Scope $ scope , Type $ keyType , Type $ itemType , Error |Variable |null $ itemVar , Error |Variable |null $ keyVar , Expr $ expr ): array
238+ private function processKeyAndItemType (MutatingScope $ scope , Type $ keyType , Type $ itemType , Error |Variable |null $ itemVar , Error |Variable |null $ keyVar , Expr $ expr ): array
239239 {
240- $ itemTypeExpr = null ;
241- $ cloneTraverser = new NodeTraverser (new CloningVisitor ());
242- /** @var Expr $expr */
243- [$ expr ] = $ cloneTraverser ->traverse ([$ expr ]);
244-
245- $ changeTraverserFactory = static fn (string $ varName , IdentifiedTypeExpr $ typeExpr ) => new NodeTraverser (new class ($ varName , $ typeExpr ) extends NodeVisitorAbstract {
246-
247- public function __construct (private string $ varName , private IdentifiedTypeExpr $ typeExpr )
248- {
249- }
250-
251- #[Override]
252- public function leaveNode (Node $ node ): ?IdentifiedTypeExpr
253- {
254- $ node ->setAttribute ('phpstan_cache_printer ' , null );
255- if (!$ node instanceof Variable) {
256- return null ;
257- }
258- if ($ node ->name !== $ this ->varName ) {
259- return null ;
260- }
261-
262- return $ this ->typeExpr ;
263- }
264-
265- });
266-
240+ $ itemVarName = null ;
267241 if ($ itemVar !== null ) {
268242 if (!$ itemVar instanceof Variable || !is_string ($ itemVar ->name )) {
269243 throw new ShouldNotHappenException ();
270244 }
271- $ itemTypeExpr = new IdentifiedTypeExpr ($ itemType , $ itemVar );
272- $ changeTraverser = $ changeTraverserFactory ($ itemVar ->name , $ itemTypeExpr );
273-
274- /** @var Expr $expr */
275- [$ expr ] = $ changeTraverser ->traverse ([$ expr ]);
245+ $ itemVarName = $ itemVar ->name ;
246+ $ scope = $ scope ->assignVariable ($ itemVarName , $ itemType , new MixedType (), TrinaryLogic::createYes ());
276247 }
277248
278- $ keyTypeExpr = null ;
249+ $ keyVarName = null ;
279250 if ($ keyVar !== null ) {
280251 if (!$ keyVar instanceof Variable || !is_string ($ keyVar ->name )) {
281252 throw new ShouldNotHappenException ();
282253 }
283- $ keyTypeExpr = new IdentifiedTypeExpr ($ keyType , $ keyVar );
284- $ changeTraverser = $ changeTraverserFactory ($ keyVar ->name , $ keyTypeExpr );
285-
286- /** @var Expr $expr */
287- [$ expr ] = $ changeTraverser ->traverse ([$ expr ]);
254+ $ keyVarName = $ keyVar ->name ;
255+ $ scope = $ scope ->assignVariable ($ keyVarName , $ keyType , new MixedType (), TrinaryLogic::createYes ());
288256 }
289257
290258 $ booleanResult = $ scope ->getType ($ expr )->toBoolean ();
@@ -295,8 +263,8 @@ public function leaveNode(Node $node): ?IdentifiedTypeExpr
295263 $ scope = $ scope ->filterByTruthyValue ($ expr );
296264
297265 return [
298- $ keyTypeExpr !== null ? $ scope ->getType ( $ keyTypeExpr ) : $ keyType ,
299- $ itemTypeExpr !== null ? $ scope ->getType ( $ itemTypeExpr ) : $ itemType ,
266+ $ keyVarName !== null ? $ scope ->getVariableType ( $ keyVarName ) : $ keyType ,
267+ $ itemVarName !== null ? $ scope ->getVariableType ( $ itemVarName ) : $ itemType ,
300268 !$ booleanResult ->isTrue ()->yes (),
301269 ];
302270 }
0 commit comments