Skip to content

Commit 07f960b

Browse files
committed
Implement &pin const self and &pin mut self sugars
1 parent 73c0ae6 commit 07f960b

File tree

7 files changed

+156
-0
lines changed

7 files changed

+156
-0
lines changed

compiler/rustc_ast/src/ast.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2530,6 +2530,8 @@ pub enum SelfKind {
25302530
Value(Mutability),
25312531
/// `&'lt self`, `&'lt mut self`
25322532
Region(Option<Lifetime>, Mutability),
2533+
/// `&'lt pin const self`, `&'lt pin mut self`
2534+
Pinned(Option<Lifetime>, Mutability),
25332535
/// `self: TYPE`, `mut self: TYPE`
25342536
Explicit(P<Ty>, Mutability),
25352537
}
@@ -2539,6 +2541,8 @@ impl SelfKind {
25392541
match self {
25402542
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
25412543
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
2544+
SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()),
2545+
SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()),
25422546
SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
25432547
unreachable!("if we had an explicit self, we wouldn't be here")
25442548
}
@@ -2601,6 +2605,15 @@ impl Param {
26012605
tokens: None,
26022606
}),
26032607
),
2608+
SelfKind::Pinned(lt, mutbl) => (
2609+
mutbl,
2610+
P(Ty {
2611+
id: DUMMY_NODE_ID,
2612+
kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }),
2613+
span,
2614+
tokens: None,
2615+
}),
2616+
),
26042617
};
26052618
Param {
26062619
attrs,

compiler/rustc_ast_pretty/src/pprust/state.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,13 @@ impl<'a> State<'a> {
17561756
self.print_mutability(*m, false);
17571757
self.word("self")
17581758
}
1759+
SelfKind::Pinned(lt, m) => {
1760+
self.word("&");
1761+
self.word("pin");
1762+
self.print_opt_lifetime(lt);
1763+
self.print_mutability(*m, true);
1764+
self.word("self")
1765+
}
17591766
SelfKind::Explicit(typ, m) => {
17601767
self.print_mutability(*m, false);
17611768
self.word("self");

compiler/rustc_parse/src/parser/item.rs

+45
Original file line numberDiff line numberDiff line change
@@ -2957,9 +2957,20 @@ impl<'a> Parser<'a> {
29572957
this.is_keyword_ahead(n, &[kw::SelfLower])
29582958
&& this.look_ahead(n + 1, |t| t != &token::PathSep)
29592959
};
2960+
// Is `pin const self` `n` tokens ahead?
2961+
let is_isolated_pin_const_self = |this: &Self, n| {
2962+
this.look_ahead(n, |token| token.is_ident_named(sym::pin))
2963+
&& this.is_keyword_ahead(n + 1, &[kw::Const])
2964+
&& is_isolated_self(this, n + 2)
2965+
};
29602966
// Is `mut self` `n` tokens ahead?
29612967
let is_isolated_mut_self =
29622968
|this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1);
2969+
// Is `pin mut self` `n` tokens ahead?
2970+
let is_isolated_pin_mut_self = |this: &Self, n| {
2971+
this.look_ahead(n, |token| token.is_ident_named(sym::pin))
2972+
&& is_isolated_mut_self(this, n + 1)
2973+
};
29632974
// Parse `self` or `self: TYPE`. We already know the current token is `self`.
29642975
let parse_self_possibly_typed = |this: &mut Self, m| {
29652976
let eself_ident = expect_self_ident(this);
@@ -3019,6 +3030,20 @@ impl<'a> Parser<'a> {
30193030
self.bump();
30203031
self.bump();
30213032
SelfKind::Region(None, Mutability::Mut)
3033+
} else if is_isolated_pin_const_self(self, 1) {
3034+
// `&pin const self`
3035+
self.bump(); // &
3036+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3037+
self.bump(); // pin
3038+
self.bump(); // const
3039+
SelfKind::Pinned(None, Mutability::Not)
3040+
} else if is_isolated_pin_mut_self(self, 1) {
3041+
// `&pin mut self`
3042+
self.bump(); // &
3043+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3044+
self.bump(); // pin
3045+
self.bump(); // mut
3046+
SelfKind::Pinned(None, Mutability::Mut)
30223047
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
30233048
// `&'lt self`
30243049
self.bump();
@@ -3030,6 +3055,26 @@ impl<'a> Parser<'a> {
30303055
let lt = self.expect_lifetime();
30313056
self.bump();
30323057
SelfKind::Region(Some(lt), Mutability::Mut)
3058+
} else if self.look_ahead(1, |t| t.is_lifetime())
3059+
&& is_isolated_pin_const_self(self, 2)
3060+
{
3061+
// `&'lt pin const self`
3062+
self.bump(); // &
3063+
let lt = self.expect_lifetime();
3064+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3065+
self.bump(); // pin
3066+
self.bump(); // const
3067+
SelfKind::Pinned(Some(lt), Mutability::Not)
3068+
} else if self.look_ahead(1, |t| t.is_lifetime())
3069+
&& is_isolated_pin_mut_self(self, 2)
3070+
{
3071+
// `&'lt pin mut self`
3072+
self.bump(); // &
3073+
let lt = self.expect_lifetime();
3074+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3075+
self.bump(); // pin
3076+
self.bump(); // mut
3077+
SelfKind::Pinned(Some(lt), Mutability::Mut)
30333078
} else {
30343079
// `&not_self`
30353080
return Ok(None);

src/tools/rustfmt/src/items.rs

+27
Original file line numberDiff line numberDiff line change
@@ -2395,6 +2395,33 @@ fn rewrite_explicit_self(
23952395
)?),
23962396
}
23972397
}
2398+
ast::SelfKind::Pinned(lt, m) => {
2399+
let mut_str = m.ptr_str();
2400+
match lt {
2401+
Some(ref l) => {
2402+
let lifetime_str = l.rewrite_result(
2403+
context,
2404+
Shape::legacy(context.config.max_width(), Indent::empty()),
2405+
)?;
2406+
Ok(combine_strs_with_missing_comments(
2407+
context,
2408+
param_attrs,
2409+
&format!("&{lifetime_str} pin {mut_str} self"),
2410+
span,
2411+
shape,
2412+
!has_multiple_attr_lines,
2413+
)?)
2414+
}
2415+
None => Ok(combine_strs_with_missing_comments(
2416+
context,
2417+
param_attrs,
2418+
&format!("&pin {mut_str} self"),
2419+
span,
2420+
shape,
2421+
!has_multiple_attr_lines,
2422+
)?),
2423+
}
2424+
}
23982425
ast::SelfKind::Explicit(ref ty, mutability) => {
23992426
let type_str = ty.rewrite_result(
24002427
context,

src/tools/rustfmt/tests/source/pin_sugar.rs

+10
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ fn g<'a>(x: & 'a pin const i32) {}
88
fn h<'a>(x: & 'a pin
99
mut i32) {}
1010
fn i(x: &pin mut i32) {}
11+
12+
struct Foo;
13+
14+
impl Foo {
15+
fn f(&pin const self) {}
16+
fn g<'a>(& 'a pin const self) {}
17+
fn h<'a>(& 'a pin
18+
mut self) {}
19+
fn i(&pin mut self) {}
20+
}

