]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/generic/ty.rs
Auto merge of #35856 - phimuemue:master, r=brson
[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, SelfKind};
19 use syntax::ext::base::ExtCtxt;
20 use syntax::ext::build::AstBuilder;
21 use syntax::codemap::respan;
22 use syntax::ptr::P;
23 use syntax_pos::Span;
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::Mutability::Immutable)
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_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
153             Tuple(ref fields) => {
154                 let ty = ast::TyKind::Tup(fields.iter()
155                     .map(|f| f.to_ty(cx, span, self_ty, self_generics))
156                     .collect());
157                 cx.ty(span, ty)
158             }
159         }
160     }
161
162     pub fn to_path(&self,
163                    cx: &ExtCtxt,
164                    span: Span,
165                    self_ty: Ident,
166                    self_generics: &Generics)
167                    -> ast::Path {
168         match *self {
169             Self_ => {
170                 let self_params = self_generics.ty_params
171                     .iter()
172                     .map(|ty_param| cx.ty_ident(span, ty_param.ident))
173                     .collect();
174                 let lifetimes = self_generics.lifetimes
175                     .iter()
176                     .map(|d| d.lifetime)
177                     .collect();
178
179                 cx.path_all(span,
180                             false,
181                             vec![self_ty],
182                             lifetimes,
183                             self_params,
184                             Vec::new())
185             }
186             Literal(ref p) => p.to_path(cx, span, self_ty, self_generics),
187             Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
188             Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
189         }
190     }
191 }
192
193
194 fn mk_ty_param(cx: &ExtCtxt,
195                span: Span,
196                name: &str,
197                bounds: &[Path],
198                self_ident: Ident,
199                self_generics: &Generics)
200                -> ast::TyParam {
201     let bounds = bounds.iter()
202         .map(|b| {
203             let path = b.to_path(cx, span, self_ident, self_generics);
204             cx.typarambound(path)
205         })
206         .collect();
207     cx.typaram(span, cx.ident_of(name), bounds, None)
208 }
209
210 fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
211                -> Generics {
212     Generics {
213         lifetimes: lifetimes,
214         ty_params: P::from_vec(ty_params),
215         where_clause: ast::WhereClause {
216             id: ast::DUMMY_NODE_ID,
217             predicates: Vec::new(),
218         },
219         span: span,
220     }
221 }
222
223 /// Lifetimes and bounds on type parameters
224 #[derive(Clone)]
225 pub struct LifetimeBounds<'a> {
226     pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
227     pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
228 }
229
230 impl<'a> LifetimeBounds<'a> {
231     pub fn empty() -> LifetimeBounds<'a> {
232         LifetimeBounds {
233             lifetimes: Vec::new(),
234             bounds: Vec::new(),
235         }
236     }
237     pub fn to_generics(&self,
238                        cx: &ExtCtxt,
239                        span: Span,
240                        self_ty: Ident,
241                        self_generics: &Generics)
242                        -> Generics {
243         let lifetimes = self.lifetimes
244             .iter()
245             .map(|&(ref lt, ref bounds)| {
246                 let bounds = bounds.iter()
247                     .map(|b| cx.lifetime(span, cx.ident_of(*b).name))
248                     .collect();
249                 cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
250             })
251             .collect();
252         let ty_params = self.bounds
253             .iter()
254             .map(|t| {
255                 match *t {
256                     (ref name, ref bounds) => {
257                         mk_ty_param(cx, span, *name, bounds, self_ty, self_generics)
258                     }
259                 }
260             })
261             .collect();
262         mk_generics(lifetimes, ty_params, span)
263     }
264 }
265
266 pub fn get_explicit_self(cx: &ExtCtxt,
267                          span: Span,
268                          self_ptr: &Option<PtrTy>)
269                          -> (P<Expr>, ast::ExplicitSelf) {
270     // this constructs a fresh `self` path
271     let self_path = cx.expr_self(span);
272     match *self_ptr {
273         None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))),
274         Some(ref ptr) => {
275             let self_ty =
276                 respan(span,
277                        match *ptr {
278                            Borrowed(ref lt, mutbl) => {
279                                let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name));
280                                SelfKind::Region(lt, mutbl)
281                            }
282                            Raw(_) => {
283                                cx.span_bug(span, "attempted to use *self in deriving definition")
284                            }
285                        });
286             let self_expr = cx.expr_deref(span, self_path);
287             (self_expr, self_ty)
288         }
289     }
290 }