]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
New upstream version 1.68.2+dfsg1
[rustc.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)
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 }