1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Allow using covariant template in mutation-free context

This commit is contained in:
Brown 2019-11-26 11:35:03 -05:00
parent a91d2ef572
commit 532e2d64be
2 changed files with 66 additions and 10 deletions

View File

@ -169,16 +169,22 @@ class TTemplateParam extends \Psalm\Type\Atomic
&& isset($class_storage->template_covariants[$template_offset])
&& $class_storage->template_covariants[$template_offset]
) {
if (\Psalm\IssueBuffer::accepts(
new \Psalm\Issue\InvalidTemplateParam(
'Template param ' . $this->param_name . ' of '
. $this->defining_class . ' is marked covariant and cannot be used'
. ' as input to a function',
$code_location
),
$source->getSuppressedIssues()
)) {
// fall through
if ($source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer
&& $source->getFunctionLikeStorage()->mutation_free
) {
// do nothing
} else {
if (\Psalm\IssueBuffer::accepts(
new \Psalm\Issue\InvalidTemplateParam(
'Template param ' . $this->param_name . ' of '
. $this->defining_class . ' is marked covariant and cannot be used'
. ' as input to a function',
$code_location
),
$source->getSuppressedIssues()
)) {
// fall through
}
}
}
}

View File

@ -279,6 +279,56 @@ class ClassTemplateCovarianceTest extends TestCase
takesIteratorAggregate($a);
}'
],
'allowImmutableCovariance' => [
'<?php
class Animal {}
class Dog extends Animal{}
class Cat extends Animal{}
/**
* @psalm-immutable
* @template-covariant T
*/
class Collection {
/** @var list<T> */
private $arr = [];
/**
* @param T ...$a
*/
public function __construct(...$a) {
$this->arr = $a;
}
/**
* @param T $a
* @return Collection<T>
*/
public function add($a) : Collection
{
return new Collection(...$this->arr, $a);
}
}
/**
* @template T
* @param Collection<Animal> $c
* @return Collection<Animal>
*/
function covariant(Collection $c) : Collection
{
return $c->add(new Cat());
}
$dogs = new Collection(new Dog(), new Dog());
$cats = new Collection(new Cat(), new Cat());
$misc = new Collection(new Cat(), new Dog());
covariant($dogs);
covariant($cats);
covariant($misc);',
],
];
}