Skip to content

Recursive RPIT causes E0792 (an error about TAIT): "this generic parameter must be used with a generic type parameter" #139350

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

Open
theemathas opened this issue Apr 4, 2025 · 5 comments
Labels
A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@theemathas
Copy link
Contributor

theemathas commented Apr 4, 2025

Code

I tried this code:

fn conjure<T>() -> T { panic!() }

fn what<T, F: FnOnce() -> T>(_: F) -> impl Sized {
    if false {
        let _: T = what::<T, _>(move || conjure::<T>());
    }
    conjure::<T>()
}

I expect the code to compile (although maybe the function might be impossible to call). Instead, on the latest nightly rust (1.88.0-nightly (2025-04-02 d5b4c2e4f19b6d703737)), I got this error:

error[E0792]: expected generic type parameter, found `{closure@src/lib.rs:5:33: 5:40}`
 --> src/lib.rs:5:16
  |
3 | fn what<T, F: FnOnce() -> T>(_: F) -> impl Sized {
  |            - this generic parameter must be used with a generic type parameter
4 |     if false {
5 |         let _: T = what::<T, _>(move || conjure::<T>());
  |                ^

For more information about this error, try `rustc --explain E0792`.

Version it worked on

The code compiles fine on rust 1.72.0 on godbolt.

Version with regression

The code gives the above error on rust 1.73.0 on godbolt.

Additional context

I was playing around trying to break rust, and I ran into this.

Removing the : T type annotation causes the code to compile fine.

The E0792 error emitted by the compiler is an error about TAIT, which is weird, given that the code uses RPIT, not TAIT.

Another variant of the code is:

#[allow(unconditional_recursion)]
fn what<T, F: FnOnce() -> T>(f: F) -> impl Sized {
    what(move || what::<T, _>(move || f()))
}

This variant gives:

  • the confusing E0792 error since version 1.73.0
  • a "concrete type differs from previous defining opaque type use" error in versions 1.65.0 to 1.72.0
  • a "broken MIR" internal compiler error in versions 1.61 to 1.64.0
  • the arguably correct "cannot resolve opaque type" error in version 1.60.0. (I haven't checked earlier versions than this).

@rustbot modify labels: +regression-from-stable-to-stable -regression-untriaged +A-impl-trait

@theemathas theemathas added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels Apr 4, 2025
@rustbot rustbot added I-prioritize Issue: Indicates that prioritization has been requested for this issue. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-untriaged Untriaged performance or correctness regression. labels Apr 4, 2025
@jieyouxu jieyouxu added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 4, 2025
@theemathas
Copy link
Contributor Author

Another variant:

fn conjure<T>() -> T { panic!() }

fn what<T, F: FnOnce() -> T>(_: F) -> impl Sized {
    if false {
        let _: T = what::<T, _>(conjure::<T>);
    }
    conjure::<T>()
}

fn main() {
    what(|| {});
}

This compiles and runs fine(!) in version 1.72.0. However, it gives a compilation error since 1.73.0. Again, removing the : T annotation makes it compile fine.

@theemathas
Copy link
Contributor Author

See also #134838 (comment) for RPIT being weird.

@lcnr
Copy link
Contributor

lcnr commented Apr 4, 2025

This broke due to #112842 and is intended breakage. The documentation is incorrect in only talking about TAIT as recursive calls can introduce RPIT with non-universal arguments as well, e.g. here the assignment let _: T = what::<T, _>(conjure::<T>); tries to define opaque<T, conjure_fn_def> = T and conjure_fn_def is not a generic parameter.

@apiraino apiraino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Apr 4, 2025
@theemathas
Copy link
Contributor Author

Another variant:

#[allow(unconditional_recursion)]
fn weird<T>() -> impl Sized {
    let _: () = weird::<i32>();  // deleting this line makes the code compile, for some reason
    weird::<T>()
}
error[E0792]: expected generic type parameter, found `i32`
 --> src/lib.rs:3:17
  |
2 | fn weird<T>() -> impl Sized {
  |          - this generic parameter must be used with a generic type parameter
3 |     let _: () = weird::<i32>();  // deleting this line makes the code compile, for some reason
  |                 ^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0792`.

This, like the original code, errored since 1.73.0, and compiled fine in 1.72.0

@theemathas
Copy link
Contributor Author

Another variant:

#[allow(unconditional_recursion)]
fn weird<T>() -> impl Sized {
    let _: i64 = weird::<i32>();
    1i64
}
error[E0792]: expected generic type parameter, found `i32`
 --> src/lib.rs:3:12
  |
2 | fn weird<T>() -> impl Sized {
  |          - this generic parameter must be used with a generic type parameter
3 |     let _: i64 = weird::<i32>();
  |            ^^^

For more information about this error, try `rustc --explain E0792`.

Again, this errored since 1.73.0.

@lcnr lcnr added the A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools label Apr 7, 2025
@jieyouxu jieyouxu removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants