77use PHPStan \Reflection \FunctionReflection ;
88use PHPStan \Type \Accessory \AccessoryArrayListType ;
99use PHPStan \Type \Accessory \AccessoryLowercaseStringType ;
10+ use PHPStan \Type \Accessory \AccessoryNonEmptyStringType ;
11+ use PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
12+ use PHPStan \Type \Accessory \AccessoryNumericStringType ;
1013use PHPStan \Type \Accessory \NonEmptyArrayType ;
1114use PHPStan \Type \ArrayType ;
1215use PHPStan \Type \Constant \ConstantArrayTypeBuilder ;
@@ -58,17 +61,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
5861 $ newConstantArrayBuilder = ConstantArrayTypeBuilder::createEmpty ();
5962 foreach ($ constantArray ->getKeyTypes () as $ i => $ keyType ) {
6063 $ 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 );
7266 }
7367
7468 $ newConstantArrayBuilder ->setOffsetValueType (
@@ -88,22 +82,30 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
8882 } else {
8983 $ keysType = $ arrayType ->getIterableKeyType ();
9084
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 {
9286 if ($ type instanceof UnionType) {
9387 return $ traverse ($ type );
9488 }
9589
90+ if ($ type instanceof ConstantStringType) {
91+ return $ this ->mapConstantString ($ type , $ case );
92+ }
93+
9694 if ($ type ->isString ()->yes ()) {
9795 if ($ case === CASE_LOWER ) {
9896 return TypeCombinator::intersect ($ type , new AccessoryLowercaseStringType ());
9997 } 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 );
107109 }
108110 }
109111
@@ -123,4 +125,18 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
123125 return $ newArrayType ;
124126 }
125127
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+
126142}
0 commit comments