Skip to content

Commit d801919

Browse files
committed
More precise ?? type inference
1 parent 3c78441 commit d801919

File tree

5 files changed

+25
-7
lines changed

5 files changed

+25
-7
lines changed

src/Analyser/MutatingScope.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,8 @@ private function resolveType(string $exprString, Expr $node): Type
15761576
}
15771577

15781578
if ($node instanceof Expr\BinaryOp\Coalesce) {
1579-
$leftType = $this->getType($node->left);
1579+
$issetLeftExpr = new Expr\Isset_([$node->left]);
1580+
$leftType = $this->filterByTruthyValue($issetLeftExpr)->getType($node->left);
15801581

15811582
$result = $this->issetCheck($node->left, static function (Type $type): ?bool {
15821583
$isNull = $type->isNull();
@@ -1591,7 +1592,7 @@ private function resolveType(string $exprString, Expr $node): Type
15911592
return TypeCombinator::removeNull($leftType);
15921593
}
15931594

1594-
$rightType = $this->filterByFalseyValue(new Expr\Isset_([$node->left]))->getType($node->right);
1595+
$rightType = $this->filterByFalseyValue($issetLeftExpr)->getType($node->right);
15951596

15961597
if ($result === null) {
15971598
return TypeCombinator::union(

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ public function dataFileAsserts(): iterable
174174
}
175175

176176
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-3875.php');
177+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10327.php');
177178
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2611.php');
178179
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-3548.php');
179180
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10131.php');
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Bug10327;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @param object{optionalKey?: int} $object
9+
* @param array{optionalKey?: int} $array
10+
*/
11+
function test(object $object, array $array): void
12+
{
13+
$valueObject = $object->optionalKey ?? null;
14+
15+
assertType('int|null', $valueObject);
16+
}

tests/PHPStan/Analyser/data/bug-4117.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ public function getIterator(): ArrayIterator
3030
public function broken(int $key)
3131
{
3232
$item = $this->items[$key] ?? null;
33-
assertType('T (class Bug4117Types\GenericList, argument)|null', $item);
33+
assertType('T of mixed~null (class Bug4117Types\GenericList, argument)|null', $item);
3434
if ($item) {
3535
assertType("T of mixed~0|0.0|''|'0'|array{}|false|null (class Bug4117Types\GenericList, argument)", $item);
3636
} else {
37-
assertType("(array{}&T (class Bug4117Types\GenericList, argument))|(0.0&T (class Bug4117Types\GenericList, argument))|(0&T (class Bug4117Types\GenericList, argument))|(''&T (class Bug4117Types\GenericList, argument))|('0'&T (class Bug4117Types\GenericList, argument))|(T (class Bug4117Types\GenericList, argument)&false)|null", $item);
37+
assertType("(array{}&T of mixed~null (class Bug4117Types\GenericList, argument))|(0.0&T of mixed~null (class Bug4117Types\GenericList, argument))|(0&T of mixed~null (class Bug4117Types\GenericList, argument))|(''&T of mixed~null (class Bug4117Types\GenericList, argument))|('0'&T of mixed~null (class Bug4117Types\GenericList, argument))|(T of mixed~null (class Bug4117Types\GenericList, argument)&false)|null", $item);
3838
}
3939

40-
assertType('T (class Bug4117Types\GenericList, argument)|null', $item);
40+
assertType('T of mixed~null (class Bug4117Types\GenericList, argument)|null', $item);
4141

4242
return $item;
4343
}
@@ -48,7 +48,7 @@ public function broken(int $key)
4848
public function works(int $key)
4949
{
5050
$item = $this->items[$key] ?? null;
51-
assertType('T (class Bug4117Types\GenericList, argument)|null', $item);
51+
assertType('T of mixed~null (class Bug4117Types\GenericList, argument)|null', $item);
5252

5353
return $item;
5454
}

tests/PHPStan/Analyser/data/isset-coalesce-empty-type-root.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
assertType('bool', isset($sometimesDefinedVariable));
1414
assertType('bool', isset($neverDefinedVariable));
1515

16-
assertType('mixed', $foo ?? false);
16+
assertType('mixed~null', $foo ?? false);
1717

1818
$bar = 'abc';
1919
assertType('\'abc\'', $bar ?? false);

0 commit comments

Comments
 (0)