-
Notifications
You must be signed in to change notification settings - Fork 650
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
Generics hole that can lead to runtime errors #6066
Comments
I found these snippets: https://psalm.dev/r/8b6d92aee7<?php
/** @template T of object */
interface Collection
{
/** @param T $item */
public function add(object $item): void;
}
class Cat
{
}
class Dog
{
}
/**
* @template T of object
* @param Collection<T> $c
* @param T $d
*/
function foo(Collection $c, object $d): void
{
$c->add($d); // adds Cat to Collection<Dog>
}
/**
* @param Collection<Dog> $c
*/
function bar(Collection $c): void
{
foo($c, new Cat());
}
|
Or maybe we don't have to change the type inference logic, I just noticed that PHPStan reports this on the referenced example:
Since the |
Yeah, the call to |
Also broken: https://psalm.dev/r/8a00a541fa |
I found these snippets: https://psalm.dev/r/8a00a541fa<?php
/** @template T of object */
interface Collection1
{
/** @param T $item */
public function add(object $item): void;
}
/** @template T of object */
interface Collection2
{
/** @param T $item */
public function add(object $item): void;
/** @return T */
public function get(): object;
}
class Cat
{
}
class Dog
{
}
/**
* @template T of object
* @param Collection1<T> $c
* @param Collection2<T> $d
*/
function foo(Collection1 $c, Collection2 $d): void
{
$c->add($d->get()); // adds Cat to Collection<Dog>
}
/**
* @param Collection1<Dog> $c
* @param Collection2<Cat> $d
*/
function bar(Collection1 $c, Collection2 $d): void
{
foo($c, $d);
}
|
muglug
added a commit
that referenced
this issue
Jul 10, 2021
muglug
added a commit
that referenced
this issue
Jul 10, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When type variable
T
is present multiple times in function parameters, the resultingT
is the union of all passed parameters mapped to that type.For example:
One exception to this behaviour is when
T
is in the position of a callable:I think I've found a similar situation that asks for the same behavior, but I want multiple sets of eyes before I change this in PHPStan (and ask for the same change in Psalm too).
Let's say you have
Collection
class with@template TValue
. When you haveCollection<Dog>
, you don't wantCat
to be added to that collection. But if you define a function like this, it can happen without any warning from SA:Because you can call it like this:
Full example: https://psalm.dev/r/8b6d92aee7 (no issues reported)
With my suggestion to treat
T
inCollection<T>
same way ascallable(T)
is treated, this wouldn't be an issue, becauseT
infoo($c, new Cat());
would be resolved toCat
andCollection<Cat>
doesn't acceptCollection<Dog>
.Thank you for consideration.
The text was updated successfully, but these errors were encountered: