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

UnresolvedSymbol is now accepted by Vector.sort #6334

Merged
merged 2 commits into from
Apr 20, 2023

Conversation

hubertp
Copy link
Collaborator

@hubertp hubertp commented Apr 18, 2023

Pull Request Description

Vector.sort does some custom method dispatch logic which always expected a function as by and on arguments. At the same time, UnresolvedSymbol is treated like a (to be resolved) Function and under normal circumstances there would be no difference between _.foo and .foo provided as arguments.

Rather than adding an additional phase that does some form of eta-expansion, to accomodate for this custom dispatch, this change only fixes the problem locally. We accept Function and UnresolvedSymbol and perform the resolution on the fly. Ideally, we would have a specialization on the latter but again, it would be dependent on the contents of the Vector so unclear if that is better.

Closes #6276,

Important Notes

There was a suggestion to somehow modify our codegen to accomodate for this scenario but I went against it. In fact a lot of name literals have isMethod flag and that information is used in the passes but it should not control how (late) codegen is done. If we were to make this more generic, I would suggest maybe to add separate eta-expansion pass. But it could affect other things and could be potentially a significant change with limited potential initially, so potential future work item.

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • All code follows the
    Scala,
    Java,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • All code has been tested:
    • Unit tests have been written where possible.

`Vector.sort` does some custom method dispatch logic which always
expected a function as `by` and `on` arguments. At the same time,
`UnresolvedSymbol` is treated like a (to be resolved) `Function` and
under normal circumstances there would be no difference between
`_.foo` and `.foo` provided as arguments.

Rather than adding an additional phase that does some form of
eta-expansion, to accomodate for this custom dispatch, this change only
fixes the problem locally. We accept `Function` and `UnresolvedSymbol`
and perform the resolution on the fly. Ideally, we would have a
specialization on the latter but again, it would be dependent on the
contents of the `Vector` so unclear if that is better.
@hubertp hubertp added the CI: No changelog needed Do not require a changelog entry for this PR. label Apr 18, 2023
@hubertp hubertp requested a review from Akirathan April 18, 2023 12:07
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the primary goal is to make the (on = .b) syntax work. Approving.

However I'd be also interested in making it run (reasonably) fast. Or (at least) not to do such wild things where a Node is held and used by a non-node object. There should be a clear separation between "code" (represented by Node hierarchy) and "data" - however with Compare I am not sure where to draw the line - it feels like a mixture of both.

* as the comparator function, which has to be first resolved before it
* can be used to compare values.
*/
private abstract class Compare {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Truffle way" of doing this would be to have a class Compare extends Node and insert the right one (or more) into the AST somehow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will revisit in future work, as discussed.


@Override
boolean hasFunctionSelfArgument(Object definedOn) {
if (function.getSchema().getArgumentsCount() > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function.getSchema() is a candidate for speculating that it is a constant. However done this way, it is certainly not going to be a constant.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will revisit in future work, as discussed.

@Override
boolean hasFunctionSelfArgument(Object definedOn) {
if (function.getSchema().getArgumentsCount() > 0) {
return function.getSchema().getArgumentInfos()[0].getName().equals("self");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can equals be used on fast-path? Probably this code isn't on fast-path, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this is not on fast-path. It is called from sortGeneric specialization that is behind boundary. If it would be on fast-path, native-image build test should fail, I believe.

private class CompareFromUnresolvedSymbol extends Compare {

private final UnresolvedSymbol unresolvedSymbol;
private final MethodResolverNode methodResolverNode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid having references to Node from a "data". Or is Compare supposed to be "code"? Then it should be Node... This feels like mixing apples and oranges...

You could also go the slow-path route and use MethodResolverNode.getUncached() at usage sites of methodResolverNode.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, indeed, feels weird. I think that optimally, this whole Compare class hierarchy should work like "InvokeCompareFunctionNode". The method resolution from the UnresolvedSymbol could be done straight away in GenericSortComparator constructor.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method resolution from the UnresolvedSymbol could be done straight away in GenericSortComparator constructor.

Not really. Constructor has no knowledge (yet) of the values on which one should dispatch the unresolved symbol on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I misinterpreted that. You are right. I guess that is fine then.

@hubertp
Copy link
Collaborator Author

hubertp commented Apr 18, 2023

I assume the primary goal is to make the (on = .b) syntax work. Approving.

Thanks.

However I'd be also interested in making it run (reasonably) fast. Or (at least) not to do such wild things where a Node is held and used by a non-node object. There should be a clear separation between "code" (represented by Node hierarchy) and "data" - however with Compare I am not sure where to draw the line - it feels like a mixture of both.

I assume that given that SortVectorNode was already reviewed and merged, and already does that kind of magic in GenericSortComparator then pushing it slightly further would "do no harm". I will happily look into making it more Truffle-friendly.

@JaroslavTulach
Copy link
Member

I assume that given that SortVectorNode was already reviewed and merged,

Well, the code is a bit complex. During recent discussions we realized that there is a @Specialization that is also @TruffleBoundary and it "happily" calls into Node instances. That's wrong, it should use CallTarget to return back to PE mode just like #5782 does.

However it is a deeper problem and it can wait for another PR.

@hubertp
Copy link
Collaborator Author

hubertp commented Apr 20, 2023

I assume that given that SortVectorNode was already reviewed and merged,

Well, the code is a bit complex. During recent discussions we realized that there is a @Specialization that is also @TruffleBoundary and it "happily" calls into Node instances. That's wrong, it should use CallTarget to return back to PE mode just like #5782 does.

However it is a deeper problem and it can wait for another PR.

Yeap, agreed. Thanks for the pointers regarding Truffle. I will create a follow up ticket.

Copy link
Member

@jdunkerley jdunkerley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving the enso side.

@hubertp hubertp added the CI: Ready to merge This PR is eligible for automatic merge label Apr 20, 2023
@mergify mergify bot merged commit 6d3151f into develop Apr 20, 2023
@mergify mergify bot deleted the wip/hubert/6276-unresolved-symbol-arg branch April 20, 2023 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: No changelog needed Do not require a changelog entry for this PR. CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

on argument of Vector.sort does not support UnresolvedSymbol
4 participants