• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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