1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +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,6 +169,11 @@ class TTemplateParam extends \Psalm\Type\Atomic
&& isset($class_storage->template_covariants[$template_offset])
&& $class_storage->template_covariants[$template_offset]
) {
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 '
@ -182,6 +187,7 @@ class TTemplateParam extends \Psalm\Type\Atomic
}
}
}
}
$this->as->check($source, $code_location, $suppressed_issues, $phantom_classes, $inferred);

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);',
],
];
}