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

[Generics] Recursive / self-referencing template type variable #3006

Open
teohhanhui opened this issue Feb 19, 2020 · 10 comments
Open

[Generics] Recursive / self-referencing template type variable #3006

teohhanhui opened this issue Feb 19, 2020 · 10 comments

Comments

@teohhanhui
Copy link
Contributor

Feature request

https://phpstan.org/r/ea622d5b-dd5f-47ba-a0e2-39a214c2d877

I understand that this would require #2928 first.

@ondrejmirtes ondrejmirtes added this to the Generics milestone Feb 19, 2020
@teohhanhui
Copy link
Contributor Author

teohhanhui commented Feb 19, 2020

I guess my use case in the code snippet is not really related to generics (as T is constant), but I just need a way to "declare" a type and re-use it in a recursive way? See phpstan/phpdoc-parser#9

But the feature request is still valid.

@muglug
Copy link
Contributor

muglug commented Feb 21, 2020

FYI recursive types are very hard to reason about (though support for a JSON recursive type would probably come in handy)

@phpstan-bot
Copy link
Contributor

@teohhanhui PHPStan now reports different result with your code snippet:

@@ @@
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T|true> is not supported.
-16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, true>|true>|true>.
+16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, bool>|bool>|true>.
Full report
Line Error
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
14 `PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T
16 `Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, bool>

@phpstan-bot
Copy link
Contributor

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

@@ @@
+14: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
-14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T|true> is not supported.
-16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, true>|true>|true>.
+14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
+16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T|true> but returns array('a' => array('a1' => true, 'a2' => array('a2.1' => true)), 'b' => true).
Full report
Line Error
14 Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
16 `Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T

@phpstan-bot
Copy link
Contributor

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

@@ @@
+14: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
-14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T|true> is not supported.
-16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, true>|true>|true>.
+14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
+14: Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
+16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T|true> but returns array('a' => array('a1' => true, 'a2' => array('a2.1' => true)), 'b' => true).
Full report
Line Error
14 Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
14 Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
16 `Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T

@phpstan-bot
Copy link
Contributor

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

@@ @@
+14: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
-14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T|true> is not supported.
-16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, true>|true>|true>.
+14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
+14: Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
+16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T|true> but returns array{a: array{a1: true, a2: array{a2.1: true}}, b: true}.
Full report
Line Error
14 Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type true is not supported.
14 Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
16 `Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T

@phpstan-bot
Copy link
Contributor

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

@@ @@
+14: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
 14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
-14: PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() with bound type array<string, GraphQL\Type\Definition\T|true> is not supported.
-16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T but returns array<string, array<string, array<string, true>|true>|true>.
+14: Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
+16: Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T|true> but returns array{a: array{a1: true, a2: array{a2.1: true}}, b: true}.
Full report
Line Error
14 Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid return type GraphQL\Type\Definition\T.
14 PHPDoc tag @template T for method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() has invalid bound type GraphQL\Type\Definition\T.
14 Template type T of method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() is not referenced in a parameter.
16 `Method GraphQL\Type\Definition\ResolveInfo::getFieldSelection() should return T of array<string, GraphQL\Type\Definition\T

@alexander-schranz
Copy link

I think I'm running into a similar issue with phpstan-type to produce recursive item: https://phpstan.org/r/5a1faff9-b45a-45c6-a9a0-9e29f5ec68d4

@ZebulanStanphill
Copy link
Contributor

One notable use-case for recursive template types is an array-flattening method:

/**
 * Transforms multidimensional array to flat array. Based on Nette\Utils\Arrays::flatten().
 *
 * @template K of array-key
 * @template V of mixed
 *
 * @param array<K, V|array<K|V>> $array
 *
 * @return ($preserveKeys is true ? array<K, V> : list<V>)
 */
public static function flatten(array $array, bool $preserveKeys = false): array {
	// ...
}

@olleharstedt
Copy link

No progress here? I'm parsing an S-expression into a SplStack, and I'm not sure if there's a way to express such a type?

@return SplStack<string|SplStack<string|SplStack<string| ... etc

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

7 participants