Skip to content

Commit b09104d

Browse files
janedbalondrejmirtes
authored andcommitted
QueryResultTypeWalker: fix TypedExpression handling
1 parent 25e200b commit b09104d

File tree

2 files changed

+18
-50
lines changed

2 files changed

+18
-50
lines changed

Diff for: src/Type/Doctrine/Query/QueryResultTypeWalker.php

+11-23
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
namespace PHPStan\Type\Doctrine\Query;
44

55
use BackedEnum;
6-
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\DBAL\Types\StringType as DbalStringType;
7+
use Doctrine\DBAL\Types\Type as DbalType;
78
use Doctrine\ORM\EntityManagerInterface;
89
use Doctrine\ORM\Mapping\ClassMetadata;
910
use Doctrine\ORM\Query;
@@ -817,28 +818,15 @@ public function walkSelectExpression($selectExpression): string
817818
$resultAlias = $selectExpression->fieldIdentificationVariable ?? $this->scalarResultCounter++;
818819
$type = $this->unmarshalType($expr->dispatch($this));
819820

820-
if (class_exists(TypedExpression::class) && $expr instanceof TypedExpression) {
821-
$enforcedType = $this->resolveDoctrineType(Types::INTEGER);
822-
$type = TypeTraverser::map($type, static function (Type $type, callable $traverse) use ($enforcedType): Type {
823-
if ($type instanceof UnionType || $type instanceof IntersectionType) {
824-
return $traverse($type);
825-
}
826-
if ($type instanceof NullType) {
827-
return $type;
828-
}
829-
if ($enforcedType->accepts($type, true)->yes()) {
830-
return $type;
831-
}
832-
if ($enforcedType instanceof StringType) {
833-
if ($type instanceof IntegerType || $type instanceof FloatType) {
834-
return TypeCombinator::union($type->toString(), $type);
835-
}
836-
if ($type instanceof BooleanType) {
837-
return TypeCombinator::union($type->toInteger()->toString(), $type);
838-
}
839-
}
840-
return $enforcedType;
841-
});
821+
if (
822+
$expr instanceof TypedExpression
823+
&& !$expr->getReturnType() instanceof DbalStringType // StringType is no-op, so using TypedExpression with that does nothing
824+
) {
825+
$dbalTypeName = DbalType::getTypeRegistry()->lookupName($expr->getReturnType());
826+
$type = TypeCombinator::intersect( // e.g. count is typed as int, but we infer int<0, max>
827+
$type,
828+
$this->resolveDoctrineType($dbalTypeName, null, TypeCombinator::containsNull($type))
829+
);
842830
} else {
843831
// Expressions default to Doctrine's StringType, whose
844832
// convertToPHPValue() is a no-op. So the actual type depends on

Diff for: tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php

+7-27
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Doctrine\Common\Collections\ArrayCollection;
1010
use Doctrine\ORM\EntityManagerInterface;
1111
use Doctrine\ORM\Mapping\Column;
12-
use Doctrine\ORM\Query\AST\TypedExpression;
1312
use Doctrine\ORM\Tools\SchemaTool;
1413
use PHPStan\Testing\PHPStanTestCase;
1514
use PHPStan\Type\Accessory\AccessoryNumericStringType;
@@ -615,19 +614,15 @@ public function getTestData(): iterable
615614
],
616615
[
617616
new ConstantIntegerType(3),
618-
$this->hasTypedExpressions()
619-
? $this->uint()
620-
: $this->uintStringified(),
617+
$this->uint(),
621618
],
622619
[
623620
new ConstantIntegerType(4),
624621
TypeCombinator::addNull($this->intStringified()),
625622
],
626623
[
627624
new ConstantIntegerType(5),
628-
$this->hasTypedExpressions()
629-
? $this->uint()
630-
: $this->uintStringified(),
625+
$this->uint(),
631626
],
632627
[
633628
new ConstantIntegerType(6),
@@ -682,9 +677,7 @@ public function getTestData(): iterable
682677
],
683678
[
684679
new ConstantStringType('count'),
685-
$this->hasTypedExpressions()
686-
? $this->uint()
687-
: $this->uintStringified(),
680+
$this->uint(),
688681
],
689682
]),
690683
'
@@ -1360,23 +1353,17 @@ public function getTestData(): iterable
13601353
$this->constantArray([
13611354
[
13621355
new ConstantIntegerType(1),
1363-
$this->hasTypedExpressions()
1364-
? $this->uint()
1365-
: $this->uintStringified(),
1356+
$this->uint(),
13661357
],
13671358
[
13681359
new ConstantIntegerType(2),
13691360
TypeCombinator::addNull(
1370-
$this->hasTypedExpressions()
1371-
? $this->uint()
1372-
: $this->uintStringified()
1361+
$this->uint()
13731362
),
13741363
],
13751364
[
13761365
new ConstantIntegerType(3),
1377-
$this->hasTypedExpressions()
1378-
? $this->uint()
1379-
: $this->uintStringified(),
1366+
$this->uint(),
13801367
],
13811368
]),
13821369
'
@@ -1568,9 +1555,7 @@ public function getTestData(): iterable
15681555
[new ConstantIntegerType(1), TypeCombinator::addNull($this->numericStringOrInt())],
15691556
[
15701557
new ConstantIntegerType(2),
1571-
$this->hasTypedExpressions()
1572-
? $this->uint()
1573-
: $this->uintStringified(),
1558+
$this->uint(),
15741559
],
15751560
]),
15761561
'
@@ -1706,11 +1691,6 @@ private function unumericStringified(): Type
17061691
);
17071692
}
17081693

1709-
private function hasTypedExpressions(): bool
1710-
{
1711-
return class_exists(TypedExpression::class);
1712-
}
1713-
17141694
/**
17151695
* @param array<mixed[]> $arrays
17161696
*

0 commit comments

Comments
 (0)