]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/generic/ty.rs
Auto merge of #30457 - Manishearth:rollup, r=Manishearth
[rust.git] / src / libsyntax_ext / deriving / generic / ty.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
12 //! when specifying impls to be derived.
13
14 pub use self::PtrTy::*;
15 pub use self::Ty::*;
16
17 use syntax::ast;
18 use syntax::ast::{Expr,Generics,Ident};
19 use syntax::ext::base::ExtCtxt;
20 use syntax::ext::build::AstBuilder;
21 use syntax::codemap::{Span,respan};
22 use syntax::parse::token::special_idents;
23 use syntax::ptr::P;
24
25 /// The types of pointers
26 #[derive(Clone, Eq, PartialEq)]
27 #[allow(dead_code)]
28 pub enum PtrTy<'a> {
29     /// &'lifetime mut
30     Borrowed(Option<&'a str>, ast::Mutability),
31     /// *mut
32     Raw(ast::Mutability),
33 }
34
35 /// A path, e.g. `::std::option::Option::<i32>` (global). Has support
36 /// for type parameters and a lifetime.
37 #[derive(Clone, Eq, PartialEq)]
38 pub struct Path<'a> {
39     pub path: Vec<&'a str> ,
40     pub lifetime: Option<&'a str>,
41     pub params: Vec<Box<Ty<'a>>>,
42     pub global: bool,
43 }
44
45 impl<'a> Path<'a> {
46     pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> {
47         Path::new_(path, None, Vec::new(), true)
48     }
49     pub fn new_local<'r>(path: &'r str) -> Path<'r> {
50         Path::new_(vec!( path ), None, Vec::new(), false)
51     }
52     pub fn new_<'r>(path: Vec<&'r str> ,
53                     lifetime: Option<&'r str>,
54                     params: Vec<Box<Ty<'r>>>,
55                     global: bool)
56                     -> Path<'r> {
57         Path {
58             path: path,
59             lifetime: lifetime,
60             params: params,
61             global: global
62         }
63     }
64
65     pub fn to_ty(&self,
66                  cx: &ExtCtxt,
67                  span: Span,
68                  self_ty: Ident,
69                  self_generics: &Generics)
70                  -> P<ast::Ty> {
71         cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
72     }
73     pub fn to_path(&self,
74                    cx: &ExtCtxt,
75                    span: Span,
76                    self_ty: Ident,
77                    self_generics: &Generics)
78                    -> ast::Path {
79         let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
80         let lt = mk_lifetimes(cx, span, &self.lifetime);
81         let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
82
83         cx.path_all(span, self.global, idents, lt, tys, Vec::new())
84     }
85 }
86
87 /// A type. Supports pointers, Self, and literals
88 #[derive(Clone, Eq, PartialEq)]
89 pub enum Ty<'a> {
90     Self_,
91     /// &/Box/ Ty
92     Ptr(Box<Ty<'a>>, PtrTy<'a>),
93     /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
94     /// parameter, and things like `i32`
95     Literal(Path<'a>),
96     /// includes unit
97     Tuple(Vec<Ty<'a>> )
98 }
99
100 pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
101     Borrowed(None, ast::MutImmutable)
102 }
103 pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
104     Ptr(ty, borrowed_ptrty())
105 }
106
107 pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
108     Some(Some(borrowed_ptrty()))
109 }
110
111 pub fn borrowed_self<'r>() -> Ty<'r> {
112     borrowed(Box::new(Self_))
113 }
114
115 pub fn nil_ty<'r>() -> Ty<'r> {
116     Tuple(Vec::new())
117 }
118
119 fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
120     match *lt {
121         Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)),
122         None => None
123     }
124 }
125
126 fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
127     match *lt {
128         Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)),
129         None => vec!()
130     }
131 }
132
133 impl<'a> Ty<'a> {
134     pub fn to_ty(&self,
135                  cx: &ExtCtxt,
136                  span: Span,
137                  self_ty: Ident,
138                  self_generics: &Generics)
139                  -> P<ast::Ty> {
140         match *self {
141             Ptr(ref ty, ref ptr) => {
142                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
143                 match *ptr {
144                     Borrowed(ref lt, mutbl) => {
145                         let lt = mk_lifetime(cx, span, lt);
146                         cx.ty_rptr(span, raw_ty, lt, mutbl)
147                     }
148                     Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl)
149                 }
150             }
151             Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
152             Self_  => {
153                 cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
154             }
155             Tuple(ref fields) => {
156                 let ty = ast::TyTup(fields.iter()
157                     .map(|f| f.to_ty(cx, span, self_ty, self_generics))
158                     .collect());
159                 cx.ty(span, ty)
160             }
161         }
162     }
163
164     pub fn to_path(&self,
165                    cx: &ExtCtxt,
166                    span: Span,
167                    self_ty: Ident,
168                    self_generics: &Generics)
169                    -> ast::Path {
170         match *self {
171             Self_ => {
172                 let self_params = self_generics.ty_params.map(|ty_param| {
173                     cx.ty_ident(span, ty_param.ident)
174                 });
175                 let lifetimes = self_generics.lifetimes.iter()
176                                                        .map(|d| d.lifetime)
177                                                        .collect();
178
179                 cx.path_all(span, false, vec!(self_ty), lifetimes,
180                             self_params.into_vec(), Vec::new())
181             }
182             Literal(ref p) => {
183                 p.to_path(cx, span, self_ty, self_generics)
184             }
185             Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `derive`") }
186             Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `derive`") }
187         }
188     }
189 }
190
191
192 fn mk_ty_param(cx: &ExtCtxt,
193                span: Span,
194                name: &str,
195                bounds: &[Path],
196                self_ident: Ident,
197                self_generics: &Generics)
198                -> ast::TyParam {
199     let bounds =
200         bounds.iter().map(|b| {
201             let path = b.to_path(cx, span, self_ident, self_generics);
202             cx.typarambound(path)
203         }).collect();
204     cx.typaram(span, cx.ident_of(name), bounds, None)
205 }
206
207 fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
208                -> Generics {
209     Generics {
210         lifetimes: lifetimes,
211         ty_params: P::from_vec(ty_params),
212         where_clause: ast::WhereClause {
213             id: ast::DUMMY_NODE_ID,
214             predicates: Vec::new(),
215         },
216     }
217 }
218
219 /// Lifetimes and bounds on type parameters
220 #[derive(Clone)]
221 pub struct LifetimeBounds<'a> {
222     pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
223     pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
224 }
225
226 impl<'a> LifetimeBounds<'a> {
227     pub fn empty() -> LifetimeBounds<'a> {
228         LifetimeBounds {
229             lifetimes: Vec::new(), bounds: Vec::new()
230         }
231     }
232     pub fn to_generics(&self,
233                        cx: &ExtCtxt,
234                        span: Span,
235                        self_ty: Ident,
236                        self_generics: &Generics)
237                        -> Generics {
238         let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| {
239             let bounds =
240                 bounds.iter().map(
241                     |b| cx.lifetime(span, cx.ident_of(*b).name)).collect();
242             cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
243         }).collect();
244         let ty_params = self.bounds.iter().map(|t| {
245             match *t {
246                 (ref name, ref bounds) => {
247                     mk_ty_param(cx,
248                                 span,
249                                 *name,
250                                 bounds,
251                                 self_ty,
252                                 self_generics)
253                 }
254             }
255         }).collect();
256         mk_generics(lifetimes, ty_params)
257     }
258 }
259
260 pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
261     -> (P<Expr>, ast::ExplicitSelf) {
262     // this constructs a fresh `self` path, which will match the fresh `self` binding
263     // created below.
264     let self_path = cx.expr_self(span);
265     match *self_ptr {
266         None => {
267             (self_path, respan(span, ast::SelfValue(special_idents::self_)))
268         }
269         Some(ref ptr) => {
270             let self_ty = respan(
271                 span,
272                 match *ptr {
273                     Borrowed(ref lt, mutbl) => {
274                         let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name));
275                         ast::SelfRegion(lt, mutbl, special_idents::self_)
276                     }
277                     Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition")
278                 });
279             let self_expr = cx.expr_deref(span, self_path);
280             (self_expr, self_ty)
281         }
282     }
283 }