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