66use PhpParser \Node \Expr ;
77use PHPStan \Analyser \MutatingScope ;
88use PHPStan \Analyser \Scope ;
9+ use PHPStan \Reflection \FunctionReflection ;
10+ use PHPStan \Reflection \MethodReflection ;
11+ use PHPStan \Reflection \ParameterReflection ;
912use PHPStan \Type \Type ;
1013
1114final class FiberScope extends MutatingScope
1215{
1316
17+ /** @var Expr[] */
18+ private array $ truthyValueExprs = [];
19+
20+ /** @var Expr[] */
21+ private array $ falseyValueExprs = [];
22+
1423 public function toFiberScope (): self
1524 {
1625 return $ this ;
@@ -46,10 +55,7 @@ public function getType(Expr $node): Type
4655 new BeforeScopeForExprRequest ($ node , $ this ),
4756 );
4857
49- $ scope = $ beforeScope ->toMutatingScope ();
50- if ($ this ->nativeTypesPromoted ) {
51- $ scope = $ scope ->doNotTreatPhpDocTypesAsCertain ();
52- }
58+ $ scope = $ this ->preprocessScope ($ beforeScope ->toMutatingScope ());
5359
5460 return $ scope ->getType ($ node );
5561 }
@@ -72,10 +78,7 @@ public function getNativeType(Expr $expr): Type
7278 new BeforeScopeForExprRequest ($ expr , $ this ),
7379 );
7480
75- $ scope = $ beforeScope ->toMutatingScope ();
76- if ($ this ->nativeTypesPromoted ) {
77- $ scope = $ scope ->doNotTreatPhpDocTypesAsCertain ();
78- }
81+ $ scope = $ this ->preprocessScope ($ beforeScope ->toMutatingScope ());
7982
8083 return $ scope ->getNativeType ($ expr );
8184 }
@@ -87,12 +90,70 @@ public function getKeepVoidType(Expr $node): Type
8790 new BeforeScopeForExprRequest ($ node , $ this ),
8891 );
8992
90- $ scope = $ beforeScope ->toMutatingScope ();
93+ $ scope = $ this ->preprocessScope ($ beforeScope ->toMutatingScope ());
94+
95+ return $ scope ->getKeepVoidType ($ node );
96+ }
97+
98+ public function filterByTruthyValue (Expr $ expr ): self
99+ {
100+ /** @var self $scope */
101+ $ scope = parent ::filterByTruthyValue ($ expr );
102+ $ scope ->truthyValueExprs = $ this ->truthyValueExprs ;
103+ $ scope ->truthyValueExprs [] = $ expr ;
104+
105+ return $ scope ;
106+ }
107+
108+ public function filterByFalseyValue (Expr $ expr ): self
109+ {
110+ /** @var self $scope */
111+ $ scope = parent ::filterByTruthyValue ($ expr );
112+ $ scope ->falseyValueExprs = $ this ->falseyValueExprs ;
113+ $ scope ->falseyValueExprs [] = $ expr ;
114+
115+ return $ scope ;
116+ }
117+
118+ private function preprocessScope (Scope $ scope ): Scope
119+ {
91120 if ($ this ->nativeTypesPromoted ) {
92121 $ scope = $ scope ->doNotTreatPhpDocTypesAsCertain ();
93122 }
94123
95- return $ scope ->getKeepVoidType ($ node );
124+ foreach ($ this ->truthyValueExprs as $ expr ) {
125+ $ scope = $ scope ->filterByTruthyValue ($ expr );
126+ }
127+ foreach ($ this ->falseyValueExprs as $ expr ) {
128+ $ scope = $ scope ->filterByFalseyValue ($ expr );
129+ }
130+
131+ return $ scope ;
132+ }
133+
134+ /**
135+ * @param MethodReflection|FunctionReflection|null $reflection
136+ */
137+ public function pushInFunctionCall ($ reflection , ?ParameterReflection $ parameter , bool $ rememberTypes ): self
138+ {
139+ // no need to track this in rules, the type will be correct anyway
140+ return $ this ;
141+ }
142+
143+ public function popInFunctionCall (): self
144+ {
145+ // no need to track this in rules, the type will be correct anyway
146+ return $ this ;
147+ }
148+
149+ public function getParentScope (): ?MutatingScope
150+ {
151+ $ parent = parent ::getParentScope ();
152+ if ($ parent === null ) {
153+ return null ;
154+ }
155+
156+ return $ parent ->toFiberScope ();
96157 }
97158
98159}
0 commit comments