7
7
use PHPStan \Reflection \FunctionReflection ;
8
8
use PHPStan \Type \Accessory \AccessoryArrayListType ;
9
9
use PHPStan \Type \Accessory \AccessoryLowercaseStringType ;
10
+ use PHPStan \Type \Accessory \AccessoryNonEmptyStringType ;
11
+ use PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
12
+ use PHPStan \Type \Accessory \AccessoryNumericStringType ;
10
13
use PHPStan \Type \Accessory \NonEmptyArrayType ;
11
14
use PHPStan \Type \ArrayType ;
12
15
use PHPStan \Type \Constant \ConstantArrayTypeBuilder ;
@@ -58,17 +61,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
58
61
$ newConstantArrayBuilder = ConstantArrayTypeBuilder::createEmpty ();
59
62
foreach ($ constantArray ->getKeyTypes () as $ i => $ keyType ) {
60
63
$ valueType = $ constantArray ->getOffsetValueType ($ keyType );
61
- if ($ keyType ->isString ()->yes ()) {
62
- if (!isset ($ case )) {
63
- $ keyType = TypeCombinator::union (
64
- new ConstantStringType (strtolower ((string ) $ keyType ->getValue ())),
65
- new ConstantStringType (strtoupper ((string ) $ keyType ->getValue ())),
66
- );
67
- } elseif ($ case === CASE_LOWER ) {
68
- $ keyType = new ConstantStringType (strtolower ((string ) $ keyType ->getValue ()));
69
- } else {
70
- $ keyType = new ConstantStringType (strtoupper ((string ) $ keyType ->getValue ()));
71
- }
64
+ if ($ keyType instanceof ConstantStringType) {
65
+ $ keyType = $ this ->mapConstantString ($ keyType , $ case );
72
66
}
73
67
74
68
$ newConstantArrayBuilder ->setOffsetValueType (
@@ -88,22 +82,30 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
88
82
} else {
89
83
$ keysType = $ arrayType ->getIterableKeyType ();
90
84
91
- $ keysType = TypeTraverser::map ($ keysType , static function (Type $ type , callable $ traverse ) use ($ case ): Type {
85
+ $ keysType = TypeTraverser::map ($ keysType , function (Type $ type , callable $ traverse ) use ($ case ): Type {
92
86
if ($ type instanceof UnionType) {
93
87
return $ traverse ($ type );
94
88
}
95
89
90
+ if ($ type instanceof ConstantStringType) {
91
+ return $ this ->mapConstantString ($ type , $ case );
92
+ }
93
+
96
94
if ($ type ->isString ()->yes ()) {
97
95
if ($ case === CASE_LOWER ) {
98
96
return TypeCombinator::intersect ($ type , new AccessoryLowercaseStringType ());
99
97
} elseif ($ type ->isLowercaseString ()->yes ()) {
100
- return TypeCombinator::intersect (
101
- new StringType (),
102
- ...array_filter (
103
- TypeUtils::getAccessoryTypes ($ type ),
104
- static fn (Type $ accessory ): bool => !$ accessory instanceof AccessoryLowercaseStringType,
105
- ),
106
- );
98
+ $ types = [new StringType ()];
99
+ if ($ type ->isNonFalsyString ()->yes ()) {
100
+ $ types [] = new AccessoryNonFalsyStringType ();
101
+ } elseif ($ type ->isNonEmptyString ()->yes ()) {
102
+ $ types [] = new AccessoryNonEmptyStringType ();
103
+ }
104
+ if ($ type ->isNumericString ()->yes ()) {
105
+ $ types [] = new AccessoryNumericStringType ();
106
+ }
107
+
108
+ return TypeCombinator::intersect (...$ types );
107
109
}
108
110
}
109
111
@@ -123,4 +125,18 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
123
125
return $ newArrayType ;
124
126
}
125
127
128
+ private function mapConstantString (ConstantStringType $ type , ?int $ case ): Type
129
+ {
130
+ if ($ case === CASE_LOWER ) {
131
+ return new ConstantStringType (strtolower ($ type ->getValue ()));
132
+ } elseif ($ case === CASE_UPPER ) {
133
+ return new ConstantStringType (strtoupper ($ type ->getValue ()));
134
+ } else {
135
+ return TypeCombinator::union (
136
+ new ConstantStringType (strtolower ($ type ->getValue ())),
137
+ new ConstantStringType (strtoupper ($ type ->getValue ())),
138
+ );
139
+ }
140
+ }
141
+
126
142
}
0 commit comments