Skip to content

Commit

Permalink
Nested generic type - correctly infer template types
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Mar 8, 2021
1 parent e4331af commit 48aea56
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 5 deletions.
7 changes: 4 additions & 3 deletions src/Type/Generic/TemplateTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,15 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
]);
}

$resolvedBound = TemplateTypeHelper::resolveToBounds($this->getBound());
$map = $this->getBound()->inferTemplateTypes($receivedType);
$resolvedBound = TemplateTypeHelper::resolveTemplateTypes($this->getBound(), $map);
if ($resolvedBound->isSuperTypeOf($receivedType)->yes()) {
return (new TemplateTypeMap([
$this->name => $this->shouldGeneralizeInferredType() ? TemplateTypeHelper::generalizeType($receivedType) : $receivedType,
]))->union($this->getBound()->inferTemplateTypes($receivedType));
]))->union($map);
}

return $this->getBound()->inferTemplateTypes($receivedType);
return $map;
}

public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array
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 @@ -10961,6 +10961,11 @@ public function dataIteratorIterator(): array
return $this->gatherAssertTypes(__DIR__ . '/data/iterator-iterator.php');
}

public function dataBug4642(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4642.php');
}

/**
* @param string $file
* @return array<string, mixed[]>
Expand Down Expand Up @@ -11214,6 +11219,7 @@ private function gatherAssertTypes(string $file): array
* @dataProvider dataNestedGenericTypesUnwrapping
* @dataProvider dataNestedGenericIncompleteConstructor
* @dataProvider dataIteratorIterator
* @dataProvider dataBug4642
* @param string $assertType
* @param string $file
* @param mixed ...$args
Expand Down
28 changes: 28 additions & 0 deletions tests/PHPStan/Analyser/data/bug-4642.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Bug4642;

use function PHPStan\Analyser\assertType;

interface IEntity {}
/** @template E of IEntity */
interface IRepository {}

interface I {
/**
* Returns repository by repository class.
* @template E of IEntity
* @template T of IRepository<E>
* @phpstan-param class-string<T> $className
* @phpstan-return T
*/
function getRepository(string $className): IRepository;
}

class User implements IEntity {}
/** @implements IRepository<User> */
class UsersRepository implements IRepository {}

function (I $model): void {
assertType(UsersRepository::class, $model->getRepository(UsersRepository::class));
};
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ function (): void {

function (): void {
$result = loadWithIndirectUnwrap2(SomePackage::class);
assertType('NestedGenericTypesUnwrapping\GenericPackage<NestedGenericTypesUnwrapping\SomeInnerPackage>', $result);
assertType(SomePackage::class, $result);
};

function (SomePackage $somePackage): void {
$result = unwrapGeneric($somePackage);
assertType(SomeInnerPackage::class, $result);

$result = unwrapGeneric2($somePackage);
assertType('NestedGenericTypesUnwrapping\GenericPackage<NestedGenericTypesUnwrapping\SomeInnerPackage>', $result);
assertType(SomePackage::class, $result);
};
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1883,4 +1883,12 @@ public function testBug3922(): void
]);
}

public function testBug4642(): void
{
$this->checkThisOnly = false;
$this->checkNullables = true;
$this->checkUnionTypes = true;
$this->analyse([__DIR__ . '/../../Analyser/data/bug-4642.php'], []);
}

}

0 comments on commit 48aea56

Please sign in to comment.