Skip to content

Commit fc7630a

Browse files
bors[bot]taiki-e
andauthored
Merge #190
190: Improve handling of Self r=taiki-e a=taiki-e Based on https://github.com/dtolnay/async-trait/blob/0.1.30/src/receiver.rs Co-authored-by: Taiki Endo <te316e89@gmail.com>
2 parents 2707b35 + 2dc57f7 commit fc7630a

File tree

4 files changed

+141
-208
lines changed

4 files changed

+141
-208
lines changed

pin-project-internal/src/utils.rs

+70-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::mem;
1+
use std::{iter::FromIterator, mem};
22

33
use proc_macro2::{Group, TokenStream, TokenTree};
44
use quote::{format_ident, quote_spanned};
@@ -191,7 +191,7 @@ impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
191191
// visitors
192192

193193
// Replace `self`/`Self` with `__self`/`self_ty`.
194-
// Based on https://github.com/dtolnay/async-trait/blob/0.1.22/src/receiver.rs
194+
// Based on https://github.com/dtolnay/async-trait/blob/0.1.30/src/receiver.rs
195195

196196
pub(crate) struct ReplaceReceiver<'a> {
197197
self_ty: &'a Type,
@@ -202,7 +202,7 @@ impl<'a> ReplaceReceiver<'a> {
202202
Self { self_ty }
203203
}
204204

205-
fn self_to_qself(&mut self, qself: &mut Option<QSelf>, path: &mut Path) {
205+
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
206206
if path.leading_colon.is_some() {
207207
return;
208208
}
@@ -235,15 +235,28 @@ impl<'a> ReplaceReceiver<'a> {
235235
}
236236

237237
fn self_to_expr_path(&self, path: &mut Path) {
238+
if path.leading_colon.is_some() {
239+
return;
240+
}
241+
242+
let first = &path.segments[0];
243+
if first.ident != "Self" || !first.arguments.is_empty() {
244+
return;
245+
}
246+
238247
if let Type::Path(self_ty) = &self.self_ty {
239-
*path = self_ty.path.clone();
248+
let variant = mem::replace(path, self_ty.path.clone());
240249
for segment in &mut path.segments {
241250
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
242251
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
243252
bracketed.colon2_token = Some(token::Colon2::default());
244253
}
245254
}
246255
}
256+
if variant.segments.len() > 1 {
257+
path.segments.push_punct(token::Colon2::default());
258+
path.segments.extend(variant.segments.into_pairs().skip(1));
259+
}
247260
} else {
248261
let span = path.segments[0].ident.span();
249262
let msg = "Self type of this impl is unsupported in expression position";
@@ -285,26 +298,48 @@ impl VisitMut for ReplaceReceiver<'_> {
285298
}
286299

287300
fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
288-
if expr.path.is_ident("Self") {
289-
self.self_to_expr_path(&mut expr.path);
290-
}
301+
self.self_to_expr_path(&mut expr.path);
291302
visit_mut::visit_expr_struct_mut(self, expr);
292303
}
293304

305+
fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
306+
if pat.qself.is_none() {
307+
self.self_to_qself(&mut pat.qself, &mut pat.path);
308+
}
309+
visit_mut::visit_pat_path_mut(self, pat);
310+
}
311+
312+
fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
313+
self.self_to_expr_path(&mut pat.path);
314+
visit_mut::visit_pat_struct_mut(self, pat);
315+
}
316+
317+
fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
318+
self.self_to_expr_path(&mut pat.path);
319+
visit_mut::visit_pat_tuple_struct_mut(self, pat);
320+
}
321+
322+
fn visit_item_mut(&mut self, node: &mut Item) {
323+
match node {
324+
// Visit `macro_rules!` because locally defined macros can refer to `self`.
325+
Item::Macro(node) if node.mac.path.is_ident("macro_rules") => {
326+
self.visit_macro_mut(&mut node.mac)
327+
}
328+
// Otherwise, do not recurse into nested items.
329+
_ => {}
330+
}
331+
}
332+
294333
fn visit_macro_mut(&mut self, node: &mut Macro) {
295334
// We can't tell in general whether `self` inside a macro invocation
296335
// refers to the self in the argument list or a different self
297336
// introduced within the macro. Heuristic: if the macro input contains
298337
// `fn`, then `self` is more likely to refer to something other than the
299338
// outer function's self argument.
300339
if !contains_fn(node.tokens.clone()) {
301-
node.tokens = fold_token_stream(node.tokens.clone());
340+
visit_token_stream(&mut node.tokens);
302341
}
303342
}
304-
305-
fn visit_item_mut(&mut self, _: &mut Item) {
306-
// Do not recurse into nested items.
307-
}
308343
}
309344