src/tools/rustfmt/tests/target/pin_sugar.rs

+9
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ fn f(x: &pin const i32) {}
77
fn g<'a>(x: &'a pin const i32) {}
88
fn h<'a>(x: &'a pin mut i32) {}
99
fn i(x: &pin mut i32) {}
10+
11+
struct Foo;
12+
13+
impl Foo {
14+
fn f(&self) {}
15+
fn g<'a>(&'a self) {}
16+
fn h<'a>(&'a mut self) {}
17+
fn i(&mut self) {}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ check-pass
2+
3+
#![feature(pin_ergonomics)]
4+
#![allow(dead_code, incomplete_features)]
5+
6+
// Makes sure we can handle `&pin mut self` and `&pin const self` as sugar for
7+
// `self: Pin<&mut Self>` and `self: Pin<&Self>`.
8+
9+
use std::pin::Pin;
10+
11+
struct Foo;
12+
13+
impl Foo {
14+
fn baz(&pin mut self) {}
15+
16+
fn baz_const(&pin const self) {}
17+
18+
fn baz_lt<'a>(&'a pin mut self) {}
19+
20+
fn baz_const_lt(&'_ pin const self) {}
21+
}
22+
23+
fn foo(_: &pin mut Foo) {}
24+
25+
fn foo_const(x: &pin const Foo) {}
26+
27+
fn bar(x: &pin mut Foo) {
28+
foo(x);
29+
foo(x); // for this to work we need to automatically reborrow,
30+
// as if the user had written `foo(x.as_mut())`.
31+
32+
Foo::baz(x);
33+
Foo::baz(x);
34+
35+
// make sure we can reborrow &mut as &.
36+
foo_const(x);
37+
Foo::baz_const(x);
38+
39+
let x: &pin const _ = Pin::new(&Foo);
40+
41+
foo_const(x); // make sure reborrowing from & to & works.
42+
foo_const(x);
43+
}
44+
45+
fn main() {}

0 commit comments

Comments
 (0)