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

Generic return type via static method damage template type (with bound) #3251

Closed
hrach opened this issue May 5, 2020 · 13 comments
Closed

Generic return type via static method damage template type (with bound) #3251

hrach opened this issue May 5, 2020 · 13 comments

Comments

@hrach
Copy link
Contributor

hrach commented May 5, 2020

Bug report

https://phpstan.org/r/f04e6af3-c413-4d94-93b4-0b9b21572598

class E {}

/**
 * @template T of E
 */
class R {
	/** @var T */
	public $e;
	
	/** @return T */
	function ret() { return $this->e; } // nonsense, to silence missing return
	
	function test(): void {
		$this->e = static::ret(); // not ok
		$this->e = self::ret(); // not ok
		$this->e = $this->ret(); // ok
	}
}

self::ret() is evaluated to E type

Property R<T of E>::$e (T of E) does not accept E.

Expected output

No error

@ondrejmirtes
Copy link
Member

You're losing the instance-level @template T if you're calling a method statically, that's kind of expected...

@muglug
Copy link
Contributor

muglug commented May 7, 2020

It's not really called statically, though:

<?php declare(strict_types = 1);

class E {}
class EChild extends E {};

/**
 * @template T of E
 */
class R {
    /** @var T */
    private $t;
    
    /** @param T $t */
    public function __construct($t) {
        $this->t = $t;
    }
	
    /** @return T */
    public function ret() {
        var_dump(get_class($this->t));
        return $this->t;
    }
	
    public function test(): void {
        $this->t = static::ret();
        $this->t = self::ret();
        $this->t = $this->ret();
    }
}

(new R(new EChild()))->test();

results in

string(6) "EChild"
string(6) "EChild"
string(6) "EChild"

@ondrejmirtes
Copy link
Member

Yeah, I get it, we should figure out which self:: and static:: are really $this->. But I consider this "nice to have" as the user can always use $this->.

@ondrejmirtes ondrejmirtes added this to the Generics milestone May 7, 2020
@hrach
Copy link
Contributor Author

hrach commented May 8, 2020

Well, actually, I wanted to have this behavior on real static. I think the bug is it doesn't report unknown T definition over the static method.

https://phpstan.org/r/66eb9b43-0130-4c2e-97e2-b2d65579e39b

@ondrejmirtes
Copy link
Member

#2738

@LukasVitek
Copy link

Next reproduction of the same bug: https://phpstan.org/r/8ca83eff-7db3-4e98-a322-1d963e20aabb

@phpstan-bot
Copy link
Contributor

@hrach After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-16: Property R<T of E>::$e (T of E) does not accept E.
-17: Property R<T of E>::$e (T of E) does not accept E.
+16: Property R<T of E>::$e (T of E) does not accept E.
Full report
Line Error
16 Property R<T of E>::$e (T of E) does not accept E.

@phpstan-bot
Copy link
Contributor

@hrach After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
 13: Method R::ret() should return class-string<T of E> but returns string.
-16: Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.
-17: Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.
+16: Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.
Full report
Line Error
13 Method R::ret() should return class-string<T of E> but returns string.
16 Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.

@phpstan-bot
Copy link
Contributor

@LukasVitek After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-44: Method Parameters::add() should return Parameters<TCriterion of IOrderCriterion> but returns Parameters<IOrderCriterion>.
+No errors

@phpstan-bot
Copy link
Contributor

@hrach After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-16: Property R<T of E>::$e (T of E) does not accept E.
-17: Property R<T of E>::$e (T of E) does not accept E.
+No errors

@phpstan-bot
Copy link
Contributor

@hrach After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-13: Method R::ret() should return class-string<T of E> but returns string.
-16: Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.
-17: Property R<T of E>::$e (class-string<T of E>) does not accept class-string<E>.
+13: Method R::ret() should return class-string<T of E> but returns string.
Full report
Line Error
13 Method R::ret() should return class-string<T of E> but returns string.

@ondrejmirtes
Copy link
Member

Fixed: phpstan/phpstan-src@4acbc6c + phpstan/phpstan-src@d4e0177

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 29, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants