]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
Rollup merge of #87346 - rylev:rename-force-warn, r=nikomatsakis
[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 = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
76         let params =
77             lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
78
79         match self.kind {
80             PathKind::Global => cx.path_all(span, true, idents, params),
81             PathKind::Local => cx.path_all(span, false, idents, params),
82             PathKind::Std => {
83                 let def_site = cx.with_def_site_ctxt(DUMMY_SP);
84                 idents.insert(0, Ident::new(kw::DollarCrate, def_site));
85                 cx.path_all(span, false, idents, params)
86             }
87         }
88     }
89 }
90
91 /// A type. Supports pointers, Self, and literals.
92 #[derive(Clone)]
93 pub enum Ty {
94     Self_,
95     /// &/Box/ Ty
96     Ptr(Box<Ty>, PtrTy),
97     /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
98     /// parameter, and things like `i32`
99     Literal(Path),
100     /// includes unit
101     Tuple(Vec<Ty>),
102 }
103
104 pub fn borrowed_ptrty() -> PtrTy {
105     Borrowed(None, ast::Mutability::Not)
106 }
107 pub fn borrowed(ty: Box<Ty>) -> Ty {
108     Ptr(ty, borrowed_ptrty())
109 }
110
111 pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
112     Some(Some(borrowed_ptrty()))
113 }
114
115 pub fn borrowed_self() -> Ty {
116     borrowed(Box::new(Self_))
117 }
118
119 pub fn nil_ty() -> Ty {
120     Tuple(Vec::new())
121 }
122
123 fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
124     lt.map(|ident| cx.lifetime(span, ident))
125 }
126
127 fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
128     mk_lifetime(cx, span, lt).into_iter().collect()
129 }
130
131 impl Ty {
132     pub fn to_ty(
133         &self,
134         cx: &ExtCtxt<'_>,
135         span: Span,
136         self_ty: Ident,
137         self_generics: &Generics,
138     ) -> P<ast::Ty> {
139         match *self {
140             Ptr(ref ty, ref ptr) => {
141                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
142                 match *ptr {
143                     Borrowed(ref lt, mutbl) => {
144                         let lt = mk_lifetime(cx, span, lt);
145                         cx.ty_rptr(span, raw_ty, lt, mutbl)
146                     }
147                     Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
148                 }
149             }
150             Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
151             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
152             Tuple(ref fields) => {
153                 let ty = ast::TyKind::Tup(
154                     fields.iter().map(|f| f.to_ty(cx, span, self_ty, self_generics)).collect(),
155                 );
156                 cx.ty(span, ty)
157             }
158         }
159     }
160
161     pub fn to_path(
162         &self,
163         cx: &ExtCtxt<'_>,
164         span: Span,
165         self_ty: Ident,
166         generics: &Generics,
167     ) -> ast::Path {
168         match *self {
169             Self_ => {
170                 let params: Vec<_> = generics
171                     .params
172                     .iter()
173                     .map(|param| match param.kind {
174                         GenericParamKind::Lifetime { .. } => {
175                             GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
176                         }
177                         GenericParamKind::Type { .. } => {
178                             GenericArg::Type(cx.ty_ident(span, param.ident))
179                         }
180                         GenericParamKind::Const { .. } => {
181                             GenericArg::Const(cx.const_ident(span, param.ident))
182                         }
183                     })
184                     .collect();
185
186                 cx.path_all(span, false, vec![self_ty], params)
187             }
188             Literal(ref p) => p.to_path(cx, span, self_ty, generics),
189             Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
190             Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
191         }
192     }
193 }
194
195 fn mk_ty_param(
196     cx: &ExtCtxt<'_>,
197     span: Span,
198     name: Symbol,
199     attrs: &[ast::Attribute],
200     bounds: &[Path],
201     self_ident: Ident,
202     self_generics: &Generics,
203 ) -> ast::GenericParam {
204     let bounds = bounds
205         .iter()
206         .map(|b| {
207             let path = b.to_path(cx, span, self_ident, self_generics);
208             cx.trait_bound(path)
209         })
210         .collect();
211     cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
212 }
213
214 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
215     Generics {
216         params,
217         where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
218         span,
219     }
220 }
221
222 /// Bounds on type parameters.
223 #[derive(Clone)]
224 pub struct Bounds {
225     pub bounds: Vec<(Symbol, Vec<Path>)>,
226 }
227
228 impl Bounds {
229     pub fn empty() -> Bounds {
230         Bounds { bounds: Vec::new() }
231     }
232     pub fn to_generics(
233         &self,
234         cx: &ExtCtxt<'_>,
235         span: Span,
236         self_ty: Ident,
237         self_generics: &Generics,
238     ) -> Generics {
239         let generic_params = self
240             .bounds
241             .iter()
242             .map(|t| {
243                 let (name, ref bounds) = *t;
244                 mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
245             })
246             .collect();
247
248         mk_generics(generic_params, span)
249     }
250 }
251
252 pub fn get_explicit_self(
253     cx: &ExtCtxt<'_>,
254     span: Span,
255     self_ptr: &Option<PtrTy>,
256 ) -> (P<Expr>, ast::ExplicitSelf) {
257     // this constructs a fresh `self` path
258     let self_path = cx.expr_self(span);
259     match *self_ptr {
260         None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))),
261         Some(ref ptr) => {
262             let self_ty = respan(
263                 span,
264                 match *ptr {
265                     Borrowed(ref lt, mutbl) => {
266                         let lt = lt.map(|s| cx.lifetime(span, s));
267                         SelfKind::Region(lt, mutbl)
268                     }
269                     Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition"),
270                 },
271             );
272             let self_expr = cx.expr_deref(span, self_path);
273             (self_expr, self_ty)
274         }
275     }
276 }