rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.86k stars 12.51k forks source link

Confusing diagnostics when using RPIT in `Fn` return type #122163

Open marcospb19 opened 6 months ago

marcospb19 commented 6 months ago

Code

#![feature(impl_trait_in_fn_trait_return)]

use std::future::Future;

//  ↓↓↓  remove this parameter and it works
fn f<H>() -> impl Fn() -> impl Future {
    || async {}
}

Current output

error: concrete type differs from previous defining opaque type use
 --> src/lib.rs:6:8
  |
6 |     || async {}
  |        ^^^^^^^^ expected `impl Future`, got `{async block@src/lib.rs:6:8: 6:16}`
  |
note: previous use here
 --> src/lib.rs:6:5
  |
6 |     || async {}
  |     ^^^^^^^^^^^

error[E0720]: cannot resolve opaque type
 --> src/lib.rs:5:27
  |
5 | fn f<H>() -> impl Fn() -> impl Future {
  |                           ^^^^^^^^^^^ cannot resolve opaque type

This error message doesn't mention <H> or explain why it is a problem.

I tried reproducing the same error message with other chains of impl, but I could only reproduce with FnOnce, Fn and FnMut.

Rust Version

rustc 1.78.0-nightly (b6d2d841b 2024-03-05)
binary: rustc
commit-hash: b6d2d841bcf4b77343b159f134c7d39c2dd4ceaa
commit-date: 2024-03-05
host: x86_64-unknown-linux-gnu
release: 1.78.0-nightly
LLVM version: 18.1.0
marcospb19 commented 6 months ago

Actually, why doesn't it compile? Idk :)

fn f() -> impl Fn() -> impl Future { ... }         // ✅ ok
fn f<H>(h: H) {}                                   // ✅ ok
// Both work, I can do both in the same function   // 🤔 mmmmm
fn f<H>(h: H) -> impl Fn() -> impl Future { ... }  // ❌ nope

(Maybe the problem source isn't diagnostics?)

marcospb19 commented 6 months ago

Here is another odd example:

fn f<H>() -> impl Fn() -> impl Future<Output = ()> {
    g
}
async fn g() {}

Works, now change the expression to a closure:

fn f<H>() -> impl Fn() -> impl Future<Output = ()> {
    || g()
}

And it gives a similar error message, but with this different piece:

error: concrete type differs from previous defining opaque type use
 --> src/lib.rs:6:8
  |
6 |     || g()
  |        ^^^ expected `impl Future<Output = ()>`, got `impl Future<Output = ()>`

expected impl Future<Output = ()> got impl Future<Output = ()>