-
Notifications
You must be signed in to change notification settings - Fork 653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Psalm unable to infer generic type when templated class implements a templated interface #2928
Labels
Comments
I found these snippets: https://psalm.dev/r/557d8b895c<?php
/**
* @psalm-template TKey of array-key
* @psalm-template T
* @template-extends IteratorAggregate<TKey, T>
*/
interface Collection extends IteratorAggregate {}
/**
* @psalm-template TKey of array-key
* @psalm-template T
* @template-implements Collection<TKey,T>
*/
class FooCollection implements Collection
{
private $elements;
/**
* @psalm-param array<TKey,T> $elements
*/
public function __construct(array $elements)
{
$this->elements = $elements;
}
public function getIterator()
{
return new ArrayIterator($this->elements);
}
}
// Psalm knows that $bar is a string.
/** @var Collection<int, string> $foo */
$foo = new FooCollection(['foo']);
foreach ($foo as $bar) {
$bar + 1;
}
// But when using the implementation in the type hint, $bar's type can't be inferred.
// Even though Psalm knows that $foo is of a "non-numeric type FooCollection<int, string>"
/** @var FooCollection<int, string> $foo */
$foo = new FooCollection(['foo']);
foreach ($foo as $bar) {
$bar + 1;
}
|
You can fix this by adding a return type to Still not sure if this is a bug, though |
I found these snippets: https://psalm.dev/r/3f8b934c61<?php
/**
* @psalm-template TKey of array-key
* @psalm-template T
* @template-extends IteratorAggregate<TKey, T>
*/
interface Collection extends IteratorAggregate {}
/**
* @psalm-template TKey of array-key
* @psalm-template T
* @template-implements Collection<TKey,T>
*/
class FooCollection implements Collection
{
private $elements;
/**
* @psalm-param array<TKey,T> $elements
*/
public function __construct(array $elements) {
$this->elements = $elements;
}
/** @return ArrayIterator<TKey, T> */
public function getIterator()
{
return new ArrayIterator($this->elements);
}
}
/** @var Collection<int, string> $foo */
$foo = new FooCollection(['foo']);
foreach ($foo as $bar) {
$bar + 1;
}
/** @var FooCollection<int, string> $foo */
$foo = new FooCollection(['foo']);
foreach ($foo as $bar) {
$bar + 1;
}
|
Awesome, thanks for the swift fix! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I've created a snippet to illustrate the issue: https://psalm.dev/r/557d8b895c
The first
foreach
block:results in
Cannot perform a numeric operation with a non-numeric type string
. So Psalm knows that$bar
is a string. So far so good.When I use the concrete class in the type hint (or leave the docblock out completely), Psalm is unable to infer that
$bar
is a string instead ofmixed
, even though it knows that it is of typeFooCollection<int, string>
:Running Psalm with the second
foreach
block gives me:The text was updated successfully, but these errors were encountered: