What is Rust's use<'lifetime> syntax?
Asked Answered
S

1

5

If you create a function returning an impl Trait which requires a lifetime that can't be elided, rustc tells you to add it.

use futures::prelude::*;

fn make_fut(input: &()) -> impl Future<Output = ()> {
    async move {
        return *input
    }
}
error[E0700]: hidden type for `impl futures::Future<Output = ()>` captures lifetime that does not appear in bounds
 --> src/lib.rs:4:5
  |
3 |   fn make_fut(input: &()) -> impl Future<Output = ()> {
  |                      ---     ------------------------ opaque type defined here
  |                      |
  |                      hidden type `{async block@src/lib.rs:4:5: 4:15}` captures the anonymous lifetime defined here
4 | /     async move {
5 | |         return *input
6 | |     }
  | |_____^
  |
help: add a `use<...>` bound to explicitly capture `'_`
  |
3 | fn make_fut(input: &()) -> impl Future<Output = ()> + use<'_> {
  |                                                     +++++++++

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

This error can be fixed by simply adding + '_ to the return type, but rustc tells use to add + use<'_> instead. Running rustc --explain E0700 only shows the former change and doesn't mention use<'_> at all. The Rust book contains no mention of use being used in this context.

What is this use<'lifetime> syntax? Where is it documented and how can I learn about when I should use it over another syntax?

Starofbethlehem answered 27/10 at 0:17 Comment(1)
rustc --explain mentioning the old way is a bug you should report.Dandle
D
7

This is a new syntax, released in Rust 1.82.0.

In the release blog post we can find more information about it, and there was also a blog post specifically aimed at this syntax (and siblings), but the most information can be found in the RFC.

In short, use<'lifetime> is an alternative to + 'lifetime, but is clearer and better served - in some cases, especially those involving multiple lifetimes and lifetimes with bounds, + 'lifetime won't work but use<'lifetime> will (as explained in the RFC).

It also will, in the future, support use<Type> (meaning "capture all the lifetimes in Type"), which can't be expressed using the + syntax (although it wasn't needed either, because the default was (and still is) to capture all types).

But most importantly, it allows you to opt out of captures: since edition 2024 (and even before that for impl Trait in return type in traits), by default all types and lifetimes will be captured (previously, only types were captured). use<[optionally capture only some]> allows you to get back the old behavior, should it be needed.

Note that as of writing, the RFC is not fully implemented yet: for now, you must still capture all types, and I believe using use in traits was just implemented (maybe even not merged yet). These restrictions will be lifted eventually.

Dandle answered 27/10 at 0:35 Comment(1)
There's also this documentation: doc.rust-lang.org/nightly/reference/types/…Vergne

© 2022 - 2024 — McMap. All rights reserved.