Skip to content

Do proper signature equality checking for tail calls#156007

Open
WaffleLapkin wants to merge 7 commits into
rust-lang:mainfrom
WaffleLapkin:tail-call-proper-sig-eq
Open

Do proper signature equality checking for tail calls#156007
WaffleLapkin wants to merge 7 commits into
rust-lang:mainfrom
WaffleLapkin:tail-call-proper-sig-eq

Conversation

@WaffleLapkin

@WaffleLapkin WaffleLapkin commented Apr 30, 2026

Copy link
Copy Markdown
Member

View all comments

For tail calls to be valid, we need some support from the ABI, specifically the caller of the function needs to be able to do all necessary cleanup after the tail called function returns. This can be achieved with a callee-cleanup ABI, but we want to permit tail calls for other ABIs as well (in particular, extern "rust").

In such cases the property that we are looking for is "the caller and callee require the same cleanup". We approximate this with "caller and callee have the same ABI" and we approximate that with "caller and callee have the same signatures (modulo subtyping)".

Previously the code would compare FnSigs with ==, which would not support subtyping and produced other weird results. This PR changes tail call checks to use type checking machinery and in particular eq.

It also fixes handling of opaque types, given the next trait solver is enabled.

r? types

@WaffleLapkin WaffleLapkin added the F-explicit_tail_calls `#![feature(explicit_tail_calls)]` label Apr 30, 2026
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 30, 2026
@rust-log-analyzer

This comment has been minimized.

become foo(x, y);
//~^ ERROR mismatched signatures
//[current]~^ ERROR mismatched signatures
}

@folkertdev folkertdev Apr 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cc #144953

What exactly makes RPIT not work for the old trait solver?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not quite sure (lcnr can probably explain better), but something something opaque types are more annoying to handle in the old solver and in this case they are not being revealed as their hidden type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the main issue is that the old solver does not have a way to say "we're in the defining scope of the following opaque types and have already inferred their hidden types".

So while you can kind of hack around this by allowing them to be redefined and then checking that they match the actually inferred value, this is annoying and doesn't fully work. This is what check_opaque_type_well_formed (I think that's what the method is called) does

@rust-log-analyzer

This comment has been minimized.

Comment thread compiler/rustc_mir_build/src/check_tail_calls.rs Outdated
@WaffleLapkin WaffleLapkin force-pushed the tail-call-proper-sig-eq branch from 6623564 to 1ddb39e Compare June 4, 2026 12:14
@rustbot

This comment has been minimized.

@WaffleLapkin WaffleLapkin force-pushed the tail-call-proper-sig-eq branch from 1ddb39e to cf7e816 Compare June 8, 2026 12:20
Comment thread compiler/rustc_mir_build/src/check_tail_calls.rs Outdated
if let Err(ErrorGuaranteed { .. }) = self.found_errors {
// We do a lot of special-cased errors above; equating signatures below would duplicate
// them, so bail out if we emitted any errors so far.
return;

@lcnr lcnr Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i feel like it would be a lot nicer for this to return Result<(), ErrorGuaranteed> to make the eager returns easier to reason about

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Tried this. Not sure if it's better or worse.

I've used ? as ! to signify "this always returns an error". Kinda goofy, but I think it's the best way to describe this idea.

self.report_signature_mismatch(
expr.span,
self.tcx.liberate_late_bound_regions(
CRATE_DEF_ID.to_def_id(),

@lcnr lcnr Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

that error reporting is weird 🤔

why are you using the identity signature of the caller_ty I guess it's fine as we're in the caller. But then it's just instantiate_identity and liberate_late_bound_regions using the caller_def_id.

Also, why liberate instead of just instantiating with infer or sth 🤔

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

liberate isn't wrong necessarily, just a bit weird if we don't care about regions

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't necessarily understand why liberate_late_bound_regions is used here. Got introduced in #145012 (comment)...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

doens't rly matter

@WaffleLapkin WaffleLapkin force-pushed the tail-call-proper-sig-eq branch from cf4857c to 27c59a3 Compare June 15, 2026 14:24
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@WaffleLapkin WaffleLapkin force-pushed the tail-call-proper-sig-eq branch from 27c59a3 to f184753 Compare June 25, 2026 13:53
@rustbot

rustbot commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

if self.is_closure {
self.report_in_closure(expr);
return;
self.report_in_closure(expr)? as !;

@lcnr lcnr Jun 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hmm i'd do return Err(self.report_in_closure(expr)); 😁

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

or wait the reporting functions use Result<!, ErrorGuaranteed> instead of just ErrorGuaranteed 🤔

idk how I feel about that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess my vibe is, seems worse than just returning ErrorGuaranteed directly and wrapping it in Err here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I just really don't like return Err(...) as a construct tbh. But if you think it's clearer, I can rewrite this to just use return Err(...), it's trivial to do so...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

weak preference for that :x I do dislike self.report_in_closure(expr)? as !;

I also don't care enough to block things on bikeshed tbh, do what you want cause a pirate is free YOU ARE A PIRATE

@rust-bors

rust-bors Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-explicit_tail_calls `#![feature(explicit_tail_calls)]` S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants