Skip to content
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

A trait with type parameters can not pass the type parameter to another trait #10519

Open
vzz3 opened this issue Dec 29, 2023 · 3 comments
Open

Comments

@vzz3
Copy link

vzz3 commented Dec 29, 2023

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
Copy link

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

@bkdotcom

This comment was marked as off-topic.

@weirdan

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants