]> git.proxmox.com Git - rustc.git/blob - src/libsyntax_ext/deriving/generic/ty.rs
New upstream version 1.19.0+dfsg1
[rustc.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(s) => Some(cx.lifetime(span, Ident::from_str(s))),
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(s) => vec![cx.lifetime(span, Ident::from_str(s))],
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 attrs: &[ast::Attribute],
198 bounds: &[Path],
199 self_ident: Ident,
200 self_generics: &Generics)
201 -> ast::TyParam {
202 let bounds = bounds.iter()
203 .map(|b| {
204 let path = b.to_path(cx, span, self_ident, self_generics);
205 cx.typarambound(path)
206 })
207 .collect();
208 cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
209 }
210
211 fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
212 -> Generics {
213 Generics {
214 lifetimes: lifetimes,
215 ty_params: ty_params,
216 where_clause: ast::WhereClause {
217 id: ast::DUMMY_NODE_ID,
218 predicates: Vec::new(),
219 },
220 span: span,
221 }
222 }
223
224 /// Lifetimes and bounds on type parameters
225 #[derive(Clone)]
226 pub struct LifetimeBounds<'a> {
227 pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
228 pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
229 }
230
231 impl<'a> LifetimeBounds<'a> {
232 pub fn empty() -> LifetimeBounds<'a> {
233 LifetimeBounds {
234 lifetimes: Vec::new(),
235 bounds: Vec::new(),
236 }
237 }
238 pub fn to_generics(&self,
239 cx: &ExtCtxt,
240 span: Span,
241 self_ty: Ident,
242 self_generics: &Generics)
243 -> Generics {
244 let lifetimes = self.lifetimes
245 .iter()
246 .map(|&(lt, ref bounds)| {
247 let bounds = bounds.iter()
248 .map(|b| cx.lifetime(span, Ident::from_str(b)))
249 .collect();
250 cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds)
251 })
252 .collect();
253 let ty_params = self.bounds
254 .iter()
255 .map(|t| {
256 match *t {
257 (ref name, ref bounds) => {
258 mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
259 }
260 }
261 })
262 .collect();
263 mk_generics(lifetimes, ty_params, span)
264 }
265 }
266
267 pub fn get_explicit_self(cx: &ExtCtxt,
268 span: Span,
269 self_ptr: &Option<PtrTy>)
270 -> (P<Expr>, ast::ExplicitSelf) {
271 // this constructs a fresh `self` path
272 let self_path = cx.expr_self(span);
273 match *self_ptr {
274 None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))),
275 Some(ref ptr) => {
276 let self_ty =
277 respan(span,
278 match *ptr {
279 Borrowed(ref lt, mutbl) => {
280 let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
281 SelfKind::Region(lt, mutbl)
282 }
283 Raw(_) => {
284 cx.span_bug(span, "attempted to use *self in deriving definition")
285 }
286 });
287 let self_expr = cx.expr_deref(span, self_path);
288 (self_expr, self_ty)
289 }
290 }
291 }