-
Notifications
You must be signed in to change notification settings - Fork 676
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
Incorrect inference of template definition using nested templates #8112
Comments
I found these snippets: https://psalm.dev/r/f444f78efa<?php
abstract class Id {}
/**
* @template I of Id
*/
interface ObjectSpec {}
/**
* @template I of Id
* @template O of ObjectSpec<I>
*/
interface Repository{}
class Utils
{
/**
* @template I of Id
* @template O of ObjectSpec<I>
* @psalm-param Repository<I, O> $repo
* @return void
*/
public static function aFunction(Repository $repo): void {}
}
https://psalm.dev/r/f8c537da60<?php
abstract class Id {}
/**
* @template I of Id
*/
interface ObjectSpec {}
/**
* @template I of Id
* @template O of ObjectSpec<I>
*/
interface Repository{}
/**
* @template I of Id
* @template O of ObjectSpec<I>
*/
class Utils
{
/**
* @psalm-param Repository<I, O> $repo
* @return void
*/
public function aFunction(Repository $repo): void {}
}
|
I think this is another case where Psalm's support for using nested templates is buggy 🙁 |
It seems I have yet another case : https://psalm.dev/r/dd644437de Note that though the Psalm issue points to the parameter |
I found these snippets: https://psalm.dev/r/dd644437de<?php
// DATA MODEL
/** @template T */
interface AnId
{
/**
* Getter for the internal value.
*
* @return T Internal value.
*/
public function getValue();
}
/** @template I of AnId */
abstract class AnObject
{
/**
* Getter for the identifier.
*
* @psalm-return I The identifier
*/
abstract public function getId();
}
// PERSISTENCE
/** @template T of object */
interface DbEntity
{
/**
* Maps this entity to a data-model object
*
* @return object Data-model object to which this entity maps.
* @psalm-return T
*/
public function toModel(): object;
}
/**
* Interface for all entities that map to data model object with an identifier.
*
* @template I of AnId
* @template O of AnObject<I>
* @extends DbEntity<O>
*/
interface AnEntity
extends DbEntity {}
/**
* Repository of database entities.
* @template T of object
* @template E of DbEntity<T>
*/
abstract class DbEntityRepository {}
/**
* Repository of database entities that maps to data model objects with identifiers.
* @template I of AnId
* @template O of AnObject<I>
* @template E of AnEntity<I, O>
* @extends DbEntityRepository<O, E>
*/
abstract class AnEntityRepository
extends DbEntityRepository
{}
https://psalm.dev/r/ad8477b7ea<?php
// DATA MODEL
/** @template T */
interface AnId
{
/**
* Getter for the internal value.
*
* @return T Internal value.
*/
public function getValue();
}
/** @template I of AnId */
abstract class AnObject
{
/**
* Getter for the identifier.
*
* @psalm-return I The identifier
*/
abstract public function getId();
}
// PERSISTENCE
/** @template T of object */
interface DbEntity
{
/**
* Maps this entity to a data-model object
*
* @return object Data-model object to which this entity maps.
* @psalm-return T
*/
public function toModel(): object;
}
/**
* Interface for all entities that map to data model object with an identifier.
*
* @template I of AnId
* @template O of AnObject<I>
* @extends DbEntity<O>
*/
interface AnEntity
extends DbEntity {}
/**
* Repository of database entities.
* @template T of object
* @template E of DbEntity<T>
*/
abstract class DbEntityRepository {}
/**
* Repository of database entities that maps to data model objects with identifiers.
* @template I of AnId
* @template O of AnObject<I>
* @template E of AnEntity<I, O>
*/
abstract class AnEntityRepository
{}
|
I think the simplest case to reproduce the issue is that one : https://psalm.dev/r/6531496dba |
I found these snippets: https://psalm.dev/r/73c1e5aa67<?php
/** @template T */
interface A {}
/**
* @template T
* @template U of A<T>
*/
interface B {}
/**
* @template T
* @template U of A<T>
* @template V of B<T, U>
*/
interface C {}
/** @template T */
interface J {}
/**
* @template T
* @template U of A<T>
* @template V of B<T, U>
* @implements J<V>
*/
class K1 implements J {} // class with 3 nested template arguments : KO
/**
* @template T
* @template U of A<T>
* @implements J<U>
*/
class K2 implements J {} // class with 2 nested template arguments : OK
/**
* @template T
* @template U of A<T>
* @template V of B<T, U>
* @extends J<V>
*/
interface K3 extends J {} // interface with 3 nested template arguments : OK
|
I was wrong, here is a definitely simpler example : https://psalm.dev/r/a89a8f3138 |
I found these snippets: https://psalm.dev/r/a89a8f3138<?php
/** @template T */
interface A {}
/**
* @template T
* @template U of A<T>
*/
interface B {}
/** @template T */
interface J {}
/**
* @implements J<B<object, A<object>>>
*/
class K1 implements J {} // class with 3 nested template arguments : KO
|
Hi,
I would expected the 2 following snippets to work :
https://psalm.dev/r/f444f78efa
https://psalm.dev/r/f8c537da60
It seems Psalm does not get that it has the same template definition in
Utils::aFunction()
and in theRepository
interface.Am I missing anything ?
Regards,
The text was updated successfully, but these errors were encountered: