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