Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 124 additions & 127 deletions compiler/rustc_mir_build/src/check_tail_calls.rs

Large diffs are not rendered by default.

33 changes: 18 additions & 15 deletions tests/ui/explicit-tail-calls/caller-lifetime-presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,42 @@
#![feature(explicit_tail_calls)]
#![allow(incomplete_features)]

fn foo<'a>(_: fn(&'a ())) {
become bar(dummy);
struct A;
struct B;

fn foo<'a>(_: fn(&'a ()), _: A) {
become bar(dummy, B);
//~^ ERROR mismatched signatures
//~| NOTE `become` requires caller and callee to have matching signatures
//~| NOTE caller signature: `fn(fn(&'a ()))`
//~| NOTE callee signature: `fn(for<'a> fn(&'a ()))`
//~| NOTE caller signature: `fn(fn(&'a ()), A)`
//~| NOTE callee signature: `fn(for<'a> fn(&'a ()), B)`
}

fn bar(_: fn(&())) {}
fn bar(_: fn(&()), _: B) {}

fn dummy(_: &()) {}

fn foo_(_: fn(&())) {
become bar1(dummy2);
fn foo2(_: fn(&()), _: A) {
become bar2(dummy2, B);
//~^ ERROR mismatched signatures
//~| NOTE `become` requires caller and callee to have matching signatures
//~| NOTE caller signature: `fn(for<'a> fn(&'a ()))`
//~| NOTE callee signature: `fn(fn(&'a ()))`
//~| NOTE caller signature: `fn(for<'a> fn(&'a ()), A)`
//~| NOTE callee signature: `fn(fn(&'a ()), B)`
}

fn bar1<'a>(_: fn(&'a ())) {}
fn bar2<'a>(_: fn(&'a ()), _: B) {}

fn dummy2(_: &()) {}

fn foo__(_: fn(&'static ())) {
become bar(dummy3);
fn foo3(_: fn(&'static ()), _: A) {
become bar3(dummy3, B);
//~^ ERROR mismatched signatures
//~| NOTE `become` requires caller and callee to have matching signatures
//~| NOTE caller signature: `fn(fn(&'static ()))`
//~| NOTE callee signature: `fn(for<'a> fn(&'a ()))`
//~| NOTE caller signature: `fn(fn(&'static ()), A)`
//~| NOTE callee signature: `fn(for<'a> fn(&'a ()), B)`
}

fn bar2(_: fn(&())) {}
fn bar3(_: fn(&()), _: B) {}

fn dummy3(_: &()) {}

Expand Down
30 changes: 15 additions & 15 deletions tests/ui/explicit-tail-calls/caller-lifetime-presence.stderr
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
error: mismatched signatures
--> $DIR/caller-lifetime-presence.rs:16:5
--> $DIR/caller-lifetime-presence.rs:19:5
|
LL | become bar(dummy);
| ^^^^^^^^^^^^^^^^^
LL | become bar(dummy, B);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `become` requires caller and callee to have matching signatures
= note: caller signature: `fn(fn(&'a ()))`
= note: callee signature: `fn(for<'a> fn(&'a ()))`
= note: caller signature: `fn(fn(&'a ()), A)`
= note: callee signature: `fn(for<'a> fn(&'a ()), B)`

error: mismatched signatures
--> $DIR/caller-lifetime-presence.rs:28:5
--> $DIR/caller-lifetime-presence.rs:31:5
|
LL | become bar1(dummy2);
| ^^^^^^^^^^^^^^^^^^^
LL | become bar2(dummy2, B);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `become` requires caller and callee to have matching signatures
= note: caller signature: `fn(for<'a> fn(&'a ()))`
= note: callee signature: `fn(fn(&'a ()))`
= note: caller signature: `fn(for<'a> fn(&'a ()), A)`
= note: callee signature: `fn(fn(&'a ()), B)`

error: mismatched signatures
--> $DIR/caller-lifetime-presence.rs:40:5
--> $DIR/caller-lifetime-presence.rs:43:5
|
LL | become bar(dummy3);
| ^^^^^^^^^^^^^^^^^^
LL | become bar3(dummy3, B);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `become` requires caller and callee to have matching signatures
= note: caller signature: `fn(fn(&'static ()))`
= note: callee signature: `fn(for<'a> fn(&'a ()))`
= note: caller signature: `fn(fn(&'static ()), A)`
= note: callee signature: `fn(for<'a> fn(&'a ()), B)`

error: aborting due to 3 previous errors

2 changes: 1 addition & 1 deletion tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

fn foo() -> for<'a> fn(&'a i32) {
become bar();
//~^ ERROR mismatched signatures
//~^ ERROR mismatched types
}

fn bar() -> fn(&'static i32) {
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error: mismatched signatures
error[E0308]: mismatched types
--> $DIR/ret-ty-hr-mismatch.rs:5:5
|
LL | become bar();
| ^^^^^^^^^^^^
| ^^^^^^^^^^^^ one type is more general than the other
|
= note: `become` requires caller and callee to have matching signatures
= note: caller signature: `fn() -> for<'a> fn(&'a i32)`
= note: callee signature: `fn() -> fn(&'static i32)`
= note: expected fn pointer `for<'a> fn(&'a _)`
found fn pointer `fn(&'static _)`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: mismatched signatures
--> $DIR/rpit.rs:14:5
--> $DIR/rpit.rs:19:5
|
LL | become foo(x, y);
| ^^^^^^^^^^^^^^^^
Expand Down
7 changes: 6 additions & 1 deletion tests/ui/explicit-tail-calls/rpit.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[next] check-pass

#![feature(explicit_tail_calls)]
#![expect(incomplete_features)]

Expand All @@ -12,7 +17,7 @@ fn foo(x: u32, y: u32) -> u32 {

fn bar(x: u32, y: u32) -> impl ToString {
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


fn main() {
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/explicit-tail-calls/safety.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Checks that you can tail call functions with different unsafety
//
//@ check-pass
#![feature(explicit_tail_calls)]
#![expect(incomplete_features)]

fn a() {
unsafe {
become b();
}
}

unsafe fn b() {
become c();
}

fn c() {}

fn main() {}
28 changes: 28 additions & 0 deletions tests/ui/explicit-tail-calls/subtyping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Check that signature comparison for tail calls allows subtyping.
//
//@ check-pass
#![expect(incomplete_features)]
#![feature(explicit_tail_calls)]

fn f<'short>(
a: &'static (),
b: &'short (),
c: fn(&'static ()),
d: for<'a> fn(&'a ()),
) -> (&'short (), fn(&'static ()), for<'a> fn(&'a ())) {
become g(b, a, d, c);
}

fn g<'short>(
// swapped short/static
a: &'short (),
b: &'static (),
// swapped binder/non binder
c: for<'a> fn(&'a ()),
d: fn(&'static ()),
// 'short=>'static; non binder=>binder
) -> (&'static (), for<'a> fn(&'a ()), for<'a> fn(&'a ())) {
(b, c, c)
}

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/explicit-tail-calls/tail-call-with-projection-arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Check that tail call checks correctly handle projections in signatures.
// (this was briefly broken while working on #156007)
//
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
#![expect(incomplete_features)]
#![feature(explicit_tail_calls)]

trait Trait {
type Assoc;
}

fn a<T: Trait>(_: T::Assoc) {}

fn b<T: Trait>(x: T::Assoc) {
become a::<T>(x)
}

fn main() {}
Loading