mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Rollup merge of #139080 - m-ou-se:super-let-gate, r=traviscross
Experimental feature gate for `super let`
This adds an experimental feature gate, `#![feature(super_let)]`, for the `super let` experiment.
Tracking issue: https://github.com/rust-lang/rust/issues/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:
```rust
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: ✨
```rust
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](2a06022951/library/core/src/pin.rs (L1947)
)), and no way to express it at all in Rust 2024 (see [issue](https://github.com/rust-lang/rust/issues/138718)).
## 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](https://github.com/rust-lang/rust/issues/92698):
```rust
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.)
This commit is contained in:
commit
dbd7f52c83
@ -511,6 +511,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
gate_all!(contracts, "contracts are incomplete");
|
||||
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
|
||||
gate_all!(where_clause_attrs, "attributes in `where` clause are unstable");
|
||||
gate_all!(super_let, "`super let` is experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
@ -629,6 +629,8 @@ declare_features! (
|
||||
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
|
||||
/// Allows `super let` statements.
|
||||
(incomplete, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
|
||||
/// Allows subtrait items to shadow supertrait items.
|
||||
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
|
||||
/// Allows using `#[thread_local]` on `static` items.
|
||||
|
@ -73,7 +73,20 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
let stmt = if self.token.is_keyword(kw::Let) {
|
||||
let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) {
|
||||
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
|
||||
this.expect_keyword(exp!(Super))?;
|
||||
this.psess.gated_spans.gate(sym::super_let, this.prev_token.span);
|
||||
this.expect_keyword(exp!(Let))?;
|
||||
let local = this.parse_local(attrs)?; // FIXME(mara): implement super let
|
||||
let trailing = Trailing::from(capture_semi && this.token == token::Semi);
|
||||
Ok((
|
||||
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
|
||||
trailing,
|
||||
UsePreAttrPos::No,
|
||||
))
|
||||
})?
|
||||
} else if self.token.is_keyword(kw::Let) {
|
||||
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
|
||||
this.expect_keyword(exp!(Let))?;
|
||||
let local = this.parse_local(attrs)?;
|
||||
|
@ -114,6 +114,7 @@ pub enum TokenType {
|
||||
KwSelfUpper,
|
||||
KwStatic,
|
||||
KwStruct,
|
||||
KwSuper,
|
||||
KwTrait,
|
||||
KwTry,
|
||||
KwType,
|
||||
@ -250,6 +251,7 @@ impl TokenType {
|
||||
KwSelfUpper,
|
||||
KwStatic,
|
||||
KwStruct,
|
||||
KwSuper,
|
||||
KwTrait,
|
||||
KwTry,
|
||||
KwType,
|
||||
@ -324,6 +326,7 @@ impl TokenType {
|
||||
TokenType::KwSelfUpper => Some(kw::SelfUpper),
|
||||
TokenType::KwStatic => Some(kw::Static),
|
||||
TokenType::KwStruct => Some(kw::Struct),
|
||||
TokenType::KwSuper => Some(kw::Super),
|
||||
TokenType::KwTrait => Some(kw::Trait),
|
||||
TokenType::KwTry => Some(kw::Try),
|
||||
TokenType::KwType => Some(kw::Type),
|
||||
@ -549,6 +552,7 @@ macro_rules! exp {
|
||||
(SelfUpper) => { exp!(@kw, SelfUpper, KwSelfUpper) };
|
||||
(Static) => { exp!(@kw, Static, KwStatic) };
|
||||
(Struct) => { exp!(@kw, Struct, KwStruct) };
|
||||
(Super) => { exp!(@kw, Super, KwSuper) };
|
||||
(Trait) => { exp!(@kw, Trait, KwTrait) };
|
||||
(Try) => { exp!(@kw, Try, KwTry) };
|
||||
(Type) => { exp!(@kw, Type, KwType) };
|
||||
|
@ -2040,6 +2040,7 @@ symbols! {
|
||||
sub_assign,
|
||||
sub_with_overflow,
|
||||
suggestion,
|
||||
super_let,
|
||||
supertrait_item_shadowing,
|
||||
surface_async_drop_in_place,
|
||||
sym,
|
||||
|
4
tests/ui/feature-gates/feature-gate-super-let.rs
Normal file
4
tests/ui/feature-gates/feature-gate-super-let.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
super let a = 1;
|
||||
//~^ ERROR `super let` is experimental
|
||||
}
|
13
tests/ui/feature-gates/feature-gate-super-let.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-super-let.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0658]: `super let` is experimental
|
||||
--> $DIR/feature-gate-super-let.rs:2:5
|
||||
|
|
||||
LL | super let a = 1;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #139076 <https://github.com/rust-lang/rust/issues/139076> for more information
|
||||
= help: add `#![feature(super_let)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
Loading…
Reference in New Issue
Block a user