Skip to content

Commit f3dc08d

Browse files
committed
Auto merge of rust-lang#135733 - frank-king:feature/pin-self-receiver, r=<try>
Implement `&pin const self` and `&pin mut self` sugars This PR implements part of rust-lang#130494. It introduces the sugars `&pin const self` and `&pin mut self` for `self: Pin<&Self>` and `self: Pin<&mut Self>`.
2 parents 69fd5e4 + f3a88c0 commit f3dc08d

File tree

9 files changed

+195
-13
lines changed

9 files changed

+195
-13
lines changed

compiler/rustc_ast/src/ast.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -2583,6 +2583,8 @@ pub enum SelfKind {
25832583
Value(Mutability),
25842584
/// `&'lt self`, `&'lt mut self`
25852585
Region(Option<Lifetime>, Mutability),
2586+
/// `&'lt pin const self`, `&'lt pin mut self`
2587+
Pinned(Option<Lifetime>, Mutability),
25862588
/// `self: TYPE`, `mut self: TYPE`
25872589
Explicit(P<Ty>, Mutability),
25882590
}
@@ -2592,6 +2594,8 @@ impl SelfKind {
25922594
match self {
25932595
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
25942596
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
2597+
SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()),
2598+
SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()),
25952599
SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
25962600
unreachable!("if we had an explicit self, we wouldn't be here")
25972601
}
@@ -2608,11 +2612,13 @@ impl Param {
26082612
if ident.name == kw::SelfLower {
26092613
return match self.ty.kind {
26102614
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
2611-
TyKind::Ref(lt, MutTy { ref ty, mutbl })
2612-
| TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
2615+
TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
2616+
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
2617+
}
2618+
TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
26132619
if ty.kind.is_implicit_self() =>
26142620
{
2615-
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
2621+
Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl)))
26162622
}
26172623
_ => Some(respan(
26182624
self.pat.span.to(self.ty.span),
@@ -2654,6 +2660,15 @@ impl Param {
26542660
tokens: None,
26552661
}),
26562662
),
2663+
SelfKind::Pinned(lt, mutbl) => (
2664+
mutbl,
2665+
P(Ty {
2666+
id: DUMMY_NODE_ID,
2667+
kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }),
2668+
span,
2669+
tokens: None,
2670+
}),
2671+
),
26572672
};
26582673
Param {
26592674
attrs,

compiler/rustc_ast_pretty/src/pprust/state.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,13 @@ impl<'a> State<'a> {
17781778
self.print_mutability(*m, false);
17791779
self.word("self")
17801780
}
1781+
SelfKind::Pinned(lt, m) => {
1782+
self.word("&");
1783+
self.word("pin");
1784+
self.print_opt_lifetime(lt);
1785+
self.print_mutability(*m, true);
1786+
self.word("self")
1787+
}
17811788
SelfKind::Explicit(typ, m) => {
17821789
self.print_mutability(*m, false);
17831790
self.word("self");

compiler/rustc_parse/src/parser/item.rs

+45
Original file line numberDiff line numberDiff line change
@@ -2962,9 +2962,20 @@ impl<'a> Parser<'a> {
29622962
this.is_keyword_ahead(n, &[kw::SelfLower])
29632963
&& this.look_ahead(n + 1, |t| t != &token::PathSep)
29642964
};
2965+
// Is `pin const self` `n` tokens ahead?
2966+
let is_isolated_pin_const_self = |this: &Self, n| {
2967+
this.look_ahead(n, |token| token.is_ident_named(sym::pin))
2968+
&& this.is_keyword_ahead(n + 1, &[kw::Const])
2969+
&& is_isolated_self(this, n + 2)
2970+
};
29652971
// Is `mut self` `n` tokens ahead?
29662972
let is_isolated_mut_self =
29672973
|this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1);
2974+
// Is `pin mut self` `n` tokens ahead?
2975+
let is_isolated_pin_mut_self = |this: &Self, n| {
2976+
this.look_ahead(n, |token| token.is_ident_named(sym::pin))
2977+
&& is_isolated_mut_self(this, n + 1)
2978+
};
29682979
// Parse `self` or `self: TYPE`. We already know the current token is `self`.
29692980
let parse_self_possibly_typed = |this: &mut Self, m| {
29702981
let eself_ident = expect_self_ident(this);
@@ -3024,6 +3035,20 @@ impl<'a> Parser<'a> {
30243035
self.bump();
30253036
self.bump();
30263037
SelfKind::Region(None, Mutability::Mut)
3038+
} else if is_isolated_pin_const_self(self, 1) {
3039+
// `&pin const self`
3040+
self.bump(); // &
3041+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3042+
self.bump(); // pin
3043+
self.bump(); // const
3044+
SelfKind::Pinned(None, Mutability::Not)
3045+
} else if is_isolated_pin_mut_self(self, 1) {
3046+
// `&pin mut self`
3047+
self.bump(); // &
3048+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3049+
self.bump(); // pin
3050+
self.bump(); // mut
3051+
SelfKind::Pinned(None, Mutability::Mut)
30273052
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
30283053
// `&'lt self`
30293054
self.bump();
@@ -3035,6 +3060,26 @@ impl<'a> Parser<'a> {
30353060
let lt = self.expect_lifetime();
30363061
self.bump();
30373062
SelfKind::Region(Some(lt), Mutability::Mut)
3063+
} else if self.look_ahead(1, |t| t.is_lifetime())
3064+
&& is_isolated_pin_const_self(self, 2)
3065+
{
3066+
// `&'lt pin const self`
3067+
self.bump(); // &
3068+
let lt = self.expect_lifetime();
3069+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3070+
self.bump(); // pin
3071+
self.bump(); // const
3072+
SelfKind::Pinned(Some(lt), Mutability::Not)
3073+
} else if self.look_ahead(1, |t| t.is_lifetime())
3074+
&& is_isolated_pin_mut_self(self, 2)
3075+
{
3076+
// `&'lt pin mut self`
3077+
self.bump(); // &
3078+
let lt = self.expect_lifetime();
3079+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
3080+
self.bump(); // pin
3081+
self.bump(); // mut
3082+
SelfKind::Pinned(Some(lt), Mutability::Mut)
30383083
} else {
30393084
// `&not_self`
30403085
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(&pin const self) {}
15+
fn g<'a>(&'a pin const self) {}
16+
fn h<'a>(&'a pin mut self) {}
17+
fn i(&pin 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() {}

tests/ui/feature-gates/feature-gate-pin_ergonomics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ struct Foo;
77
impl Foo {
88
fn foo(self: Pin<&mut Self>) {
99
}
10+
fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental
11+
fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental
1012
}
1113

12-
fn foo(x: Pin<&mut Foo>) {
14+
fn foo(mut x: Pin<&mut Foo>) {
15+
Foo::foo_sugar(x.as_mut());
16+
Foo::foo_sugar_const(x.as_ref());
1317
let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
1418
}
1519

tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
error[E0658]: pinned reference syntax is experimental
2-
--> $DIR/feature-gate-pin_ergonomics.rs:13:14
2+
--> $DIR/feature-gate-pin_ergonomics.rs:10:19
3+
|
4+
LL | fn foo_sugar(&pin mut self) {}
5+
| ^^^
6+
|
7+
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
8+
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: pinned reference syntax is experimental
12+
--> $DIR/feature-gate-pin_ergonomics.rs:11:25
13+
|
14+
LL | fn foo_sugar_const(&pin const self) {}
15+
| ^^^
16+
|
17+
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
18+
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error[E0658]: pinned reference syntax is experimental
22+
--> $DIR/feature-gate-pin_ergonomics.rs:17:14
323
|
424
LL | let _y: &pin mut Foo = x;
525
| ^^^
@@ -9,7 +29,7 @@ LL | let _y: &pin mut Foo = x;
929
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1030

1131
error[E0658]: pinned reference syntax is experimental
12-
--> $DIR/feature-gate-pin_ergonomics.rs:16:18
32+
--> $DIR/feature-gate-pin_ergonomics.rs:20:18
1333
|
1434
LL | fn foo_sugar(_: &pin mut Foo) {}
1535
| ^^^
@@ -19,7 +39,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {}
1939
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2040

2141
error[E0658]: pinned reference syntax is experimental
22-
--> $DIR/feature-gate-pin_ergonomics.rs:28:18
42+
--> $DIR/feature-gate-pin_ergonomics.rs:32:18
2343
|
2444
LL | fn baz_sugar(_: &pin const Foo) {}
2545
| ^^^
@@ -29,7 +49,7 @@ LL | fn baz_sugar(_: &pin const Foo) {}
2949
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
3050

3151
error[E0382]: use of moved value: `x`
32-
--> $DIR/feature-gate-pin_ergonomics.rs:20:9
52+
--> $DIR/feature-gate-pin_ergonomics.rs:24:9
3353
|
3454
LL | fn bar(x: Pin<&mut Foo>) {
3555
| - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -39,15 +59,15 @@ LL | foo(x);
3959
| ^ value used here after move
4060
|
4161
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
42-
--> $DIR/feature-gate-pin_ergonomics.rs:12:11
62+
--> $DIR/feature-gate-pin_ergonomics.rs:14:15
4363
|
44-
LL | fn foo(x: Pin<&mut Foo>) {
45-
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
64+
LL | fn foo(mut x: Pin<&mut Foo>) {
65+
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
4666
| |
4767
| in this function
4868

4969
error[E0382]: use of moved value: `x`
50-
--> $DIR/feature-gate-pin_ergonomics.rs:25:5
70+
--> $DIR/feature-gate-pin_ergonomics.rs:29:5
5171
|
5272
LL | fn baz(mut x: Pin<&mut Foo>) {
5373
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -66,7 +86,7 @@ help: consider reborrowing the `Pin` instead of moving it
6686
LL | x.as_mut().foo();
6787
| +++++++++
6888

69-
error: aborting due to 5 previous errors
89+
error: aborting due to 7 previous errors
7090

7191
Some errors have detailed explanations: E0382, E0658.
7292
For more information about an error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)