]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/generic/ty.rs
Rollup merge of #63055 - Mark-Simulacrum:save-analysis-clean-2, r=Xanewok
[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     #[allow(dead_code)]
22     Raw(ast::Mutability),
23 }
24
25 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
26 /// for type parameters and a lifetime.
27 #[derive(Clone)]
28 pub struct Path<'a> {
29     path: Vec<&'a str>,
30     lifetime: Option<&'a str>,
31     params: Vec<Box<Ty<'a>>>,
32     kind: PathKind,
33 }
34
35 #[derive(Clone)]
36 pub enum PathKind {
37     Local,
38     Global,
39     Std,
40 }
41
42 impl<'a> Path<'a> {
43     pub fn new(path: Vec<&str>) -> Path<'_> {
44         Path::new_(path, None, Vec::new(), PathKind::Std)
45     }
46     pub fn new_local(path: &str) -> Path<'_> {
47         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
48     }
49     pub fn new_<'r>(path: Vec<&'r str>,
50                     lifetime: Option<&'r str>,
51                     params: Vec<Box<Ty<'r>>>,
52                     kind: PathKind)
53                     -> Path<'r> {
54         Path {
55             path,
56             lifetime,
57             params,
58             kind,
59         }
60     }
61
62     pub fn to_ty(&self,
63                  cx: &ExtCtxt<'_>,
64                  span: Span,
65                  self_ty: Ident,
66                  self_generics: &Generics)
67                  -> P<ast::Ty> {
68         cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
69     }
70     pub fn to_path(&self,
71                    cx: &ExtCtxt<'_>,
72                    span: Span,
73                    self_ty: Ident,
74                    self_generics: &Generics)
75                    -> ast::Path {
76         let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
77         let lt = mk_lifetimes(cx, span, &self.lifetime);
78         let tys: Vec<P<ast::Ty>> =
79             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
80         let params = lt.into_iter()
81                        .map(|lt| GenericArg::Lifetime(lt))
82                        .chain(tys.into_iter().map(|ty| GenericArg::Type(ty)))
83                        .collect();
84
85         match self.kind {
86             PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
87             PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
88             PathKind::Std => {
89                 let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id);
90                 idents.insert(0, Ident::new(kw::DollarCrate, def_site));
91                 cx.path_all(span, false, idents, params, Vec::new())
92             }
93         }
94
95     }
96 }
97
98 /// A type. Supports pointers, Self, and literals.
99 #[derive(Clone)]
100 pub enum Ty<'a> {
101     Self_,
102     /// &/Box/ Ty
103     Ptr(Box<Ty<'a>>, PtrTy<'a>),
104     /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
105     /// parameter, and things like `i32`
106     Literal(Path<'a>),
107     /// includes unit
108     Tuple(Vec<Ty<'a>>),
109 }
110
111 pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
112     Borrowed(None, ast::Mutability::Immutable)
113 }
114 pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
115     Ptr(ty, borrowed_ptrty())
116 }
117
118 pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
119     Some(Some(borrowed_ptrty()))
120 }
121
122 pub fn borrowed_self<'r>() -> Ty<'r> {
123     borrowed(Box::new(Self_))
124 }
125
126 pub fn nil_ty<'r>() -> Ty<'r> {
127     Tuple(Vec::new())
128 }
129
130 fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
131     lt.map(|s|
132         cx.lifetime(span, Ident::from_str(s))
133     )
134 }
135
136 fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
137     mk_lifetime(cx, span, lt).into_iter().collect()
138 }
139
140 impl<'a> Ty<'a> {
141     pub fn to_ty(&self,
142                  cx: &ExtCtxt<'_>,
143                  span: Span,
144                  self_ty: Ident,
145                  self_generics: &Generics)
146                  -> P<ast::Ty> {
147         match *self {
148             Ptr(ref ty, ref ptr) => {
149                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
150                 match *ptr {
151                     Borrowed(ref lt, mutbl) => {
152                         let lt = mk_lifetime(cx, span, lt);
153                         cx.ty_rptr(span, raw_ty, lt, mutbl)
154                     }
155                     Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
156                 }
157             }
158             Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
159             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
160             Tuple(ref fields) => {
161                 let ty = ast::TyKind::Tup(fields.iter()
162                     .map(|f| f.to_ty(cx, span, self_ty, self_generics))
163                     .collect());
164                 cx.ty(span, ty)
165             }
166         }
167     }
168
169     pub fn to_path(&self,
170                    cx: &ExtCtxt<'_>,
171                    span: Span,
172                    self_ty: Ident,
173                    generics: &Generics)
174                    -> ast::Path {
175         match *self {
176             Self_ => {
177                 let params: Vec<_> = generics.params.iter().map(|param| match param.kind {
178                     GenericParamKind::Lifetime { .. } => {
179                         GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
180                     }
181                     GenericParamKind::Type { .. } => {
182                         GenericArg::Type(cx.ty_ident(span, param.ident))
183                     }
184                     GenericParamKind::Const { .. } => {
185                         GenericArg::Const(cx.const_ident(span, param.ident))
186                     }
187                 }).collect();
188
189                 cx.path_all(span, false, vec![self_ty], params, vec![])
190             }
191             Literal(ref p) => p.to_path(cx, span, self_ty, generics),
192             Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
193             Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
194         }
195     }
196 }
197
198
199 fn mk_ty_param(cx: &ExtCtxt<'_>,
200                span: Span,
201                name: &str,
202                attrs: &[ast::Attribute],
203                bounds: &[Path<'_>],
204                self_ident: Ident,
205                self_generics: &Generics)
206                -> ast::GenericParam {
207     let bounds = bounds.iter()
208         .map(|b| {
209             let path = b.to_path(cx, span, self_ident, self_generics);
210             cx.trait_bound(path)
211         })
212         .collect();
213     cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
214 }
215
216 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
217     Generics {
218         params,
219         where_clause: ast::WhereClause {
220             predicates: Vec::new(),
221             span,
222         },
223         span,
224     }
225 }
226
227 /// Lifetimes and bounds on type parameters
228 #[derive(Clone)]
229 pub struct LifetimeBounds<'a> {
230     pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
231     pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
232 }
233
234 impl<'a> LifetimeBounds<'a> {
235     pub fn empty() -> LifetimeBounds<'a> {
236         LifetimeBounds {
237             lifetimes: Vec::new(),
238             bounds: Vec::new(),
239         }
240     }
241     pub fn to_generics(&self,
242                        cx: &ExtCtxt<'_>,
243                        span: Span,
244                        self_ty: Ident,
245                        self_generics: &Generics)
246                        -> Generics {
247         let generic_params = self.lifetimes
248             .iter()
249             .map(|&(lt, ref bounds)| {
250                 let bounds = bounds.iter()
251                     .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
252                 cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
253             })
254             .chain(self.bounds
255                 .iter()
256                 .map(|t| {
257                     let (name, ref bounds) = *t;
258                     mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
259                 })
260             )
261             .collect();
262
263         mk_generics(generic_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 }