psalm
psalm copied to clipboard
A trait with type parameters can not pass the type parameter to another trait
Example: https://psalm.dev/r/37284614ae
The class RepA
uses the trait TraitBase
with the type parameter A
, which works as expected. However, if the TraitBase
is used by the trait TraitSub
and the TraitSub
is used by a class, which finally defines the type parameter (RepB
or RepC
), the following error is produced:
ERROR: [ArgumentTypeCoercion](https://psalm.dev/193) - 44:30 - Argument 1 of RepB::configureBase expects class-string<B>, but parent type class-string<T:TraitSub as object> provided
I found these snippets:
https://psalm.dev/r/37284614ae
<?php
/**
* @template T
*/
trait TraitBase {
/**
* @var class-string<T>
*/
protected string $_ObjectType;
/**
*
* @param class-string<T> $yObjectType
* @return void
*/
protected function configureBase(string $yObjectType): void {
$this->_ObjectType = $yObjectType;
}
}
/**
* @template T
*/
trait TraitSub {
/**
* @use TraitBase<T>
*/
use TraitBase;
/**
* @var string
*/
protected string $_OtherString;
/**
*
* @param class-string<T> $yObjectType
* @param string $yOtherString
* @return void
*/
protected function configureSub(string $yObjectType, string $yOtherString): void {
$this->configureBase($yObjectType);
$this->_OtherString = $yOtherString;
}
}
class A {}
class B {}
class C {}
class RepA {
/**
* @use TraitBase<A>
*/
use TraitBase;
public function __construct() {
$this->configureBase(A::class);
}
}
class RepB {
/**
* @use TraitSub<B>
*/
use TraitSub;
public function __construct() {
$this->configureSub(B::class, 'repB test');
}
}
class RepC {
/**
* @use TraitSub<C>
*/
use TraitSub;
public function __construct() {
$this->configureSub(C::class, 'repB test');
}
}
Psalm output (using commit a75d26a):
ERROR: ArgumentTypeCoercion - 44:30 - Argument 1 of RepB::configureBase expects class-string<B>, but parent type class-string<T:TraitSub as object> provided
ERROR: PropertyNotSetInConstructor - 64:7 - Property RepB::$_ObjectType is not defined in constructor of RepB or in any methods called in the constructor
ERROR: ArgumentTypeCoercion - 44:30 - Argument 1 of RepC::configureBase expects class-string<C>, but parent type class-string<T:TraitSub as object> provided
ERROR: PropertyNotSetInConstructor - 75:7 - Property RepC::$_ObjectType is not defined in constructor of RepC or in any methods called in the constructor
Related (I think)
@psalm-import-type CustomType from \Foo\BarTrait
doesn't appear to work either.
complains that it can't find a class or Enum named \Foo\BarTrait
Related (I think)
@bkdotcom Not really. Type aliases and generics are two very different things. For your issue see #10625