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 ;
@@ -622,10 +624,10 @@ public function walkFunction($function): string
622
624
$ type = $ this ->createFloat (false );
623
625
624
626
} elseif ($ castedExprType ->isNumericString ()->yes ()) {
625
- $ type = $ this ->createNumericString (false );
627
+ $ type = $ this ->createNumericString (false , $ castedExprType -> isLowercaseString ()-> yes (), $ castedExprType -> isUppercaseString ()-> yes () );
626
628
627
629
} else {
628
- $ type = TypeCombinator::union ($ this ->createFloat (false ), $ this ->createNumericString (false ));
630
+ $ type = TypeCombinator::union ($ this ->createFloat (false ), $ this ->createNumericString (false , false , true ));
629
631
}
630
632
631
633
} else {
@@ -738,7 +740,7 @@ private function inferAvgFunction(AST\Functions\AvgFunction $function): Type
738
740
739
741
if ($ this ->driverType === DriverDetector::PDO_MYSQL || $ this ->driverType === DriverDetector::MYSQLI ) {
740
742
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
741
- return $ this ->createNumericString ($ nullable );
743
+ return $ this ->createNumericString ($ nullable, true , true );
742
744
}
743
745
744
746
if ($ exprTypeNoNull ->isString ()->yes () && !$ exprTypeNoNull ->isNumericString ()->yes ()) {
@@ -750,7 +752,7 @@ private function inferAvgFunction(AST\Functions\AvgFunction $function): Type
750
752
751
753
if ($ this ->driverType === DriverDetector::PGSQL || $ this ->driverType === DriverDetector::PDO_PGSQL ) {
752
754
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
753
- return $ this ->createNumericString ($ nullable );
755
+ return $ this ->createNumericString ($ nullable, true , true );
754
756
}
755
757
756
758
return $ this ->generalizeConstantType ($ exprType , $ nullable );
@@ -786,7 +788,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type
786
788
787
789
if ($ this ->driverType === DriverDetector::PDO_MYSQL || $ this ->driverType === DriverDetector::MYSQLI ) {
788
790
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
789
- return $ this ->createNumericString ($ nullable );
791
+ return $ this ->createNumericString ($ nullable, true , true );
790
792
}
791
793
792
794
if ($ exprTypeNoNull ->isString ()->yes () && !$ exprTypeNoNull ->isNumericString ()->yes ()) {
@@ -800,7 +802,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type
800
802
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
801
803
return TypeCombinator::union (
802
804
$ this ->createInteger ($ nullable ),
803
- $ this ->createNumericString ($ nullable ),
805
+ $ this ->createNumericString ($ nullable, true , true ),
804
806
);
805
807
}
806
808
@@ -837,19 +839,41 @@ private function createNonNegativeInteger(bool $nullable): Type
837
839
return $ nullable ? TypeCombinator::addNull ($ integer ) : $ integer ;
838
840
}
839
841
840
- private function createNumericString (bool $ nullable ): Type
842
+ private function createNumericString (bool $ nullable, bool $ lowercase = false , bool $ uppercase = false ): Type
841
843
{
842
- $ numericString = TypeCombinator:: intersect (
844
+ $ types = [
843
845
new StringType (),
844
846
new AccessoryNumericStringType (),
845
- );
847
+ ];
848
+ if ($ lowercase ) {
849
+ $ types [] = new AccessoryLowercaseStringType ();
850
+ }
851
+ if ($ uppercase ) {
852
+ $ types [] = new AccessoryUppercaseStringType ();
853
+ }
854
+
855
+ $ numericString = new IntersectionType ($ types );
846
856
847
857
return $ nullable ? TypeCombinator::addNull ($ numericString ) : $ numericString ;
848
858
}
849
859
850
- private function createString (bool $ nullable ): Type
860
+ private function createString (bool $ nullable, bool $ lowercase = false , bool $ uppercase = false ): Type
851
861
{
852
- $ string = new StringType ();
862
+ if ($ lowercase || $ uppercase ) {
863
+ $ types = [
864
+ new StringType (),
865
+ ];
866
+ if ($ lowercase ) {
867
+ $ types [] = new AccessoryLowercaseStringType ();
868
+ }
869
+ if ($ uppercase ) {
870
+ $ types [] = new AccessoryUppercaseStringType ();
871
+ }
872
+ $ string = new IntersectionType ($ types );
873
+ } else {
874
+ $ string = new StringType ();
875
+ }
876
+
853
877
return $ nullable ? TypeCombinator::addNull ($ string ) : $ string ;
854
878
}
855
879
@@ -895,10 +919,18 @@ private function generalizeConstantType(Type $type, bool $makeNullable): Type
895
919
$ result = $ this ->createFloat ($ containsNull );
896
920
897
921
} elseif ($ typeNoNull ->isNumericString ()->yes ()) {
898
- $ result = $ this ->createNumericString ($ containsNull );
922
+ $ result = $ this ->createNumericString (
923
+ $ containsNull ,
924
+ $ typeNoNull ->isLowercaseString ()->yes (),
925
+ $ typeNoNull ->isUppercaseString ()->yes (),
926
+ );
899
927
900
928
} elseif ($ typeNoNull ->isString ()->yes ()) {
901
- $ result = $ this ->createString ($ containsNull );
929
+ $ result = $ this ->createString (
930
+ $ containsNull ,
931
+ $ typeNoNull ->isLowercaseString ()->yes (),
932
+ $ typeNoNull ->isUppercaseString ()->yes (),
933
+ );
902
934
903
935
} else {
904
936
$ result = $ type ;
@@ -1241,7 +1273,7 @@ public function walkSelectExpression($selectExpression): string
1241
1273
1242
1274
// 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
1243
1275
// so we relax constant types and return just numeric-string to avoid those issues
1244
- $ stringifiedFloat = $ this ->createNumericString (false );
1276
+ $ stringifiedFloat = $ this ->createNumericString (false , false , true );
1245
1277
1246
1278
if ($ stringify ->yes ()) {
1247
1279
return $ stringifiedFloat ;
@@ -1773,7 +1805,11 @@ private function inferPlusMinusTimesType(array $termTypes): Type
1773
1805
}
1774
1806
1775
1807
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), $ this ->createNumericString (false )])) {
1776
- return $ this ->createNumericString ($ nullable );
1808
+ return $ this ->createNumericString (
1809
+ $ nullable ,
1810
+ $ unionWithoutNull ->toString ()->isLowercaseString ()->yes (),
1811
+ $ unionWithoutNull ->toString ()->isUppercaseString ()->yes (),
1812
+ );
1777
1813
}
1778
1814
1779
1815
if ($ this ->containsOnlyNumericTypes ($ unionWithoutNull )) {
@@ -1825,7 +1861,7 @@ private function inferDivisionType(array $termTypes): Type
1825
1861
1826
1862
if ($ unionWithoutNull ->isInteger ()->yes ()) {
1827
1863
if ($ this ->driverType === DriverDetector::MYSQLI || $ this ->driverType === DriverDetector::PDO_MYSQL ) {
1828
- return $ this ->createNumericString ($ nullable );
1864
+ return $ this ->createNumericString ($ nullable, true , true );
1829
1865
} elseif ($ this ->driverType === DriverDetector::PDO_PGSQL || $ this ->driverType === DriverDetector::PGSQL || $ this ->driverType === DriverDetector::SQLITE3 || $ this ->driverType === DriverDetector::PDO_SQLITE ) {
1830
1866
return $ this ->createInteger ($ nullable );
1831
1867
}
@@ -1853,7 +1889,11 @@ private function inferDivisionType(array $termTypes): Type
1853
1889
}
1854
1890
1855
1891
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), $ this ->createNumericString (false )])) {
1856
- return $ this ->createNumericString ($ nullable );
1892
+ return $ this ->createNumericString (
1893
+ $ nullable ,
1894
+ $ unionWithoutNull ->toString ()->isLowercaseString ()->yes (),
1895
+ $ unionWithoutNull ->toString ()->isUppercaseString ()->yes (),
1896
+ );
1857
1897
}
1858
1898
1859
1899
if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new FloatType (), $ this ->createNumericString (false )])) {
0 commit comments