rust-lang / rust

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

Confusing error around 2024 impl trait lifetime capture #128113

Open ehuss opened 2 months ago

ehuss commented 2 months ago

I'm finding the error message for 2024 impl trait lifetime capture a little confusing. In the following example:

#![feature(lifetime_capture_rules_2024)]

trait Trait1 {
    type Item;
}
trait Trait2<'a> {}

struct Example;

impl Trait1 for Example {
    type Item = Element;
}

struct Element;
impl<'a> Trait2<'a> for Element {}

fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a>> {
    Example
}

Produces the following output:

error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
  --> src/lib.rs:19:44
   |
19 | fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a>> {
   |                                            ^^^^^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope
   |
note: lifetime declared here
  --> src/lib.rs:19:26
   |
19 | fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a>> {
   |                          ^^

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

For someone that is not familiar with how impl trait capturing works, it seems confusing to understand why the compiler thinks that impl Trait2 is trying to capture anything, since I'm not telling it to.

I'm not entirely certain what would help here, but here are some suggestions:

Version

rustc 1.82.0-nightly (92c6c0380 2024-07-21)
binary: rustc
commit-hash: 92c6c03805408a1a261b98013304e9bbf59ee428
commit-date: 2024-07-21
host: aarch64-apple-darwin
release: 1.82.0-nightly
LLVM version: 18.1.7
compiler-errors commented 2 months ago

Some notes:

Be concrete and short about what is happening.

All three parts of that diagnostic are necessary to explain the error without being inaccurate -- namely, we need to say that an inner opaque can't capture a higher ranked lifetime from an outer opaque. You can capture higher-ranked lifetimes (from the fn signature), just not ones from an outer opaque type.

I'm happy to make the error message more specific by rendering the names of the things involved here, but we also risk very large names coming from very large impl Trait types.

I assume this is blocked on precise_capturing

Nah, I can implement the suggestion in a way that's gated on precise_capturing. And precise_capturing is necessarily landing before lifetime_capture_rules_2024/the edition, so I'm not worried here.

Would also be nice if it also explained why this is an error. The real reason why this doesn't work is overly technical and probably not appreciable by the user.

We just need to say that this behavior is not supported in impl Traits today.

Add a link to the edition-guide chapter that explains capture rules

For the record, this is an error you can observe on master today (i.e. without lifetime_capture_rules_2024) so we do need to be careful not to link someone an explanation that is not actually the reason why the error occurred. We should be able to detect whether the opaque captures the lifetime implicitly or explicitly, though.

tgross35 commented 2 months ago

(The E0657 docs could probably use an update at some point, especially after precise_capturing happens)