Experimental feature gate for super let by m-ou-se · Pull Request #139080 · rust-lang/rust (original) (raw)

This adds an experimental feature gate, #![feature(super_let)], for the super let experiment.

Tracking issue: #139076

Liaison: @nikomatsakis

Description

There's a rough (inaccurate) description here: https://blog.m-ou.se/super-let/

In short, super let allows you to define something that lives long enough to be borrowed by the tail expression of the block. For example:

let a = { super let b = temp(); &b };

Here, b is extended to live as long as a, similar to how in let a = &temp();, the temporary will be extended to live as long as a.

Properties

During the temporary lifetimes work we did last year, we explored the properties of "super let" and concluded that the fundamental property should be that these two are always equivalent in any context:

  1. & $expr
  2. { super let a = & $expr; a }

And, additionally, that these are equivalent in any context when $expr is a temporary (aka rvalue):

  1. & $expr
  2. { super let a = $expr; & a }

This makes it possible to give a name to a temporary without affecting how temporary lifetimes work, such that a macro can transparently use a block in its expansion, without that having any effect on the outside.

Implementing pin!() correctly

With super let, we can properly implement the pin!() macro without hacks: ✨

pub macro pin($value:expr $(,)?) { { super let mut pinned = $value; unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) } } }

This is important, as there is currently no way to express it without hacks in Rust 2021 and before (see hacky definition), and no way to express it at all in Rust 2024 (see issue).

Fixing format_args!()

This will also allow us to express format_args!() in a way where one can assign the result to a variable, fixing a long standing issue:

let f = format_args!("Hello {name}!"); // error today, but accepted in the future! (after separate FCP)

Experiment

The precise definition of super let, what happens for super let x; (without initializer), and whether to accept super let _ = _ else { .. } are still open questions, to be answered by the experiment.

Furthermore, once we have a more complete understanding of the feature, we might be able to come up with a better syntax. (Which could be just a different keywords, or an entirely different way of naming temporaries that doesn't involve a block and a (super) let statement.)