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