8
8
use PHPStan \Reflection \FunctionReflection ;
9
9
use PHPStan \Reflection \ReflectionProvider ;
10
10
use PHPStan \ShouldNotHappenException ;
11
+ use PHPStan \TrinaryLogic ;
11
12
use PHPStan \Type \Accessory \AccessoryNonEmptyStringType ;
12
13
use PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
13
14
use PHPStan \Type \ArrayType ;
14
15
use PHPStan \Type \BooleanType ;
15
- use PHPStan \Type \Constant \ConstantArrayType ;
16
16
use PHPStan \Type \Constant \ConstantBooleanType ;
17
17
use PHPStan \Type \Constant \ConstantIntegerType ;
18
18
use PHPStan \Type \Constant \ConstantStringType ;
19
19
use PHPStan \Type \ConstantScalarType ;
20
20
use PHPStan \Type \DynamicFunctionReturnTypeExtension ;
21
- use PHPStan \Type \ErrorType ;
22
21
use PHPStan \Type \FloatType ;
23
22
use PHPStan \Type \IntegerRangeType ;
24
23
use PHPStan \Type \IntegerType ;
27
26
use PHPStan \Type \StringType ;
28
27
use PHPStan \Type \Type ;
29
28
use PHPStan \Type \TypeCombinator ;
29
+ use function array_merge ;
30
30
use function hexdec ;
31
31
use function is_int ;
32
32
use function octdec ;
@@ -160,8 +160,8 @@ public function getTypeFromFunctionCall(
160
160
$ exactType = $ this ->determineExactType ($ inputType , $ filterValue , $ defaultType , $ flagsType );
161
161
$ type = $ exactType ?? $ this ->getFilterTypeMap ()[$ filterValue ] ?? $ mixedType ;
162
162
163
- $ typeOptionNames = $ this ->getFilterTypeOptions ()[ $ filterValue] ?? [];
164
- $ otherTypes = $ this ->getOtherTypes ($ flagsType , $ typeOptionNames , $ defaultType );
163
+ $ options = $ flagsType !== null && $ this ->hasOptions ( $ flagsType )-> yes () ? $ this -> getOptions ( $ flagsType , $ filterValue) : [];
164
+ $ otherTypes = $ this ->getOtherTypes ($ flagsType , $ options , $ defaultType );
165
165
166
166
if ($ inputType ->isNonEmptyString ()->yes ()
167
167
&& $ type ->isString ()->yes ()
@@ -234,17 +234,16 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
234
234
}
235
235
236
236
/**
237
- * @param list <string> $typeOptionNames
237
+ * @param array <string, ?Type > $typeOptions
238
238
* @return array{default: Type, range?: Type}
239
239
*/
240
- private function getOtherTypes (?Type $ flagsType , array $ typeOptionNames , Type $ defaultType ): array
240
+ private function getOtherTypes (?Type $ flagsType , array $ typeOptions , Type $ defaultType ): array
241
241
{
242
242
$ falseType = new ConstantBooleanType (false );
243
243
if ($ flagsType === null ) {
244
244
return ['default ' => $ falseType ];
245
245
}
246
246
247
- $ typeOptions = $ this ->getOptions ($ flagsType , 'default ' , ...$ typeOptionNames );
248
247
$ defaultType = $ typeOptions ['default ' ] ?? $ defaultType ;
249
248
$ otherTypes = ['default ' => $ defaultType ];
250
249
$ range = [];
@@ -272,25 +271,31 @@ private function getOtherTypes(?Type $flagsType, array $typeOptionNames, Type $d
272
271
return $ otherTypes ;
273
272
}
274
273
275
- /**
276
- * @return array<string, ?Type>
277
- */
278
- private function getOptions (Type $ flagsType , string ...$ optionNames ): array
274
+ private function hasOptions (Type $ flagsType ): TrinaryLogic
279
275
{
280
- $ options = [];
276
+ return $ flagsType ->isConstantArray ()
277
+ ->and ($ flagsType ->hasOffsetValueType (new ConstantStringType ('options ' )));
278
+ }
281
279
282
- if (!$ flagsType instanceof ConstantArrayType) {
283
- return $ options ;
284
- }
280
+ /** @return array<string, ?Type> */
281
+ private function getOptions (Type $ flagsType , int $ filterValue ): array
282
+ {
283
+ $ options = [];
285
284
286
285
$ optionsType = $ flagsType ->getOffsetValueType (new ConstantStringType ('options ' ));
287
- if (!$ optionsType instanceof ConstantArrayType ) {
286
+ if (!$ optionsType-> isConstantArray ()-> yes () ) {
288
287
return $ options ;
289
288
}
290
289
290
+ $ optionNames = array_merge (['default ' ], $ this ->getFilterTypeOptions ()[$ filterValue ] ?? []);
291
291
foreach ($ optionNames as $ optionName ) {
292
- $ type = $ optionsType ->getOffsetValueType (new ConstantStringType ($ optionName ));
293
- $ options [$ optionName ] = $ type instanceof ErrorType ? null : $ type ;
292
+ $ optionaNameType = new ConstantStringType ($ optionName );
293
+ if (!$ optionsType ->hasOffsetValueType ($ optionaNameType )->yes ()) {
294
+ $ options [$ optionName ] = null ;
295
+ continue ;
296
+ }
297
+
298
+ $ options [$ optionName ] = $ optionsType ->getOffsetValueType ($ optionaNameType );
294
299
}
295
300
296
301
return $ options ;
@@ -309,7 +314,7 @@ private function hasFlag(int $flag, ?Type $flagsType): bool
309
314
310
315
private function getFlagsValue (Type $ exprType ): Type
311
316
{
312
- if (!$ exprType instanceof ConstantArrayType ) {
317
+ if (!$ exprType-> isConstantArray ()-> yes () ) {
313
318
return $ exprType ;
314
319
}
315
320
0 commit comments