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

[draft] Allow templated first class callables #7910

Closed
wants to merge 1 commit into from

Conversation

veewee
Copy link
Contributor

@veewee veewee commented Apr 29, 2022

WIP

This PR aims to fix the first class callable issue in #7244.

The idea is to set a new 'forwarding_to' prop on a TClosure.
This prop will be used during analyzing to do a VirtualFunctionCall to the forwarded function, with the arguments provided to the first class callable function.

So in this case:

/**
 * @template T
 * @param T $param
 * @return T
 */
function debug($param)
{
    return $param;
}

$firstClass = debug(...);
$actualResult = $firstClass('x');

Template on $firstClass will be inferred like this during a function call:

  • firstClass = Closure(T): T with forward_to: debug and args ['x']
  • fetch result type from VirtualFunctionCall to debug('x')
  • Make sure to Untemplate first class callable arguments afterwards (to avoid other type errors)
  • Mark 'x' as the result type of the function call firstClass('x')

Feel free to point me in the right direction, because I am just trying out some things :)

Todo:

  • write + fix test cases
  • first class callable methods
  • first class callable static methods
  • first class invokables
  • first class callable arrays - (static) method calls
  • first class callable strings
  • Closure::fromCallable
  • cleanup
  • Nested lookups?
  • how does it behave inside pipe combinator

@klimick
Copy link
Contributor

klimick commented Apr 30, 2022

Looks like a working solution. Unfortunately for me, hard to say what's drawbacks are followed with it.

@klimick
Copy link
Contributor

klimick commented Apr 30, 2022

Somewhere @weirdan mentioned that something like this requires the new type Closure<T>(T): T (or more params: Closure<T, B of int>(T, B, string): list<T|B|string>)

/**
 * @return Closure<T>(T): T
 */
function getId(): Closure
{
    return fn($v) => $v;
}

getId()('foo'); // type is 'foo'


/**
 * @template T
 * @param T $v
 * @return T
 */
function id(mixed $v): mixed
{
    return $v;
}

$fn = id(...); // type is Closure<T>(T): T
$fn('foo'); // type is 'foo'

But again. I don't know what the difference between these two solutions.

@veewee
Copy link
Contributor Author

veewee commented Apr 30, 2022

That is what I was trying to do first, but the current analyzers are not ready for that: the closure signature is loaded from memory and templates don't get inferred. Closires do accept template types (internally), but nothing happens with them.

According to the code I've seen and the issues in the issue tracker, it looks like it will be very hard to get that working. Frankly a bit above my competence at this moment.. It would be the best solution though 🙂

@thomasvargiu
Copy link
Contributor

@veewee @klimick Any news on this? It would be awesome

@veewee
Copy link
Contributor Author

veewee commented Jan 29, 2023

I haven't been able to find a good solution for this problem so far... The changes were from 9 months ago and a lot has changed since then. Hopefully anyone else has more luck implementing this feature!

@veewee veewee closed this Jan 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants