]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
Add ~const bounds trait bounds when using derive_const
[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 Ty::*;
5
6 use rustc_ast::ptr::P;
7 use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
8 use rustc_expand::base::ExtCtxt;
9 use rustc_span::source_map::{respan, DUMMY_SP};
10 use rustc_span::symbol::{kw, Ident, Symbol};
11 use rustc_span::Span;
12
13 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
14 /// for type parameters.
15 #[derive(Clone)]
16 pub struct Path {
17     path: Vec<Symbol>,
18     params: Vec<Box<Ty>>,
19     kind: PathKind,
20 }
21
22 #[derive(Clone)]
23 pub enum PathKind {
24     Local,
25     Global,
26     Std,
27 }
28
29 impl Path {
30     pub fn new(path: Vec<Symbol>) -> Path {
31         Path::new_(path, Vec::new(), PathKind::Std)
32     }
33     pub fn new_local(path: Symbol) -> Path {
34         Path::new_(vec![path], Vec::new(), PathKind::Local)
35     }
36     pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path {
37         Path { path, params, kind }
38     }
39
40     pub fn to_ty(
41         &self,
42         cx: &ExtCtxt<'_>,
43         span: Span,
44         self_ty: Ident,
45         self_generics: &Generics,
46     ) -> P<ast::Ty> {
47         cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
48     }
49     pub fn to_path(
50         &self,
51         cx: &ExtCtxt<'_>,
52         span: Span,
53         self_ty: Ident,
54         self_generics: &Generics,
55     ) -> ast::Path {
56         let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
57         let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
58         let params = tys.map(GenericArg::Type).collect();
59
60         match self.kind {
61             PathKind::Global => cx.path_all(span, true, idents, params),
62             PathKind::Local => cx.path_all(span, false, idents, params),
63             PathKind::Std => {
64                 let def_site = cx.with_def_site_ctxt(DUMMY_SP);
65                 idents.insert(0, Ident::new(kw::DollarCrate, def_site));
66                 cx.path_all(span, false, idents, params)
67             }
68         }
69     }
70 }
71
72 /// A type. Supports pointers, Self, and literals.
73 #[derive(Clone)]
74 pub enum Ty {
75     Self_,
76     /// A reference.
77     Ref(Box<Ty>, ast::Mutability),
78     /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
79     /// parameter, and things like `i32`
80     Path(Path),
81     /// For () return types.
82     Unit,
83 }
84
85 pub fn self_ref() -> Ty {
86     Ref(Box::new(Self_), ast::Mutability::Not)
87 }
88
89 impl Ty {
90     pub fn to_ty(
91         &self,
92         cx: &ExtCtxt<'_>,
93         span: Span,
94         self_ty: Ident,
95         self_generics: &Generics,
96     ) -> P<ast::Ty> {
97         match self {
98             Ref(ty, mutbl) => {
99                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
100                 cx.ty_ref(span, raw_ty, None, *mutbl)
101             }
102             Path(p) => p.to_ty(cx, span, self_ty, self_generics),
103             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
104             Unit => {
105                 let ty = ast::TyKind::Tup(vec![]);
106                 cx.ty(span, ty)
107             }
108         }
109     }
110
111     pub fn to_path(
112         &self,
113         cx: &ExtCtxt<'_>,
114         span: Span,
115         self_ty: Ident,
116         generics: &Generics,
117     ) -> ast::Path {
118         match self {
119             Self_ => {
120                 let params: Vec<_> = generics
121                     .params
122                     .iter()
123                     .map(|param| match param.kind {
124                         GenericParamKind::Lifetime { .. } => {
125                             GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
126                         }
127                         GenericParamKind::Type { .. } => {
128                             GenericArg::Type(cx.ty_ident(span, param.ident))
129                         }
130                         GenericParamKind::Const { .. } => {
131                             GenericArg::Const(cx.const_ident(span, param.ident))
132                         }
133                     })
134                     .collect();
135
136                 cx.path_all(span, false, vec![self_ty], params)
137             }
138             Path(p) => p.to_path(cx, span, self_ty, generics),
139             Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
140             Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
141         }
142     }
143 }
144
145 fn mk_ty_param(
146     cx: &ExtCtxt<'_>,
147     span: Span,
148     name: Symbol,
149     bounds: &[Path],
150     self_ident: Ident,
151     self_generics: &Generics,
152 ) -> ast::GenericParam {
153     let bounds = bounds
154         .iter()
155         .map(|b| {
156             let path = b.to_path(cx, span, self_ident, self_generics);
157             cx.trait_bound(path, false)
158         })
159         .collect();
160     cx.typaram(span, Ident::new(name, span), bounds, None)
161 }
162
163 /// Bounds on type parameters.
164 #[derive(Clone)]
165 pub struct Bounds {
166     pub bounds: Vec<(Symbol, Vec<Path>)>,
167 }
168
169 impl Bounds {
170     pub fn empty() -> Bounds {
171         Bounds { bounds: Vec::new() }
172     }
173     pub fn to_generics(
174         &self,
175         cx: &ExtCtxt<'_>,
176         span: Span,
177         self_ty: Ident,
178         self_generics: &Generics,
179     ) -> Generics {
180         let params = self
181             .bounds
182             .iter()
183             .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, &bounds, self_ty, self_generics))
184             .collect();
185
186         Generics {
187             params,
188             where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
189             span,
190         }
191     }
192 }
193
194 pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
195     // This constructs a fresh `self` path.
196     let self_path = cx.expr_self(span);
197     let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
198     (self_path, self_ty)
199 }