9
9
use PHPStan \ShouldNotHappenException ;
10
10
use PHPStan \TrinaryLogic ;
11
11
use PHPStan \Type \CallableType ;
12
+ use PHPStan \Type \ConditionalType ;
13
+ use PHPStan \Type \ConditionalTypeForParameter ;
12
14
use PHPStan \Type \Constant \ConstantIntegerType ;
15
+ use PHPStan \Type \Generic \TemplateType ;
13
16
use PHPStan \Type \Generic \TemplateTypeMap ;
14
17
use PHPStan \Type \MixedType ;
15
18
use PHPStan \Type \NullType ;
16
19
use PHPStan \Type \Type ;
17
20
use PHPStan \Type \TypeCombinator ;
21
+ use PHPStan \Type \TypeTraverser ;
18
22
use PHPStan \Type \UnionType ;
19
23
use function array_key_last ;
20
24
use function array_slice ;
@@ -146,6 +150,13 @@ public static function selectFromArgs(
146
150
}
147
151
}
148
152
153
+ if (count ($ parametersAcceptors ) === 1 ) {
154
+ $ acceptor = $ parametersAcceptors [0 ];
155
+ if (!self ::hasAcceptorTemplateOrConditionalType ($ acceptor )) {
156
+ return $ acceptor ;
157
+ }
158
+ }
159
+
149
160
foreach ($ args as $ i => $ arg ) {
150
161
$ type = $ scope ->getType ($ arg ->value );
151
162
$ index = $ arg ->name !== null ? $ arg ->name ->toString () : $ i ;
@@ -160,6 +171,37 @@ public static function selectFromArgs(
160
171
return self ::selectFromTypes ($ types , $ parametersAcceptors , $ unpack );
161
172
}
162
173
174
+ private static function hasAcceptorTemplateOrConditionalType (ParametersAcceptor $ acceptor ): bool
175
+ {
176
+ if (self ::hasTemplateOrConditionalType ($ acceptor ->getReturnType ())) {
177
+ return true ;
178
+ }
179
+
180
+ foreach ($ acceptor ->getParameters () as $ parameter ) {
181
+ if (!self ::hasTemplateOrConditionalType ($ parameter ->getType ())) {
182
+ continue ;
183
+ }
184
+
185
+ return true ;
186
+ }
187
+
188
+ return false ;
189
+ }
190
+
191
+ private static function hasTemplateOrConditionalType (Type $ type ): bool
192
+ {
193
+ $ has = false ;
194
+ TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use (&$ has ): Type {
195
+ if ($ type instanceof TemplateType || $ type instanceof ConditionalType || $ type instanceof ConditionalTypeForParameter) {
196
+ $ has = true ;
197
+ return $ type ;
198
+ }
199
+
200
+ return $ traverse ($ type );
201
+ });
202
+
203
+ return $ has ;
204
+ }
163
205
/**
164
206
* @param array<int|string, Type> $types
165
207
* @param ParametersAcceptor[] $parametersAcceptors
0 commit comments