44
55use PhpParser \Node ;
66use PhpParser \Node \Expr ;
7+ use PHPStan \Analyser \NameScope ;
78use PHPStan \Analyser \Scope ;
89use PHPStan \Node \Expr \GetOffsetValueTypeExpr ;
910use PHPStan \PhpDoc \Tag \VarTag ;
11+ use PHPStan \PhpDoc \TypeNodeResolver ;
1012use PHPStan \Rules \IdentifierRuleError ;
1113use PHPStan \Rules \RuleErrorBuilder ;
14+ use PHPStan \TrinaryLogic ;
1215use PHPStan \Type \ArrayType ;
1316use PHPStan \Type \Generic \GenericObjectType ;
1417use PHPStan \Type \MixedType ;
2427final class VarTagTypeRuleHelper
2528{
2629
27- public function __construct (private bool $ checkTypeAgainstPhpDocType , private bool $ strictWideningCheck )
30+ public function __construct (
31+ private TypeNodeResolver $ typeNodeResolver ,
32+ private bool $ checkTypeAgainstPhpDocType ,
33+ private bool $ strictWideningCheck ,
34+ )
2835 {
2936 }
3037
@@ -134,15 +141,15 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
134141 $ type = new ArrayType (new MixedType (), new MixedType ());
135142 }
136143
137- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
144+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
138145 }
139146
140147 if ($ expr instanceof Expr \ConstFetch) {
141- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
148+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
142149 }
143150
144151 if ($ expr instanceof Node \Scalar) {
145- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
152+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
146153 }
147154
148155 if ($ expr instanceof Expr \New_) {
@@ -157,36 +164,43 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
157164 private function checkType (Type $ type , Type $ varTagType , int $ depth = 0 ): bool
158165 {
159166 if ($ this ->strictWideningCheck ) {
160- return !$ type -> isSuperTypeOf ( $ varTagType )->yes ();
167+ return !$ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->yes ();
161168 }
162169
163170 if ($ type ->isConstantArray ()->yes ()) {
164171 if ($ type ->isIterableAtLeastOnce ()->no ()) {
165172 $ type = new ArrayType (new MixedType (), new MixedType ());
166- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
173+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
167174 }
168175 }
169176
170177 if ($ type ->isIterable ()->yes () && $ varTagType ->isIterable ()->yes ()) {
171- if ($ type -> isSuperTypeOf ( $ varTagType )->no ()) {
178+ if ($ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ()) {
172179 return true ;
173180 }
174181
175182 $ innerType = $ type ->getIterableValueType ();
176183 $ innerVarTagType = $ varTagType ->getIterableValueType ();
177184
178185 if ($ type ->equals ($ innerType ) || $ varTagType ->equals ($ innerVarTagType )) {
179- return !$ innerType -> isSuperTypeOf ( $ innerVarTagType )->yes ();
186+ return !$ this -> isSuperTypeOfVarType ( $ innerType , $ innerVarTagType )->yes ();
180187 }
181188
182189 return $ this ->checkType ($ innerType , $ innerVarTagType , $ depth + 1 );
183190 }
184191
185- if ($ type ->isConstantValue ()->yes () && $ depth === 0 ) {
186- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
192+ if ($ depth === 0 && $ type ->isConstantValue ()->yes ()) {
193+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
187194 }
188195
189- return !$ type ->isSuperTypeOf ($ varTagType )->yes ();
196+ return !$ this ->isSuperTypeOfVarType ($ type , $ varTagType )->yes ();
197+ }
198+
199+ private function isSuperTypeOfVarType (Type $ type , Type $ varTagType ): TrinaryLogic
200+ {
201+ $ type = $ this ->typeNodeResolver ->resolve ($ type ->toPhpDocNode (), new NameScope (null , []));
202+
203+ return $ type ->isSuperTypeOf ($ varTagType );
190204 }
191205
192206}
0 commit comments