1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix errors caused by bad generic param counts

Fixes #1474
This commit is contained in:
Matthew Brown 2019-03-17 12:20:57 -04:00
parent f66af3e267
commit ca765cba58
5 changed files with 131 additions and 43 deletions

View File

@ -430,6 +430,7 @@ class NewAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\CallAna
if (is_string($extended_template_name)
&& $extended_atomic_type instanceof Type\Atomic\TTemplateParam
&& $extended_atomic_type->param_name === $template_name
&& $extended_template_name !== $template_name
) {
return self::getGenericParamForOffset(
$extended_template_name,

View File

@ -1391,6 +1391,10 @@ class TypeAnalyzer
array_keys($input_class_storage->template_types)
);
if (!isset($input_type_params[$old_params_offset])) {
return false;
}
$candidate_param_type = $input_type_params[$old_params_offset];
} else {
$candidate_param_type = new Type\Union([$et]);
@ -1506,6 +1510,10 @@ class TypeAnalyzer
}
foreach ($input_type_part->type_params as $i => $input_param) {
if ($i > 1) {
break;
}
$container_param = $container_type_part->type_params[$i];
if ($i === 0

View File

@ -901,19 +901,6 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
continue;
}
if (!$template_type->isSingle()) {
if (IssueBuffer::accepts(
new InvalidDocblock(
'Template type cannot be a union in docblock for '
. implode('.', $this->fq_classlike_names),
new CodeLocation($this->file_scanner, $node, null, true)
)
)) {
$storage->has_docblock_issues = true;
continue;
}
}
$storage->template_types[$template_name] = [
$template_type,
$fq_classlike_name
@ -1779,20 +1766,6 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$template_type = Type::getMixed();
}
if (!$template_type->isSingle()) {
if (IssueBuffer::accepts(
new InvalidDocblock(
'Template type cannot be a union in docblock for '
. implode('.', $this->fq_classlike_names),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
$storage->has_docblock_issues = true;
}
$template_type = Type::getMixed();
}
} else {
$template_type = Type::getMixed();
}

View File

@ -1527,6 +1527,55 @@ class TemplateExtendsTest extends TestCase
use T;
}',
],
'extendWithTooFewArgs' => [
'<?php
/**
* @template TKey of array-key
* @template T
* @template-extends IteratorAggregate<TKey, T>
*/
interface Collection extends IteratorAggregate
{
}
/**
* @psalm-suppress MissingTemplateParam
* @template T
* @template TKey of array-key
* @template-implements Collection<TKey>
*/
class ArrayCollection implements Collection
{
/**
* @psalm-var T[]
*/
private $elements;
/**
* @psalm-param array<T> $elements
*/
public function __construct(array $elements = [])
{
$this->elements = $elements;
}
public function getIterator()
{
return new ArrayIterator($this->elements);
}
/**
* @psalm-suppress MissingTemplateParam
*
* @psalm-param array<T> $elements
* @psalm-return ArrayCollection<T>
*/
protected function createFrom(array $elements)
{
return new static($elements);
}
}',
],
];
}

View File

@ -1863,6 +1863,79 @@ class TemplateTest extends TestCase
return new CustomReflectionClass($className);
}'
],
'ignoreTooManyArrayArgs' => [
'<?php
function takesArray(array $arr) : void {}
/**
* @psalm-suppress TooManyTemplateParams
* @var array<int, int, int>
*/
$b = [1, 2, 3];
takesArray($b);'
],
'ignoreTooManyGenericObjectArgs' => [
'<?php
/**
* @template T
*/
class C {
/** @var T */
public $t;
/** @param T $t */
public function __construct($t) {
$this->t = $t;
}
}
/** @param C<int> $c */
function takesC(C $c) : void {}
/**
* @psalm-suppress TooManyTemplateParams
* @var C<int, int>
*/
$c = new C(5);
takesC($c);'
],
'classTemplateUnionType' => [
'<?php
/**
* @template T0 as int|string
*/
class C {
/**
* @param T0 $t
*/
public function foo($t) : void {}
}
/** @param C<int> $c */
function foo(C $c) : void {}
/** @param C<string> $c */
function bar(C $c) : void {}',
],
'functionTemplateUnionType' => [
'<?php
/**
* @template T0 as int|string
* @param T0 $t
* @return T0
*/
function foo($t) {
return $t;
}
$s = foo("hello");
$i = foo(5);',
'assertions' => [
'$s' => 'string',
'$i' => 'int',
],
],
];
}
@ -2322,22 +2395,6 @@ class TemplateTest extends TestCase
$templated_list->add(5, []);',
'error_message' => 'InvalidArgument',
],
'classTemplateUnionType' => [
'<?php
/**
* @template T0 as int|string
*/
class Foo {}',
'error_message' => 'InvalidDocblock'
],
'functionTemplateUnionType' => [
'<?php
/**
* @template T0 as int|string
*/
function foo() : void {}',
'error_message' => 'InvalidDocblock'
],
'copyScopedClassInFunction' => [
'<?php
/**