]> git.proxmox.com Git - rustc.git/blame - src/vendor/serde_derive/src/bound.rs
New upstream version 1.29.0+dfsg1
[rustc.git] / src / vendor / serde_derive / src / bound.rs
CommitLineData
3b2f2976
XL
1// Copyright 2017 Serde Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::collections::HashSet;
10
83c7162d
XL
11use syn;
12use syn::punctuated::{Pair, Punctuated};
13use syn::visit::{self, Visit};
3b2f2976 14
83c7162d 15use internals::ast::{Container, Data};
3b2f2976
XL
16use internals::attr;
17
83c7162d 18use proc_macro2::Span;
3b2f2976
XL
19
20// Remove the default from every type parameter because in the generated impls
21// they look like associated types: "error: associated type bindings are not
22// allowed here".
23pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
24 syn::Generics {
0531ce1d
XL
25 params: generics
26 .params
3b2f2976 27 .iter()
0531ce1d 28 .map(|param| match *param {
83c7162d
XL
29 syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam {
30 eq_token: None,
31 default: None,
32 ..param.clone()
33 }),
0531ce1d 34 _ => param.clone(),
ff7c6d11 35 })
3b2f2976
XL
36 .collect(),
37 ..generics.clone()
38 }
39}
40
41pub fn with_where_predicates(
42 generics: &syn::Generics,
43 predicates: &[syn::WherePredicate],
44) -> syn::Generics {
45 let mut generics = generics.clone();
83c7162d
XL
46 generics
47 .make_where_clause()
3b2f2976 48 .predicates
0531ce1d 49 .extend(predicates.into_iter().cloned());
3b2f2976
XL
50 generics
51}
52
83c7162d 53pub fn with_where_predicates_from_fields(
3b2f2976
XL
54 cont: &Container,
55 generics: &syn::Generics,
83c7162d
XL
56 from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
57) -> syn::Generics {
8faf50e0
XL
58 let predicates = cont
59 .data
3b2f2976
XL
60 .all_fields()
61 .flat_map(|field| from_field(&field.attrs))
62 .flat_map(|predicates| predicates.to_vec());
63
64 let mut generics = generics.clone();
83c7162d 65 generics.make_where_clause().predicates.extend(predicates);
3b2f2976
XL
66 generics
67}
68
8faf50e0
XL
69pub fn with_where_predicates_from_variants(
70 cont: &Container,
71 generics: &syn::Generics,
72 from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
73) -> syn::Generics {
74 let variants = match cont.data {
75 Data::Enum(ref variants) => variants,
76 Data::Struct(_, _) => {
77 return generics.clone();
78 }
79 };
80
81 let predicates = variants
82 .iter()
83 .flat_map(|variant| from_variant(&variant.attrs))
84 .flat_map(|predicates| predicates.to_vec());
85
86 let mut generics = generics.clone();
87 generics.make_where_clause().predicates.extend(predicates);
88 generics
89}
90
3b2f2976
XL
91// Puts the given bound on any generic type parameters that are used in fields
92// for which filter returns true.
93//
94// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
95//
96// struct S<'b, A, B: 'b, C> {
97// a: A,
98// b: Option<&'b B>
99// #[serde(skip_serializing)]
100// c: C,
101// }
83c7162d 102pub fn with_bound(
3b2f2976
XL
103 cont: &Container,
104 generics: &syn::Generics,
83c7162d 105 filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
3b2f2976 106 bound: &syn::Path,
83c7162d
XL
107) -> syn::Generics {
108 struct FindTyParams<'ast> {
3b2f2976
XL
109 // Set of all generic type parameters on the current struct (A, B, C in
110 // the example). Initialized up front.
83c7162d
XL
111 all_type_params: HashSet<syn::Ident>,
112
3b2f2976
XL
113 // Set of generic type parameters used in fields for which filter
114 // returns true (A and B in the example). Filled in as the visitor sees
115 // them.
83c7162d
XL
116 relevant_type_params: HashSet<syn::Ident>,
117
118 // Fields whose type is an associated type of one of the generic type
119 // parameters.
120 associated_type_usage: Vec<&'ast syn::TypePath>,
3b2f2976 121 }
83c7162d
XL
122 impl<'ast> Visit<'ast> for FindTyParams<'ast> {
123 fn visit_field(&mut self, field: &'ast syn::Field) {
124 if let syn::Type::Path(ref ty) = field.ty {
125 if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() {
126 if self.all_type_params.contains(&t.ident) {
127 self.associated_type_usage.push(ty);
128 }
129 }
130 }
131 self.visit_type(&field.ty);
132 }
133
134 fn visit_path(&mut self, path: &'ast syn::Path) {
3b2f2976 135 if let Some(seg) = path.segments.last() {
0531ce1d 136 if seg.into_value().ident == "PhantomData" {
3b2f2976
XL
137 // Hardcoded exception, because PhantomData<T> implements
138 // Serialize and Deserialize whether or not T implements it.
139 return;
140 }
141 }
0531ce1d 142 if path.leading_colon.is_none() && path.segments.len() == 1 {
8faf50e0
XL
143 let id = &path.segments[0].ident;
144 if self.all_type_params.contains(id) {
145 self.relevant_type_params.insert(id.clone());
3b2f2976
XL
146 }
147 }
0531ce1d 148 visit::visit_path(self, path);
3b2f2976 149 }
abe05a73
XL
150
151 // Type parameter should not be considered used by a macro path.
152 //
153 // struct TypeMacro<T> {
154 // mac: T!(),
155 // marker: PhantomData<T>,
156 // }
83c7162d 157 fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
3b2f2976
XL
158 }
159
8faf50e0
XL
160 let all_type_params = generics
161 .type_params()
162 .map(|param| param.ident.clone())
163 .collect();
3b2f2976 164
3b2f2976 165 let mut visitor = FindTyParams {
83c7162d
XL
166 all_type_params: all_type_params,
167 relevant_type_params: HashSet::new(),
168 associated_type_usage: Vec::new(),
3b2f2976 169 };
0531ce1d
XL
170 match cont.data {
171 Data::Enum(ref variants) => for variant in variants.iter() {
ff7c6d11
XL
172 let relevant_fields = variant
173 .fields
174 .iter()
175 .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
176 for field in relevant_fields {
83c7162d 177 visitor.visit_field(field.original);
ea8adc8c 178 }
ff7c6d11 179 },
0531ce1d 180 Data::Struct(_, ref fields) => {
ea8adc8c 181 for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
83c7162d 182 visitor.visit_field(field.original);
ea8adc8c
XL
183 }
184 }
3b2f2976
XL
185 }
186
83c7162d
XL
187 let relevant_type_params = visitor.relevant_type_params;
188 let associated_type_usage = visitor.associated_type_usage;
3b2f2976 189 let new_predicates = generics
83c7162d 190 .type_params()
8faf50e0 191 .map(|param| param.ident.clone())
83c7162d
XL
192 .filter(|id| relevant_type_params.contains(id))
193 .map(|id| syn::TypePath {
194 qself: None,
195 path: id.into(),
0531ce1d 196 })
83c7162d
XL
197 .chain(associated_type_usage.into_iter().cloned())
198 .map(|bounded_ty| {
0531ce1d
XL
199 syn::WherePredicate::Type(syn::PredicateType {
200 lifetimes: None,
ff7c6d11 201 // the type parameter that is being bounded e.g. T
83c7162d 202 bounded_ty: syn::Type::Path(bounded_ty),
8faf50e0 203 colon_token: <Token![:]>::default(),
ff7c6d11 204 // the bound e.g. Serialize
83c7162d
XL
205 bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
206 paren_token: None,
207 modifier: syn::TraitBoundModifier::None,
208 lifetimes: None,
209 path: bound.clone(),
210 })].into_iter()
211 .collect(),
ff7c6d11
XL
212 })
213 });
3b2f2976
XL
214
215 let mut generics = generics.clone();
83c7162d
XL
216 generics
217 .make_where_clause()
0531ce1d
XL
218 .predicates
219 .extend(new_predicates);
3b2f2976
XL
220 generics
221}
222
223pub fn with_self_bound(
224 cont: &Container,
225 generics: &syn::Generics,
226 bound: &syn::Path,
227) -> syn::Generics {
228 let mut generics = generics.clone();
83c7162d
XL
229 generics
230 .make_where_clause()
3b2f2976 231 .predicates
0531ce1d
XL
232 .push(syn::WherePredicate::Type(syn::PredicateType {
233 lifetimes: None,
234 // the type that is being bounded e.g. MyStruct<'a, T>
235 bounded_ty: type_of_item(cont),
8faf50e0 236 colon_token: <Token![:]>::default(),
0531ce1d 237 // the bound e.g. Default
83c7162d
XL
238 bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
239 paren_token: None,
240 modifier: syn::TraitBoundModifier::None,
241 lifetimes: None,
242 path: bound.clone(),
243 })].into_iter()
244 .collect(),
0531ce1d 245 }));
3b2f2976
XL
246 generics
247}
248
249pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
83c7162d 250 let bound = syn::Lifetime::new(lifetime, Span::call_site());
0531ce1d
XL
251 let def = syn::LifetimeDef {
252 attrs: Vec::new(),
8faf50e0 253 lifetime: bound.clone(),
0531ce1d
XL
254 colon_token: None,
255 bounds: Punctuated::new(),
256 };
3b2f2976 257
0531ce1d
XL
258 let params = Some(syn::GenericParam::Lifetime(def))
259 .into_iter()
83c7162d
XL
260 .chain(generics.params.iter().cloned().map(|mut param| {
261 match param {
262 syn::GenericParam::Lifetime(ref mut param) => {
8faf50e0 263 param.bounds.push(bound.clone());
0531ce1d 264 }
83c7162d 265 syn::GenericParam::Type(ref mut param) => {
8faf50e0
XL
266 param
267 .bounds
268 .push(syn::TypeParamBound::Lifetime(bound.clone()));
83c7162d
XL
269 }
270 syn::GenericParam::Const(_) => {}
271 }
272 param
273 }))
0531ce1d 274 .collect();
3b2f2976 275
0531ce1d
XL
276 syn::Generics {
277 params: params,
278 ..generics.clone()
3b2f2976 279 }
3b2f2976
XL
280}
281
0531ce1d
XL
282fn type_of_item(cont: &Container) -> syn::Type {
283 syn::Type::Path(syn::TypePath {
284 qself: None,
285 path: syn::Path {
286 leading_colon: None,
83c7162d 287 segments: vec![syn::PathSegment {
8faf50e0 288 ident: cont.ident.clone(),
83c7162d
XL
289 arguments: syn::PathArguments::AngleBracketed(
290 syn::AngleBracketedGenericArguments {
291 colon2_token: None,
8faf50e0
XL
292 lt_token: <Token![<]>::default(),
293 args: cont
294 .generics
83c7162d
XL
295 .params
296 .iter()
297 .map(|param| match *param {
298 syn::GenericParam::Type(ref param) => {
299 syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
300 qself: None,
8faf50e0 301 path: param.ident.clone().into(),
83c7162d
XL
302 }))
303 }
304 syn::GenericParam::Lifetime(ref param) => {
8faf50e0 305 syn::GenericArgument::Lifetime(param.lifetime.clone())
83c7162d
XL
306 }
307 syn::GenericParam::Const(_) => {
308 panic!("Serde does not support const generics yet");
309 }
310 })
311 .collect(),
8faf50e0 312 gt_token: <Token![>]>::default(),
83c7162d
XL
313 },
314 ),
315 }].into_iter()
316 .collect(),
3b2f2976 317 },
0531ce1d 318 })
3b2f2976 319}