Skip to content

Commit

Permalink
Eliminate non-generic types before inferring from unions
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Mar 11, 2021
1 parent 46d4118 commit a1b7b38
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/Type/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,28 @@ public function toArray(): Type
public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
{
$types = TemplateTypeMap::createEmpty();
if ($receivedType instanceof UnionType) {
$myTypes = [];
$remainingReceivedTypes = [];
foreach ($receivedType->getTypes() as $receivedInnerType) {
foreach ($this->types as $type) {
if ($type->isSuperTypeOf($receivedInnerType)->yes()) {
$types = $types->union($type->inferTemplateTypes($receivedInnerType));
continue 2;
}
$myTypes[] = $type;
}
$remainingReceivedTypes[] = $receivedInnerType;
}
if (count($remainingReceivedTypes) === 0) {
return $types;
}
$receivedType = TypeCombinator::union(...$remainingReceivedTypes);
} else {
$myTypes = $this->types;
}

foreach ($this->types as $type) {
foreach ($myTypes as $type) {
$types = $types->union($type->inferTemplateTypes($receivedType));
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5646,6 +5646,11 @@ public function dataBug4423(): array
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4423.php');
}

public function dataGenericUnions(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/generic-unions.php');
}

/**
* @dataProvider dataArrayFunctions
* @param string $description
Expand Down Expand Up @@ -11258,6 +11263,7 @@ private function gatherAssertTypes(string $file): array
* @dataProvider dataPseudoTypeOverrides
* @dataProvider dataGenericTraits
* @dataProvider dataBug4423
* @dataProvider dataGenericUnions
* @param string $assertType
* @param string $file
* @param mixed ...$args
Expand Down
63 changes: 63 additions & 0 deletions tests/PHPStan/Analyser/data/generic-unions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace GenericUnions;

use function PHPStan\Analyser\assertType;

class Foo
{

/**
* @template T
* @param T|null $p
* @return T
*/
public function doFoo($p)
{
if ($p === null) {
throw new \Exception();
}

return $p;
}

/**
* @template T
* @param T $p
* @return T
*/
public function doBar($p)
{
return $p;
}

/**
* @template T
* @param T|int|float $p
* @return T
*/
public function doBaz($p)
{
return $p;
}

/**
* @param int|string $stringOrInt
*/
public function foo(
?string $nullableString,
$stringOrInt
): void
{
assertType('string', $this->doFoo($nullableString));
assertType('int|string', $this->doFoo($stringOrInt));

assertType('string|null', $this->doBar($nullableString));

assertType('int', $this->doBaz(1));
assertType('string', $this->doBaz('foo'));
assertType('float', $this->doBaz(1.2));
assertType('string', $this->doBaz($stringOrInt));
}

}

0 comments on commit a1b7b38

Please sign in to comment.