1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00

Be less forgiving when extending builtin generic classes

This commit is contained in:
Matthew Brown 2019-11-30 09:32:21 -05:00
parent 952484c64d
commit 04879af105
2 changed files with 44 additions and 12 deletions

View File

@ -1860,7 +1860,6 @@ class ClassAnalyzer extends ClassLikeAnalyzer
if (isset($parent_storage->template_covariants[$i])
&& !$parent_storage->template_covariants[$i]
&& $parent_storage->user_defined
) {
foreach ($extended_type->getTypes() as $t) {
if ($t instanceof Type\Atomic\TTemplateParam
@ -1869,13 +1868,12 @@ class ClassAnalyzer extends ClassLikeAnalyzer
&& ($local_offset
= array_search($t->param_name, array_keys($storage->template_types)))
!== false
&& isset($storage->template_covariants[$local_offset])
&& $storage->template_covariants[$local_offset]
&& !empty($storage->template_covariants[$local_offset])
) {
if (IssueBuffer::accepts(
new InvalidTemplateParam(
'Cannot extend an invariant template param ' . $template_name
. ' from an invariant context',
. ' into a covariant context',
$code_location
),
$storage->suppressed_issues + $this->getSuppressedIssues()

View File

@ -95,21 +95,30 @@ class ClassTemplateCovarianceTest extends TestCase
/**
* @template-covariant TValue
* @template-extends \ArrayObject<int,TValue>
* @implements IteratorAggregate<int, TValue>
*/
class Collection extends \ArrayObject {
class Collection implements IteratorAggregate {
private $arr;
/**
* @param array<int,TValue> $kv
* @param array<int,TValue> $arr
*/
public function __construct(array $kv) {
parent::__construct($kv);
public function __construct(array $arr) {
$this->arr = $arr;
}
/** @return Traversable<int, TValue> */
public function getIterator() {
foreach ($this->arr as $k => $v) {
yield $k => $v;
}
}
}
/**
* @param Collection<Animal> $list
*/
function getSounds(Traversable $list) : void {
function getSounds(Collection $list) : void {
foreach ($list as $l) {
$l->getSound();
}
@ -136,9 +145,25 @@ class ClassTemplateCovarianceTest extends TestCase
/**
* @template-covariant TValue
* @template-extends \ArrayObject<int,TValue>
* @implements IteratorAggregate<int, TValue>
*/
class Collection extends \ArrayObject {}
class Collection implements IteratorAggregate {
private $arr;
/**
* @param array<int,TValue> $arr
*/
public function __construct(array $arr) {
$this->arr = $arr;
}
/** @return Traversable<int, TValue> */
public function getIterator() {
foreach ($this->arr as $k => $v) {
yield $k => $v;
}
}
}
/** @template-extends Collection<Dog> */
class HardwiredDogCollection extends Collection {}
@ -542,6 +567,15 @@ class ClassTemplateCovarianceTest extends TestCase
}',
'error_message' => 'InvalidTemplateParam'
],
'preventExtendingCoreWithCovariantParam' => [
'<?php
/**
* @template-covariant TValue
* @template-extends \ArrayObject<int,TValue>
*/
class Collection extends \ArrayObject {}',
'error_message' => 'InvalidTemplateParam',
],
];
}
}