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