18
18
use PHPStan \Php \PhpVersion ;
19
19
use PHPStan \ShouldNotHappenException ;
20
20
use PHPStan \TrinaryLogic ;
21
+ use PHPStan \Type \Accessory \AccessoryLowercaseStringType ;
21
22
use PHPStan \Type \Accessory \AccessoryNumericStringType ;
23
+ use PHPStan \Type \Accessory \AccessoryUppercaseStringType ;
22
24
use PHPStan \Type \ArrayType ;
23
25
use PHPStan \Type \BooleanType ;
24
26
use PHPStan \Type \Constant \ConstantBooleanType ;
@@ -630,10 +632,10 @@ public function walkFunction($function): string
630
632
$ type = $ this ->createFloat (false );
631
633
632
634
} elseif ($ castedExprType ->isNumericString ()->yes ()) {
633
- $ type = $ this ->createNumericString (false );
635
+ $ type = $ this ->createNumericString (false , $ castedExprType -> isLowercaseString ()-> yes (), $ castedExprType -> isUppercaseString ()-> yes () );
634
636
635
637
} else {
636
- $ type = TypeCombinator::union ($ this ->createFloat (false ), $ this ->createNumericString (false ));
638
+ $ type = TypeCombinator::union ($ this ->createFloat (false ), $ this ->createNumericString (false , false , true ));
637
639
}
638
640
639
641
} else {
@@ -746,7 +748,7 @@ private function inferAvgFunction(AST\Functions\AvgFunction $function): Type
746
748
747
749
if ($ this ->driverType === DriverDetector::PDO_MYSQL || $ this ->driverType === DriverDetector::MYSQLI ) {
748
750
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
749
- return $ this ->createNumericString ($ nullable );
751
+ return $ this ->createNumericString ($ nullable, true , true );
750
752
}
751
753
752
754
if ($ exprTypeNoNull ->isString ()->yes () && !$ exprTypeNoNull ->isNumericString ()->yes ()) {
@@ -758,7 +760,7 @@ private function inferAvgFunction(AST\Functions\AvgFunction $function): Type
758
760
759
761
if ($ this ->driverType === DriverDetector::PGSQL || $ this ->driverType === DriverDetector::PDO_PGSQL ) {
760
762
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
761
- return $ this ->createNumericString ($ nullable );
763
+ return $ this ->createNumericString ($ nullable, true , true );
762
764
}
763
765
764
766
return $ this ->generalizeConstantType ($ exprType , $ nullable );
@@ -794,7 +796,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type
794
796
795
797
if ($ this ->driverType === DriverDetector::PDO_MYSQL || $ this ->driverType === DriverDetector::MYSQLI ) {
796
798
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
797
- return $ this ->createNumericString ($ nullable );
799
+ return $ this ->createNumericString ($ nullable, true , true );
798
800
}
799
801
800
802
if ($ exprTypeNoNull ->isString ()->yes () && !$ exprTypeNoNull ->isNumericString ()->yes ()) {
@@ -808,7 +810,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type
808
810
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
809
811
return TypeCombinator::union (
810
812
$ this ->createInteger ($ nullable ),
811
- $ this ->createNumericString ($ nullable )
813
+ $ this ->createNumericString ($ nullable, true , true )
812
814
);
813
815
}
814
816
@@ -845,19 +847,41 @@ private function createNonNegativeInteger(bool $nullable): Type
845
847
return $ nullable ? TypeCombinator::addNull ($ integer ) : $ integer ;
846
848
}
847
849
848
- private function createNumericString (bool $ nullable ): Type
850
+ private function createNumericString (bool $ nullable, bool $ lowercase = false , bool $ uppercase = false ): Type
849
851
{
850
- $ numericString = TypeCombinator:: intersect (
852
+ $ types = [
851
853
new StringType (),
852
- new AccessoryNumericStringType ()
853
- );
854
+ new AccessoryNumericStringType (),
855
+ ];
856
+ if ($ lowercase ) {
857
+ $ types [] = new AccessoryLowercaseStringType ();
858
+ }
859
+ if ($ uppercase ) {
860
+ $ types [] = new AccessoryUppercaseStringType ();
861
+ }
862
+
863
+ $ numericString = new IntersectionType ($ types );
854
864
855
865
return $ nullable ? TypeCombinator::addNull ($ numericString ) : $ numericString ;
856
866
}
857
867
858
- private function createString (bool $ nullable ): Type
868
+ private function createString (bool $ nullable, bool $ lowercase = false , bool $ uppercase = false ): Type
859
869
{
860
- $ string = new StringType ();
870
+ if ($ lowercase || $ uppercase ) {
871
+ $ types = [
872
+ new StringType (),
873
+ ];
874
+ if ($ lowercase ) {
875
+ $ types [] = new AccessoryLowercaseStringType ();
876
+ }
877
+ if ($ uppercase ) {
878
+ $ types [] = new AccessoryUppercaseStringType ();
879
+ }
880
+ $ string = new IntersectionType ($ types );
881
+ } else {
882
+ $ string = new StringType ();
883
+ }
884
+
861
885
return $ nullable ? TypeCombinator::addNull ($ string ) : $ string ;
862
886
}
863
887
@@ -903,10 +927,18 @@ private function generalizeConstantType(Type $type, bool $makeNullable): Type
903
927
$ result = $ this ->createFloat ($ containsNull );
904
928
905
929
} elseif ($ typeNoNull ->isNumericString ()->yes ()) {
906
- $ result = $ this ->createNumericString ($ containsNull );
930
+ $ result = $ this ->createNumericString (
931
+ $ containsNull ,
932
+ $ typeNoNull ->isLowercaseString ()->yes (),
933
+ $ typeNoNull ->isUppercaseString ()->yes ()
934
+ );
907
935
908
936
} elseif ($ typeNoNull ->isString ()->yes ()) {
909
- $ result = $ this ->createString ($ containsNull );
937
+ $ result = $ this ->createString (
938
+ $ containsNull ,
939
+ $ typeNoNull ->isLowercaseString ()->yes (),
940
+ $ typeNoNull ->isUppercaseString ()->yes ()
941
+ );
910
942
911
943
} else {
912
944
$ result = $ type ;
@@ -1249,7 +1281,7 @@ public function walkSelectExpression($selectExpression): string
1249
1281
1250
1282
// e.g. 1.0 on sqlite results to '1' with pdo_stringify on PHP 8.1, but '1.0' on PHP 8.0 with no setup
1251
1283
// so we relax constant types and return just numeric-string to avoid those issues
1252
- $ stringifiedFloat = $ this ->createNumericString (false );
1284
+ $ stringifiedFloat = $ this ->createNumericString (false , false , true );
1253
1285
1254
1286
if ($ stringify ->yes ()) {
1255
1287
return $ stringifiedFloat ;
@@ -1781,7 +1813,11 @@ private function inferPlusMinusTimesType(array $termTypes): Type
1781
1813
}
1782
1814
1783
1815
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), $ this ->createNumericString (false )])) {
1784
- return $ this ->createNumericString ($ nullable );
1816
+ return $ this ->createNumericString (
1817
+ $ nullable ,
1818
+ $ unionWithoutNull ->toString ()->isLowercaseString ()->yes (),
1819
+ $ unionWithoutNull ->toString ()->isUppercaseString ()->yes ()
1820
+ );
1785
1821
}
1786
1822
1787
1823
if ($ this ->containsOnlyNumericTypes ($ unionWithoutNull )) {
@@ -1833,7 +1869,7 @@ private function inferDivisionType(array $termTypes): Type
1833
1869
1834
1870
if ($ unionWithoutNull ->isInteger ()->yes ()) {
1835
1871
if ($ this ->driverType === DriverDetector::MYSQLI || $ this ->driverType === DriverDetector::PDO_MYSQL ) {
1836
- return $ this ->createNumericString ($ nullable );
1872
+ return $ this ->createNumericString ($ nullable, true , true );
1837
1873
} elseif ($ this ->driverType === DriverDetector::PDO_PGSQL || $ this ->driverType === DriverDetector::PGSQL || $ this ->driverType === DriverDetector::SQLITE3 || $ this ->driverType === DriverDetector::PDO_SQLITE ) {
1838
1874
return $ this ->createInteger ($ nullable );
1839
1875
}
@@ -1861,7 +1897,11 @@ private function inferDivisionType(array $termTypes): Type
1861
1897
}
1862
1898
1863
1899
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), $ this ->createNumericString (false )])) {
1864
- return $ this ->createNumericString ($ nullable );
1900
+ return $ this ->createNumericString (
1901
+ $ nullable ,
1902
+ $ unionWithoutNull ->toString ()->isLowercaseString ()->yes (),
1903
+ $ unionWithoutNull ->toString ()->isUppercaseString ()->yes ()
1904
+ );
1865
1905
}
1866
1906
1867
1907
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new FloatType (), $ this ->createNumericString (false )])) {
0 commit comments