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
Missing support for templates resolution in closures/callables/first class callables #7244
Comments
I found these snippets: https://psalm.dev/r/0df3da05ef<?php
/**
* @psalm-suppress ForbiddenCode
*/
function test(): void
{
$a = [A::class , 'pipe'];
$stages = Closure::fromCallable($a);
/** @psalm-trace $stages */;
$_res = $stages('hello');
/** @psalm-trace $_res */;
}
class A
{
/**
* @template T
*
* @param Closure(T): T ...$stages
*
* @return Closure(T): T
*
* @pure
*/
function pipe(...$stages): callable
{
return array_pop($stages);
}
}
test();
|
I think my code example with callable was wrong, here's the fix: https://psalm.dev/r/75a4ef108e But the conclusion is the same... |
I found these snippets: https://psalm.dev/r/75a4ef108e<?php
/**
* @psalm-suppress ForbiddenCode
*/
function test(): void
{
$a = [A::class , 'pipe'];
$stages = Closure::fromCallable($a)();
/** @psalm-trace $stages */;
$_res = $stages('hello');
/** @psalm-trace $_res */;
}
class A
{
/**
* @template T
*
* @param Closure(T): T ...$stages
*
* @return Closure(T): T
*
* @pure
*/
function pipe(...$stages): callable
{
return array_pop($stages);
}
}
test();
|
@orklah Is there any entrypoint in code I can look at to check if I can create a fix for this issue? https://psalm.dev/r/8d405f8213 <?php
/**
* @template T
* @param T $i
* @return T
*/
function debug(mixed $i): mixed {
return $i;
}
$x = debug('hello');
$y = debug(...)($x);
/** @psalm-trace $y */ |
I'm not sure :( But I'd guess the first thing to begin would be to make sure templates are kept through closures: This should not be mixed if we want this to work |
I found these snippets: https://psalm.dev/r/01e2acbe39<?php
/**
* @template T
* @param T $i
* @return T
*/
function debug(mixed $i): mixed {
return $i;
}
$x = debug('hello');
$y = debug(...);
/** @psalm-trace $x */;
/** @psalm-trace $y */;
|
@klimick : would it (theoretically) be possible to apply the higher order logic for first class callables as well? list_filter(...) -> Closure(list<T>, callable (T): bool): list<T> If we were able to dynamically pass the generics from the underlying type - it could fix template resolving in first class callables? Additional possible case that might need a fix: pipe(
$numbers,
partial_left(custom_array_map(...), fn($i) => $i + 1)
) where both The signatrue of custom_array_map might look like this /**
* @param list<mixed> $args
* @return list<mixed>
*/
function custom_array_map(...$args) {
//...
} The args are being parsed by the dynamic function storage plugin. |
Check examples for It works with first-class-callable syntax. But plugin for partial use many internal api: In my case. I only care about the name of the function that will be partially applied. Any ideas how to make tempalte related api as public? P.S. I would postpone difficult cases, like |
Quickly scrolled through the code. It looks nice, but my main concern is this: partialLeft(mapMany(...), map1(...), map2(...), map3(...)) So my general feeling here, is that psalm should provide a system that deals with templates in first class callable syntax by itself. Otherwise you'll have to always take care of this stuff in your plugin. I currently don't have a clue how this should work. Would a similar approach in psalm internal analyzers be able to dynamically fetch+pass the storage to the first-class called function be possible? Alternatively, there could be a helper function for these kind of actions in plugins. But that most likely would be a "hacky" solution. |
Spent most of the day investigating this issue. I haven't found a way for inferring templates on closures...
Having templates support on first class callables however, is something that we must get working at some point. I've set up a draft PR that enables template inferring on first class callable functions. See #7910 Feel free to take a look and give me pointers in order to get a workable solution. |
The templates on closures and callables are not resolved into the actual provided types when a
FuncCall
is performed on it.This results in following issues:
Output:
Example code:
The text was updated successfully, but these errors were encountered: