3838use PHPStan \Type \IntersectionType ;
3939use PHPStan \Type \MixedType ;
4040use PHPStan \Type \NeverType ;
41+ use PHPStan \Type \NullType ;
4142use PHPStan \Type \ObjectType ;
4243use PHPStan \Type \StringType ;
4344use PHPStan \Type \Type ;
@@ -434,10 +435,10 @@ public function walkFunction($function): string
434435 $ exprType = $ this ->generalizeLiteralType ($ exprType , false );
435436
436437 $ exprTypeNoNull = TypeCombinator::removeNull ($ exprType );
437- $ nullable = TypeCombinator:: containsNull ($ exprType );
438+ $ nullable = $ this -> canBeNull ($ exprType );
438439
439440 if ($ exprTypeNoNull ->isInteger ()->yes ()) {
440- $ positiveInt = TypeCombinator:: containsNull ($ exprType )
441+ $ positiveInt = $ this -> canBeNull ($ exprType )
441442 ? TypeCombinator::addNull (IntegerRangeType::fromInterval (0 , null ))
442443 : IntegerRangeType::fromInterval (0 , null );
443444 return $ this ->marshalType ($ positiveInt );
@@ -459,20 +460,18 @@ public function walkFunction($function): string
459460 $ secondExprType = $ this ->unmarshalType ($ function ->secondArithmetic ->dispatch ($ this ));
460461
461462 $ type = IntegerRangeType::fromInterval (0 , null );
462- if (TypeCombinator:: containsNull ($ firstExprType ) || TypeCombinator:: containsNull ($ secondExprType )) {
463+ if ($ this -> canBeNull ($ firstExprType ) || $ this -> canBeNull ($ secondExprType )) {
463464 $ type = TypeCombinator::addNull ($ type );
464465 }
465466
466- // TODO invalid usages
467-
468467 return $ this ->marshalType ($ type );
469468
470469 case $ function instanceof AST \Functions \ConcatFunction:
471470 $ hasNull = false ;
472471
473472 foreach ($ function ->concatExpressions as $ expr ) {
474473 $ type = $ this ->unmarshalType ($ expr ->dispatch ($ this ));
475- $ hasNull = $ hasNull || TypeCombinator:: containsNull ($ type );
474+ $ hasNull = $ hasNull || $ this -> canBeNull ($ type );
476475 }
477476
478477 $ type = new StringType ();
@@ -493,7 +492,7 @@ public function walkFunction($function): string
493492 $ intervalExprType = $ this ->unmarshalType ($ function ->intervalExpression ->dispatch ($ this ));
494493
495494 $ type = new StringType ();
496- if (TypeCombinator:: containsNull ($ dateExprType ) || TypeCombinator:: containsNull ($ intervalExprType )) {
495+ if ($ this -> canBeNull ($ dateExprType ) || $ this -> canBeNull ($ intervalExprType )) {
497496 $ type = TypeCombinator::addNull ($ type );
498497 }
499498
@@ -511,7 +510,7 @@ public function walkFunction($function): string
511510 $ type = new IntegerType ();
512511 }
513512
514- if (TypeCombinator:: containsNull ($ date1ExprType ) || TypeCombinator:: containsNull ($ date2ExprType )) {
513+ if ($ this -> canBeNull ($ date1ExprType ) || $ this -> canBeNull ($ date2ExprType )) {
515514 $ type = TypeCombinator::addNull ($ type );
516515 }
517516
@@ -521,7 +520,7 @@ public function walkFunction($function): string
521520 $ stringPrimaryType = $ this ->unmarshalType ($ function ->stringPrimary ->dispatch ($ this ));
522521
523522 $ type = IntegerRangeType::fromInterval (0 , null );
524- if (TypeCombinator:: containsNull ($ stringPrimaryType )) {
523+ if ($ this -> canBeNull ($ stringPrimaryType )) {
525524 $ type = TypeCombinator::addNull ($ type );
526525 }
527526
@@ -532,7 +531,7 @@ public function walkFunction($function): string
532531 $ secondExprType = $ this ->unmarshalType ($ this ->walkStringPrimary ($ function ->secondStringPrimary ));
533532
534533 $ type = IntegerRangeType::fromInterval (0 , null );
535- if (TypeCombinator:: containsNull ($ firstExprType ) || TypeCombinator:: containsNull ($ secondExprType )) {
534+ if ($ this -> canBeNull ($ firstExprType ) || $ this -> canBeNull ($ secondExprType )) {
536535 $ type = TypeCombinator::addNull ($ type );
537536 }
538537
@@ -544,7 +543,7 @@ public function walkFunction($function): string
544543 $ stringPrimaryType = $ this ->unmarshalType ($ function ->stringPrimary ->dispatch ($ this ));
545544
546545 $ type = new StringType ();
547- if (TypeCombinator:: containsNull ($ stringPrimaryType )) {
546+ if ($ this -> canBeNull ($ stringPrimaryType )) {
548547 $ type = TypeCombinator::addNull ($ type );
549548 }
550549
@@ -574,7 +573,7 @@ public function walkFunction($function): string
574573
575574 $ type = IntegerRangeType::fromInterval (0 , null );
576575
577- if (TypeCombinator:: containsNull ($ firstExprType ) || TypeCombinator:: containsNull ($ secondExprType )) {
576+ if ($ this -> canBeNull ($ firstExprType ) || $ this -> canBeNull ($ secondExprType )) {
578577 $ type = TypeCombinator::addNull ($ type );
579578 }
580579
@@ -633,7 +632,7 @@ public function walkFunction($function): string
633632 $ type = new MixedType ();
634633 }
635634
636- if (TypeCombinator:: containsNull ($ exprType )) {
635+ if ($ this -> canBeNull ($ exprType )) {
637636 $ type = TypeCombinator::addNull ($ type );
638637 }
639638
@@ -650,7 +649,7 @@ public function walkFunction($function): string
650649 }
651650
652651 $ type = new StringType ();
653- if (TypeCombinator:: containsNull ($ stringType ) || TypeCombinator:: containsNull ($ firstExprType ) || TypeCombinator:: containsNull ($ secondExprType )) {
652+ if ($ this -> canBeNull ($ stringType ) || $ this -> canBeNull ($ firstExprType ) || $ this -> canBeNull ($ secondExprType )) {
654653 $ type = TypeCombinator::addNull ($ type );
655654 }
656655
@@ -731,7 +730,7 @@ private function inferAvgFunction(AST\Functions\AvgFunction $function): Type
731730
732731 $ exprType = $ this ->unmarshalType ($ function ->getSql ($ this ));
733732 $ exprTypeNoNull = TypeCombinator::removeNull ($ exprType );
734- $ nullable = TypeCombinator:: containsNull ($ exprType ) || $ this ->hasAggregateWithoutGroupBy ();
733+ $ nullable = $ this -> canBeNull ($ exprType ) || $ this ->hasAggregateWithoutGroupBy ();
735734
736735 $ driver = $ this ->em ->getConnection ()->getDriver ();
737736
@@ -777,7 +776,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type
777776
778777 $ exprType = $ this ->unmarshalType ($ function ->getSql ($ this ));
779778 $ exprTypeNoNull = TypeCombinator::removeNull ($ exprType );
780- $ nullable = TypeCombinator:: containsNull ($ exprType ) || $ this ->hasAggregateWithoutGroupBy ();
779+ $ nullable = $ this -> canBeNull ($ exprType ) || $ this ->hasAggregateWithoutGroupBy ();
781780
782781 $ driver = $ this ->em ->getConnection ()->getDriver ();
783782
@@ -854,7 +853,7 @@ private function containsOnlyTypes(
854853 */
855854 private function generalizeLiteralType (Type $ type , bool $ makeNullable ): Type
856855 {
857- $ containsNull = TypeCombinator:: containsNull ($ type );
856+ $ containsNull = $ this -> canBeNull ($ type );
858857 $ typeNoNull = TypeCombinator::removeNull ($ type );
859858
860859 if (!$ typeNoNull ->isConstantScalarValue ()->yes ()) {
@@ -941,7 +940,7 @@ public function walkCoalesceExpression($coalesceExpression): string
941940 }
942941
943942 $ type = $ this ->unmarshalType ($ expression ->dispatch ($ this ));
944- $ allTypesContainNull = $ allTypesContainNull && TypeCombinator:: containsNull ($ type );
943+ $ allTypesContainNull = $ allTypesContainNull && $ this -> canBeNull ($ type );
945944
946945 $ expressionTypes [] = $ type ;
947946 }
@@ -1123,7 +1122,7 @@ public function walkSelectExpression($selectExpression): string
11231122 if ($ expr instanceof TypedExpression) {
11241123 $ type = TypeCombinator::intersect ( // e.g. count is typed as int, but we infer int<0, max>
11251124 $ type ,
1126- $ this ->resolveDoctrineType (DbalType::lookupName ($ expr ->getReturnType ()), null , TypeCombinator:: containsNull ($ type ))
1125+ $ this ->resolveDoctrineType (DbalType::lookupName ($ expr ->getReturnType ()), null , $ this -> canBeNull ($ type ))
11271126 );
11281127 } else {
11291128 // Expressions default to Doctrine's StringType, whose
@@ -1642,15 +1641,17 @@ private function inferPlusMinusTimesType(array $termTypes): Type
16421641 }
16431642
16441643 $ union = TypeCombinator::union (...$ types );
1645- $ nullable = TypeCombinator:: containsNull ($ union );
1644+ $ nullable = $ this -> canBeNull ($ union );
16461645 $ unionWithoutNull = TypeCombinator::removeNull ($ union );
16471646
16481647 if ($ unionWithoutNull ->isInteger ()->yes ()) {
16491648 return $ this ->createInteger ($ nullable );
16501649 }
16511650
16521651 if ($ driver instanceof PdoPgSQLDriver) {
1653- return $ this ->createNumericString ($ nullable );
1652+ if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), new FloatType (), $ this ->createNumericString (false )])) {
1653+ return $ this ->createNumericString ($ nullable );
1654+ }
16541655 }
16551656
16561657 if ($ driver instanceof SQLite3Driver || $ driver instanceof PdoSqliteDriver) {
@@ -1725,7 +1726,7 @@ private function inferDivisionType(array $termTypes): Type
17251726 }
17261727
17271728 $ union = TypeCombinator::union (...$ types );
1728- $ nullable = TypeCombinator:: containsNull ($ union );
1729+ $ nullable = $ this -> canBeNull ($ union );
17291730 $ unionWithoutNull = TypeCombinator::removeNull ($ union );
17301731
17311732 if ($ unionWithoutNull ->isInteger ()->yes ()) {
@@ -1739,7 +1740,9 @@ private function inferDivisionType(array $termTypes): Type
17391740 }
17401741
17411742 if ($ driver instanceof PdoPgSQLDriver) {
1742- return $ this ->createNumericString ($ nullable );
1743+ if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), new FloatType (), $ this ->createNumericString (false )])) {
1744+ return $ this ->createNumericString ($ nullable );
1745+ }
17431746 }
17441747
17451748 if ($ driver instanceof SQLite3Driver || $ driver instanceof PdoSqliteDriver) {
@@ -1937,6 +1940,11 @@ private function resolveDatabaseInternalType(string $typeName, ?string $enumType
19371940 return $ type ;
19381941 }
19391942
1943+ private function canBeNull (Type $ type ): bool
1944+ {
1945+ return !$ type ->accepts (new NullType (), true )->no ();
1946+ }
1947+
19401948 /**
19411949 * Returns whether the query has aggregate function and no group by clause
19421950 *
@@ -2041,24 +2049,10 @@ private function shouldStringifyExpressions(Type $type): TrinaryLogic
20412049 }
20422050 }
20432051
2044- if ($ driver instanceof PgSQLDriver) {
2045- if ($ type ->isBoolean ()->yes ()) {
2046- return TrinaryLogic::createNo ();
2047- } elseif ($ type ->isFloat ()->yes ()) {
2048- return TrinaryLogic::createNo (); // AVG(col_float) is not, but 0.1 is
2049- } elseif ($ type ->isInteger ()->yes ()) {
2050- return TrinaryLogic::createNo ();
2051- }
2052- }
2053-
2054- if ($ driver instanceof SQLite3Driver) {
2052+ if ($ driver instanceof PgSQLDriver || $ driver instanceof SQLite3Driver || $ driver instanceof MysqliDriver) {
20552053 return TrinaryLogic::createNo ();
20562054 }
20572055
2058- if ($ driver instanceof MysqliDriver) {
2059- return TrinaryLogic::createNo (); // DECIMAL / FLOAT already decided in walkLiteral
2060- }
2061-
20622056 return TrinaryLogic::createMaybe ();
20632057 }
20642058
0 commit comments