310345
fn contains_fn(tokens: TokenStream) -> bool {
@@ -315,25 +350,35 @@ fn contains_fn(tokens: TokenStream) -> bool {
315350
})
316351
}
317352

318-
fn fold_token_stream(tokens: TokenStream) -> TokenStream {
319-
tokens
320-
.into_iter()
321-
.map(|tt| match tt {
353+
fn visit_token_stream(tokens: &mut TokenStream) -> bool {
354+
let mut out = Vec::new();
355+
let mut modified = false;
356+
for tt in tokens.clone() {
357+
match tt {
322358
TokenTree::Ident(mut ident) => {
323-
prepend_underscore_to_self(&mut ident);
324-
TokenTree::Ident(ident)
359+
modified |= prepend_underscore_to_self(&mut ident);
360+
out.push(TokenTree::Ident(ident));
325361
}
326362
TokenTree::Group(group) => {
327-
let content = fold_token_stream(group.stream());
328-
TokenTree::Group(Group::new(group.delimiter(), content))
363+
let mut content = group.stream();
364+
modified |= visit_token_stream(&mut content);
365+
let mut new = Group::new(group.delimiter(), content);
366+
new.set_span(group.span());
367+
out.push(TokenTree::Group(new));
329368
}
330-
other => other,
331-
})
332-
.collect()
369+
other => out.push(other),
370+
}
371+
}
372+
if modified {
373+
*tokens = TokenStream::from_iter(out);
374+
}
375+
modified
333376
}
334377

335-
pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) {
336-
if ident == "self" {
378+
pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
379+
let modified = ident == "self";
380+
if modified {
337381
*ident = Ident::new("__self", ident.span());
338382
}
383+
modified
339384
}

tests/pinned_drop.rs

+43-18
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ fn self_call() {
112112
}
113113
}
114114

115-
// See also `ui/pinned_drop/self.rs`.
116115
#[test]
117116
fn self_expr() {
118117
#[pin_project(PinnedDrop)]
@@ -136,25 +135,26 @@ fn self_expr() {
136135
let _: Self = Self(0);
137136
}
138137
}
138+
}
139139

140-
#[rustversion::since(1.37)]
140+
#[rustversion::since(1.37)]
141+
#[test]
142+
fn self_expr_enum() {
141143
#[pin_project(PinnedDrop)]
142144
pub enum Enum {
143145
StructVariant { x: usize },
144146
TupleVariant(usize),
145147
}
146148

147-
#[rustversion::since(1.37)]
148149
#[pinned_drop]
149150
impl PinnedDrop for Enum {
150151
fn drop(mut self: Pin<&mut Self>) {
151-
// let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401]
152+
let _: Self = Self::StructVariant { x: 0 };
152153
let _: Self = Self::TupleVariant(0);
153154
}
154155
}
155156
}
156157

157-
// See also `ui/pinned_drop/self.rs`.
158158
#[test]
159159
fn self_pat() {
160160
#[pin_project(PinnedDrop)]
@@ -164,12 +164,13 @@ fn self_pat() {
164164

165165
#[pinned_drop]
166166
impl PinnedDrop for Struct {
167+
#[allow(irrefutable_let_patterns)]
167168
fn drop(mut self: Pin<&mut Self>) {
168-
// match *self {
169-
// Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401]
170-
// }
171-
// if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
172-
// let Self { x: _ } = *self; //~ ERROR can't use generic parameters from outer function [E0401]
169+
match *self {
170+
Self { x: _ } => {}
171+
}
172+
if let Self { x: _ } = *self {}
173+
let Self { x: _ } = *self;
173174
}
174175
}
175176

@@ -187,24 +188,48 @@ fn self_pat() {
187188
let Self(_) = *self;
188189
}
189190
}
191+
}
190192

191-
#[rustversion::since(1.37)]
193+
#[rustversion::since(1.37)]
194+
#[test]
195+
fn self_pat_enum() {
192196
#[pin_project(PinnedDrop)]
193197
pub enum Enum {
194198
StructVariant { x: usize },
195199
TupleVariant(usize),
196200
}
197201

198-
#[rustversion::since(1.37)]
199202
#[pinned_drop]
200203
impl PinnedDrop for Enum {
201204
fn drop(mut self: Pin<&mut Self>) {
202-
// match *self {
203-
// Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401]
204-
// Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401]
205-
// }
206-
// if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
207-
// if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
205+
match *self {
206+
Self::StructVariant { x: _ } => {}
207+
Self::TupleVariant(_) => {}
208+
}
209+
if let Self::StructVariant { x: _ } = *self {}
210+
if let Self::TupleVariant(_) = *self {}
211+
}
212+
}
213+
}
214+
215+
// See also `ui/pinned_drop/self.rs`.
216+
#[rustversion::since(1.40)] // https://github.com/rust-lang/rust/pull/64690
217+
#[test]
218+
fn self_in_macro_def() {
219+
#[pin_project(PinnedDrop)]
220+
pub struct Struct {
221+
x: usize,
222+
}
223+
224+
#[pinned_drop]
225+
impl PinnedDrop for Struct {
226+
fn drop(self: Pin<&mut Self>) {
227+
macro_rules! t {
228+
() => {{
229+
let _ = self;
230+
}};
231+
}
232+
t!();
208233
}
209234
}
210235
}

tests/ui/pinned_drop/self.rs

+12-77
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,26 @@
11
use pin_project::{pin_project, pinned_drop};
22
use std::pin::Pin;
33

4-
fn self_expr() {
4+
fn self_in_macro_def() {
55
#[pin_project(PinnedDrop)]
66
pub struct Struct {
77
x: usize,
88
}
99

1010
#[pinned_drop]
1111
impl PinnedDrop for Struct {
12-
fn drop(mut self: Pin<&mut Self>) {
13-
let _: Self = Self { x: 0 };
14-
}
15-
}
16-
17-
#[pin_project(PinnedDrop)]
18-
pub struct TupleStruct(usize);
19-
20-
#[pinned_drop]
21-
impl PinnedDrop for TupleStruct {
22-
fn drop(mut self: Pin<&mut Self>) {
23-
let _: Self = Self(0);
24-
}
25-
}
26-
27-
#[pin_project(PinnedDrop)]
28-
pub enum Enum {
29-
StructVariant { x: usize },
30-
TupleVariant(usize),
31-
}
32-
33-
#[pinned_drop]
34-
impl PinnedDrop for Enum {
35-
fn drop(mut self: Pin<&mut Self>) {
36-
let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401]
37-
let _: Self = Self::TupleVariant(0);
38-
}
39-
}
40-
}
41-
42-
fn self_pat() {
43-
#[pin_project(PinnedDrop)]
44-
pub struct Struct {
45-
x: usize,
46-
}
47-
48-
#[pinned_drop]
49-
impl PinnedDrop for Struct {
50-
fn drop(mut self: Pin<&mut Self>) {
51-
match *self {
52-
Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401]
53-
}
54-
if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
55-
let Self { x: _ } = *self; //~ ERROR can't use generic parameters from outer function [E0401]
56-
}
57-
}
58-
59-
#[pin_project(PinnedDrop)]
60-
pub struct TupleStruct(usize);
61-
62-
#[pinned_drop]
63-
impl PinnedDrop for TupleStruct {
64-
#[allow(irrefutable_let_patterns)]
65-
fn drop(mut self: Pin<&mut Self>) {
66-
match *self {
67-
Self(_) => {}
68-
}
69-
if let Self(_) = *self {}
70-
let Self(_) = *self;
71-
}
72-
}
73-
74-
#[pin_project(PinnedDrop)]
75-
pub enum Enum {
76-
StructVariant { x: usize },
77-
TupleVariant(usize),
78-
}
79-
80-
#[pinned_drop]
81-
impl PinnedDrop for Enum {
82-
fn drop(mut self: Pin<&mut Self>) {
83-
match *self {
84-
Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401]
85-
Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401]
12+
fn drop(self: Pin<&mut Self>) {
13+
macro_rules! t {
14+
() => {{
15+
let _ = self; //~ ERROR can't capture dynamic environment in a fn item
16+
17+
fn f(self: ()) {
18+
//~^ ERROR `self` parameter is only allowed in associated functions
19+
let _ = self;
20+
}
21+
}};
8622
}
87-
if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
88-
if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401]
23+
t!();
8924
}
9025
}
9126
}

0 commit comments

Comments
 (0)