]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/generic/ty.rs
Simplify SaveHandler trait
[rust.git] / src / libsyntax_ext / deriving / generic / ty.rs
1 //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
2 //! when specifying impls to be derived.
3
4 pub use PtrTy::*;
5 pub use Ty::*;
6
7 use syntax::ast::{self, Expr, GenericParamKind, Generics, Ident, SelfKind, GenericArg};
8 use syntax::ext::base::ExtCtxt;
9 use syntax::ext::build::AstBuilder;
10 use syntax::source_map::{respan, DUMMY_SP};
11 use syntax::ptr::P;
12 use syntax_pos::Span;
13 use syntax_pos::symbol::kw;
14
15 /// The types of pointers
16 #[derive(Clone)]
17 pub enum PtrTy<'a> {
18     /// &'lifetime mut
19     Borrowed(Option<&'a str>, ast::Mutability),
20     /// *mut
21     Raw(ast::Mutability),
22 }
23
24 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
25 /// for type parameters and a lifetime.
26 #[derive(Clone)]
27 pub struct Path<'a> {
28     path: Vec<&'a str>,
29     lifetime: Option<&'a str>,
30     params: Vec<Box<Ty<'a>>>,
31     kind: PathKind,
32 }
33
34 #[derive(Clone)]
35 pub enum PathKind {
36     Local,
37     Global,
38     Std,
39 }
40
41 impl<'a> Path<'a> {
42     pub fn new(path: Vec<&str>) -> Path<'_> {
43         Path::new_(path, None, Vec::new(), PathKind::Std)
44     }
45     pub fn new_local(path: &str) -> Path<'_> {
46         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
47     }
48     pub fn new_<'r>(path: Vec<&'r str>,
49                     lifetime: Option<&'r str>,
50                     params: Vec<Box<Ty<'r>>>,
51                     kind: PathKind)
52                     -> Path<'r> {
53         Path {
54             path,
55             lifetime,
56             params,
57             kind,
58         }
59     }
60
61     pub fn to_ty(&self,
62                  cx: &ExtCtxt<'_>,
63                  span: Span,
64                  self_ty: Ident,
65                  self_generics: &Generics)
66                  -> P<ast::Ty> {
67         cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
68     }
69     pub fn to_path(&self,
70                    cx: &ExtCtxt<'_>,
71                    span: Span,
72                    self_ty: Ident,
73                    self_generics: &Generics)
74                    -> ast::Path {
75         let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
76         let lt = mk_lifetimes(cx, span, &self.lifetime);
77         let tys: Vec<P<ast::Ty>> =
78             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
79         let params = lt.into_iter()
80                        .map(|lt| GenericArg::Lifetime(lt))
81                        .chain(tys.into_iter().map(|ty| GenericArg::Type(ty)))
82                        .collect();
83
84         match self.kind {
85             PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
86             PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
87             PathKind::Std => {
88                 let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id);
89                 idents.insert(0, Ident::new(kw::DollarCrate, def_site));
90                 cx.path_all(span, false, idents, params, Vec::new())
91             }
92         }
93
94     }
95 }
96
97 /// A type. Supports pointers, Self, and literals.
98 #[derive(Clone)]
99 pub enum Ty<'a> {
100     Self_,
101     /// &/Box/ Ty
102     Ptr(Box<Ty<'a>>, PtrTy<'a>),
103     /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
104     /// parameter, and things like `i32`
105     Literal(Path<'a>),
106     /// includes unit
107     Tuple(Vec<Ty<'a>>),
108 }
109
110 /// A const expression. Supports literals and blocks.
111 #[derive(Clone, Eq, PartialEq)]
112 pub enum Const {
113     Literal,
114     Block,
115 }
116
117 pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
118     Borrowed(None, ast::Mutability::Immutable)
119 }
120 pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
121     Ptr(ty, borrowed_ptrty())
122 }
123
124 pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
125     Some(Some(borrowed_ptrty()))
126 }
127
128 pub fn borrowed_self<'r>() -> Ty<'r> {
129     borrowed(Box::new(Self_))
130 }
131
132 pub fn nil_ty<'r>() -> Ty<'r> {
133     Tuple(Vec::new())
134 }
135
136 fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
137     lt.map(|s|
138         cx.lifetime(span, Ident::from_str(s))
139     )
140 }
141
142 fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
143     mk_lifetime(cx, span, lt).into_iter().collect()
144 }
145
146 impl<'a> Ty<'a> {
147     pub fn to_ty(&self,
148                  cx: &ExtCtxt<'_>,
149                  span: Span,
150                  self_ty: Ident,
151                  self_generics: &Generics)
152                  -> P<ast::Ty> {
153         match *self {
154             Ptr(ref ty, ref ptr) => {
155                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
156                 match *ptr {
157                     Borrowed(ref lt, mutbl) => {
158                         let lt = mk_lifetime(cx, span, lt);
159                         cx.ty_rptr(span, raw_ty, lt, mutbl)
160                     }
161                     Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
162                 }
163             }
164             Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
165             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
166             Tuple(ref fields) => {
167                 let ty = ast::TyKind::Tup(fields.iter()
168                     .map(|f| f.to_ty(cx, span, self_ty, self_generics))
169                     .collect());
170                 cx.ty(span, ty)
171             }
172         }
173     }
174
175     pub fn to_path(&self,
176                    cx: &ExtCtxt<'_>,
177                    span: Span,
178                    self_ty: Ident,
179                    generics: &Generics)
180                    -> ast::Path {
181         match *self {
182             Self_ => {
183                 let params: Vec<_> = generics.params.iter().map(|param| match param.kind {
184                     GenericParamKind::Lifetime { .. } => {
185                         GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
186                     }
187                     GenericParamKind::Type { .. } => {
188                         GenericArg::Type(cx.ty_ident(span, param.ident))
189                     }
190                     GenericParamKind::Const { .. } => {
191                         GenericArg::Const(cx.const_ident(span, param.ident))
192                     }
193                 }).collect();
194
195                 cx.path_all(span, false, vec![self_ty], params, vec![])
196             }
197             Literal(ref p) => p.to_path(cx, span, self_ty, generics),
198             Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
199             Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
200         }
201     }
202 }
203
204
205 fn mk_ty_param(cx: &ExtCtxt<'_>,
206                span: Span,
207                name: &str,
208                attrs: &[ast::Attribute],
209                bounds: &[Path<'_>],
210                self_ident: Ident,
211                self_generics: &Generics)
212                -> ast::GenericParam {
213     let bounds = bounds.iter()
214         .map(|b| {
215             let path = b.to_path(cx, span, self_ident, self_generics);
216             cx.trait_bound(path)
217         })
218         .collect();
219     cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
220 }
221
222 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
223     Generics {
224         params,
225         where_clause: ast::WhereClause {
226             predicates: Vec::new(),
227             span,
228         },
229         span,
230     }
231 }
232
233 /// Lifetimes and bounds on type parameters
234 #[derive(Clone)]
235 pub struct LifetimeBounds<'a> {
236     pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
237     pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
238 }
239
240 impl<'a> LifetimeBounds<'a> {
241     pub fn empty() -> LifetimeBounds<'a> {
242         LifetimeBounds {
243             lifetimes: Vec::new(),
244             bounds: Vec::new(),
245         }
246     }
247     pub fn to_generics(&self,
248                        cx: &ExtCtxt<'_>,
249                        span: Span,
250                        self_ty: Ident,
251                        self_generics: &Generics)
252                        -> Generics {
253         let generic_params = self.lifetimes
254             .iter()
255             .map(|&(lt, ref bounds)| {
256                 let bounds = bounds.iter()
257                     .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
258                 cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
259             })
260             .chain(self.bounds
261                 .iter()
262                 .map(|t| {
263                     let (name, ref bounds) = *t;
264                     mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
265                 })
266             )
267             .collect();
268
269         mk_generics(generic_params, span)
270     }
271 }
272
273 pub fn get_explicit_self(cx: &ExtCtxt<'_>,
274                          span: Span,
275                          self_ptr: &Option<PtrTy<'_>>)
276                          -> (P<Expr>, ast::ExplicitSelf) {
277     // this constructs a fresh `self` path
278     let self_path = cx.expr_self(span);
279     match *self_ptr {
280         None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))),
281         Some(ref ptr) => {
282             let self_ty =
283                 respan(span,
284                        match *ptr {
285                            Borrowed(ref lt, mutbl) => {
286                                let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
287                                SelfKind::Region(lt, mutbl)
288                            }
289                            Raw(_) => {
290                                cx.span_bug(span, "attempted to use *self in deriving definition")
291                            }
292                        });
293             let self_expr = cx.expr_deref(span, self_path);
294             (self_expr, self_ty)
295         }
296     }
297 }