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

feature: Add basic support for become expr/tail calls #15003

Merged
merged 1 commit into from
Feb 14, 2024

Conversation

WaffleLapkin
Copy link
Member

This follows rust-lang/rfcs#3407 and my WIP implementation in the compiler.

Notice that I haven't even opened a compiler PR (although I plan to soon), so this feature doesn't really exist outside of my WIP branches. I've used this to help me test my implementation; opening a PR before I forget.

(feel free to ignore this for now, given all of the above)

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 7, 2023
@@ -716,6 +716,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.set_terminator(current, TerminatorKind::Return, expr_id.into());
Ok(None)
}
Expr::Become { .. } => not_supported!("tail-calls"),
Copy link
Member Author

Choose a reason for hiding this comment

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

MIR support is actually not hard (I already have a MIR impl in the compiler after all), but I'm not sure how to properly lower it from hir. become x is only valid if x is a call (f(x), y.m()) and MIR really would like to see this as simple as possible.

In the compiler I lower HIR->THIR as-is, then run a check on THIR that tail calls are well-formed and then do something akin to this:

let Expr::Call { ..... } = expr
    else { bug!("THIR checks should have noticed that tail call doesn't have a call") };

Not sure what is the best way to do this in r-a

Copy link
Member

Choose a reason for hiding this comment

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

What is the problem of doing the same in r-a? Just instead of bug! use not_supported! or add a variant to MirLowerError.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem is that THIR has much simpler representation of functions and I'm not sure how to correctly handle both function and method calls.

Copy link
Member

Choose a reason for hiding this comment

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

Aha. How it will be a lowered into mir? It would be a new terminator, like BecomeCall?

Copy link
Member Author

@WaffleLapkin WaffleLapkin Jun 8, 2023

Choose a reason for hiding this comment

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

Yes, it will be a new TailCall terminator. There is an experimental branch, it looks like this:

    TailCall {
        /// The function that’s being called.
        func: Operand<'tcx>,
        /// Arguments the function is called with.
        /// These are owned by the callee, which is free to modify them.
        /// This allows the memory occupied by "by-value" arguments to be
        /// reused across function calls without duplicating the contents.
        args: Vec<Operand<'tcx>>,
        // FIXME(explicit_tail_calls): should we have the span for `become`? is this span accurate? do we need it?
        /// This `Span` is the span of the function, without the dot and receiver
        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
        fn_span: Span,
    },

Copy link
Member

Choose a reason for hiding this comment

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

So I see three ways to implement it:

  1. Handle all cases manually. Assuming that become doesn't support overloaded operators, it is just call and method call.
  2. Adding a field to InferenceResult for recording the simple form of function calls (or changing the current method_resolution field). This is similar to THIR in rustc.
  3. Adding a flag to MirLowerCtx, which if true it means the next Terminator::Call should be Terminator::TailCall.

If you want to go with 2, I would suggest doing it in a separate PR, to minimize git conflicts (Assuming this PR is going to be not merged in a long time)

Copy link
Member Author

Choose a reason for hiding this comment

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

I think 3 is error prone with code like

become 1; // invalid
f(); // becomes tail call

2 I'm not exactly sure I understand.


Assuming that become doesn't support overloaded operators

Yes, this is true.

Copy link
Member

Choose a reason for hiding this comment

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

I think 1 would be easiest to go with for now even if it's not the cleanest. 2 seems kind of invasive with the current structure I think

Copy link
Member Author

Choose a reason for hiding this comment

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

This is also my understanding, yes. I'll try option 1.

@WaffleLapkin WaffleLapkin marked this pull request as draft June 7, 2023 16:44
@Veykril Veykril added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 15, 2023
@bors
Copy link
Collaborator

bors commented Sep 5, 2023

☔ The latest upstream changes (presumably #15557) made this pull request unmergeable. Please resolve the merge conflicts.

@WaffleLapkin
Copy link
Member Author

Status update: MIR support is actually harder than I anticipated 😅

This is currently blocked on rust-lang/rust#113128 (i.e. the MIR implementation for rustc).

@Veykril Veykril added the S-blocked Status: marked as blocked ❌ on something else such as an RFC or other implementation work. label Jan 2, 2024
@Veykril
Copy link
Member

Veykril commented Feb 14, 2024

Can we just merge this without the MIR support for now? Cleaning up the PR backlog and I don't see a reason to block it on that and the current parts work well without it. Do you mind rebasing this PR @WaffleLapkin if you have the time? Otherwise I can also do that if you want

@WaffleLapkin
Copy link
Member Author

I'm not sure if this is useful, given that upstream still doesn't support tail calls properly. But I don't see any problems with merging this as is, so why not. I'll rebase today/this week.

@Veykril
Copy link
Member

Veykril commented Feb 14, 2024

It's not necessarily useful right now, but the code is so small that it won't be a problem should design around it change in the future (or it being scrapped fully).

@WaffleLapkin WaffleLapkin changed the title Add support for become expr/tail calls feature: Add basic support for become expr/tail calls Feb 14, 2024
@WaffleLapkin
Copy link
Member Author

Yeah, I agree :)

(rebased)

@Veykril Veykril marked this pull request as ready for review February 14, 2024 15:43
@Veykril
Copy link
Member

Veykril commented Feb 14, 2024

Thanks!
@bors r+

@bors
Copy link
Collaborator

bors commented Feb 14, 2024

📌 Commit e146139 has been approved by Veykril

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Feb 14, 2024

⌛ Testing commit e146139 with merge dba5997...

@bors
Copy link
Collaborator

bors commented Feb 14, 2024

☀️ Test successful - checks-actions
Approved by: Veykril
Pushing dba5997 to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked Status: marked as blocked ❌ on something else such as an RFC or other implementation work. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants