Skip to content

Commit 6c5bf70

Browse files
committed
Merge pull request 1830 from taiki-e/self
2 parents 6e800ff + e81f54f commit 6c5bf70

File tree

8 files changed

+312
-6
lines changed

8 files changed

+312
-6
lines changed

serde_derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ proc-macro = true
2222
[dependencies]
2323
proc-macro2 = "1.0"
2424
quote = "1.0"
25-
syn = "1.0.60"
25+
syn = { version = "1.0.60", features = ["visit-mut"] }
2626

2727
[dev-dependencies]
2828
serde = { version = "1.0", path = "../serde" }

serde_derive/src/de.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ use bound;
88
use dummy;
99
use fragment::{Expr, Fragment, Match, Stmts};
1010
use internals::ast::{Container, Data, Field, Style, Variant};
11-
use internals::{attr, ungroup, Ctxt, Derive};
11+
use internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
1212
use pretend;
1313

1414
use std::collections::BTreeSet;
1515
use std::ptr;
1616

17-
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
17+
pub fn expand_derive_deserialize(
18+
input: &mut syn::DeriveInput,
19+
) -> Result<TokenStream, Vec<syn::Error>> {
20+
replace_receiver(input);
21+
1822
let ctxt = Ctxt::new();
1923
let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) {
2024
Some(cont) => cont,

serde_derive/src/internals/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ pub mod attr;
44
mod ctxt;
55
pub use self::ctxt::Ctxt;
66

7+
mod receiver;
8+
pub use self::receiver::replace_receiver;
9+
710
mod case;
811
mod check;
12+
mod respan;
913
mod symbol;
1014

1115
use syn::Type;
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
use super::respan::respan;
2+
use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
3+
use quote::{quote, quote_spanned};
4+
use std::{iter::FromIterator, mem};
5+
use syn::{
6+
parse_quote,
7+
punctuated::Punctuated,
8+
visit_mut::{self, VisitMut},
9+
DeriveInput, ExprPath, Macro, Path, PathArguments, QSelf, Type, TypePath,
10+
};
11+
12+
pub fn replace_receiver(input: &mut DeriveInput) {
13+
let self_ty = {
14+
let ident = &input.ident;
15+
let ty_generics = input.generics.split_for_impl().1;
16+
parse_quote!(#ident #ty_generics)
17+
};
18+
let mut visitor = ReplaceReceiver(&self_ty);
19+
visitor.visit_generics_mut(&mut input.generics);
20+
visitor.visit_data_mut(&mut input.data);
21+
}
22+
23+
struct ReplaceReceiver<'a>(&'a TypePath);
24+
25+
impl ReplaceReceiver<'_> {
26+
fn self_ty(&self, span: Span) -> TypePath {
27+
respan(self.0, span)
28+
}
29+
30+
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
31+
if path.leading_colon.is_some() {
32+
return;
33+
}
34+
35+
// Make borrow checker happy
36+
{
37+
let first = &path.segments[0];
38+
if first.ident != "Self" || !first.arguments.is_empty() {
39+
return;
40+
}
41+
}
42+
43+
if path.segments.len() == 1 {
44+
self.self_to_expr_path(path);
45+
return;
46+
}
47+
48+
let span = path.segments[0].ident.span();
49+
*qself = Some(QSelf {
50+
lt_token: Token![<](span),
51+
ty: Box::new(self.self_ty(span).into()),
52+
position: 0,
53+
as_token: None,
54+
gt_token: Token![>](span),
55+
});
56+
57+
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
58+
59+
let segments = mem::replace(&mut path.segments, Punctuated::new());
60+
path.segments = segments.into_pairs().skip(1).collect();
61+
}
62+
63+
fn self_to_expr_path(&self, path: &mut Path) {
64+
if path.leading_colon.is_some() {
65+
return;
66+
}
67+
68+
// Make borrow checker happy
69+
{
70+
let first = &path.segments[0];
71+
if first.ident != "Self" || !first.arguments.is_empty() {
72+
return;
73+
}
74+
}
75+
76+
let self_ty = self.self_ty(path.segments[0].ident.span());
77+
let variant = mem::replace(path, self_ty.path);
78+
for segment in &mut path.segments {
79+
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
80+
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
81+
bracketed.colon2_token = Some(<Token![::]>::default());
82+
}
83+
}
84+
}
85+
if variant.segments.len() > 1 {
86+
path.segments.push_punct(<Token![::]>::default());
87+
path.segments.extend(variant.segments.into_pairs().skip(1));
88+
}
89+
}
90+
91+
fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
92+
let mut out = Vec::new();
93+
let mut modified = false;
94+
let mut iter = tokens.clone().into_iter().peekable();
95+
while let Some(tt) = iter.next() {
96+
match tt {
97+
TokenTree::Ident(ident) => {
98+
if ident == "Self" {
99+
modified = true;
100+
let self_ty = self.self_ty(ident.span());
101+
match iter.peek() {
102+
Some(TokenTree::Punct(p))
103+
if p.as_char() == ':' && p.spacing() == Spacing::Joint => {}
104+
_ => {
105+
out.extend(quote!(#self_ty));
106+
continue;
107+
}
108+
}
109+
let next = iter.next().unwrap();
110+
match iter.peek() {
111+
Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
112+
let span = ident.span();
113+
out.extend(quote_spanned!(span=> <#self_ty>));
114+
}
115+
_ => out.extend(quote!(#self_ty)),
116+
}
117+
out.push(next);
118+
} else {
119+
out.push(TokenTree::Ident(ident));
120+
}
121+
}
122+
TokenTree::Group(group) => {
123+
let mut content = group.stream();
124+
modified |= self.visit_token_stream(&mut content);
125+
let mut new = Group::new(group.delimiter(), content);
126+
new.set_span(group.span());
127+
out.push(TokenTree::Group(new));
128+
}
129+
other => out.push(other),
130+
}
131+
}
132+
if modified {
133+
*tokens = TokenStream::from_iter(out);
134+
}
135+
modified
136+
}
137+
}
138+
139+
impl VisitMut for ReplaceReceiver<'_> {
140+
// `Self` -> `Receiver`
141+
fn visit_type_mut(&mut self, ty: &mut Type) {
142+
let span = if let Type::Path(node) = ty {
143+
if node.qself.is_none() && node.path.is_ident("Self") {
144+
node.path.segments[0].ident.span()
145+
} else {
146+
self.visit_type_path_mut(node);
147+
return;
148+
}
149+
} else {
150+
visit_mut::visit_type_mut(self, ty);
151+
return;
152+
};
153+
*ty = self.self_ty(span).into();
154+
}
155+
156+
// `Self::Assoc` -> `<Receiver>::Assoc`
157+
fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
158+
if ty.qself.is_none() {
159+
self.self_to_qself(&mut ty.qself, &mut ty.path);
160+
}
161+
visit_mut::visit_type_path_mut(self, ty);
162+
}
163+
164+
// `Self::method` -> `<Receiver>::method`
165+
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
166+
if expr.qself.is_none() {
167+
self.self_to_qself(&mut expr.qself, &mut expr.path);
168+
}
169+
visit_mut::visit_expr_path_mut(self, expr);
170+
}
171+
172+
fn visit_macro_mut(&mut self, mac: &mut Macro) {
173+
// We can't tell in general whether `self` inside a macro invocation
174+
// refers to the self in the argument list or a different self
175+
// introduced within the macro. Heuristic: if the macro input contains
176+
// `fn`, then `self` is more likely to refer to something other than the
177+
// outer function's self argument.
178+
if !contains_fn(mac.tokens.clone()) {
179+
self.visit_token_stream(&mut mac.tokens);
180+
}
181+
}
182+
}
183+
184+
fn contains_fn(tokens: TokenStream) -> bool {
185+
tokens.into_iter().any(|tt| match tt {
186+
TokenTree::Ident(ident) => ident == "fn",
187+
TokenTree::Group(group) => contains_fn(group.stream()),
188+
_ => false,
189+
})
190+
}

serde_derive/src/internals/respan.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use proc_macro2::{Span, TokenStream};
2+
use quote::ToTokens;
3+
use syn::parse::Parse;
4+
5+
pub(crate) fn respan<T>(node: &T, span: Span) -> T
6+
where
7+
T: ToTokens + Parse,
8+
{
9+
let tokens = node.to_token_stream();
10+
let respanned = respan_tokens(tokens, span);
11+
syn::parse2(respanned).unwrap()
12+
}
13+
14+
fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream {
15+
tokens
16+
.into_iter()
17+
.map(|mut token| {
18+
token.set_span(span);
19+
token
20+
})
21+
.collect()
22+
}

serde_derive/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
8787

8888
#[proc_macro_derive(Deserialize, attributes(serde))]
8989
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
90-
let input = parse_macro_input!(input as DeriveInput);
91-
de::expand_derive_deserialize(&input)
90+
let mut input = parse_macro_input!(input as DeriveInput);
91+
de::expand_derive_deserialize(&mut input)
9292
.unwrap_or_else(to_compile_errors)
9393
.into()
9494
}

serde_derive_internals/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ path = "lib.rs"
1616
[dependencies]
1717
proc-macro2 = "1.0"
1818
quote = "1.0"
19-
syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
19+
syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls", "visit-mut"] }
2020

2121
[package.metadata.docs.rs]
2222
targets = ["x86_64-unknown-linux-gnu"]

test_suite/tests/test_self.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[test]
4+
fn test_self() {
5+
pub trait Trait {
6+
type Assoc;
7+
}
8+
9+
#[derive(Deserialize, Serialize)]
10+
pub struct Generics<T: Trait<Assoc = Self>>
11+
where
12+
Self: Trait<Assoc = Self>,
13+
<Self as Trait>::Assoc: Sized,
14+
{
15+
_f: T,
16+
}
17+
18+
impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
19+
type Assoc = Self;
20+
}
21+
22+
#[derive(Deserialize, Serialize)]
23+
pub struct Struct {
24+
_f1: Box<Self>,
25+
_f2: Box<<Self as Trait>::Assoc>,
26+
_f4: [(); Self::ASSOC],
27+
_f5: [(); Self::assoc()],
28+
}
29+
30+
impl Struct {
31+
const ASSOC: usize = 1;
32+
const fn assoc() -> usize {
33+
0
34+
}
35+
}
36+
37+
impl Trait for Struct {
38+
type Assoc = Self;
39+
}
40+
41+
#[derive(Deserialize, Serialize)]
42+
struct Tuple(
43+
Box<Self>,
44+
Box<<Self as Trait>::Assoc>,
45+
[(); Self::ASSOC],
46+
[(); Self::assoc()],
47+
);
48+
49+
impl Tuple {
50+
const ASSOC: usize = 1;
51+
const fn assoc() -> usize {
52+
0
53+
}
54+
}
55+
56+
impl Trait for Tuple {
57+
type Assoc = Self;
58+
}
59+
60+
#[derive(Deserialize, Serialize)]
61+
enum Enum {
62+
Struct {
63+
_f1: Box<Self>,
64+
_f2: Box<<Self as Trait>::Assoc>,
65+
_f4: [(); Self::ASSOC],
66+
_f5: [(); Self::assoc()],
67+
},
68+
Tuple(
69+
Box<Self>,
70+
Box<<Self as Trait>::Assoc>,
71+
[(); Self::ASSOC],
72+
[(); Self::assoc()],
73+
),
74+
}
75+
76+
impl Enum {
77+
const ASSOC: usize = 1;
78+
const fn assoc() -> usize {
79+
0
80+
}
81+
}
82+
83+
impl Trait for Enum {
84+
type Assoc = Self;
85+
}
86+
}

0 commit comments

Comments
 (0)