blob: 8955271e794abc3b3bc0f05313b7bcac3dd6cf58 [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
2
David Tolnay771ecf42016-09-23 19:26:37 -07003/// Represents lifetimes and type parameters attached to a declaration
4/// of a function, enum, trait, etc.
David Tolnayb79ee962016-09-04 09:39:20 -07005#[derive(Debug, Clone, Eq, PartialEq, Default)]
6pub struct Generics {
7 pub lifetimes: Vec<LifetimeDef>,
8 pub ty_params: Vec<TyParam>,
David Tolnay55337722016-09-11 12:58:56 -07009 pub where_clause: WhereClause,
David Tolnayb79ee962016-09-04 09:39:20 -070010}
11
12#[derive(Debug, Clone, Eq, PartialEq)]
13pub struct Lifetime {
14 pub ident: Ident,
15}
16
David Tolnay01405f02016-10-02 09:05:02 -070017impl Lifetime {
18 pub fn new<T: Into<Ident>>(t: T) -> Self {
19 Lifetime {
20 ident: Ident::new(t),
21 }
22 }
23}
24
David Tolnay771ecf42016-09-23 19:26:37 -070025/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070026#[derive(Debug, Clone, Eq, PartialEq)]
27pub struct LifetimeDef {
28 pub lifetime: Lifetime,
29 pub bounds: Vec<Lifetime>,
30}
31
David Tolnayf9505b52016-10-02 09:18:52 -070032impl LifetimeDef {
33 pub fn new<T: Into<Ident>>(t: T) -> Self {
34 LifetimeDef {
35 lifetime: Lifetime::new(t),
36 bounds: Vec::new(),
37 }
38 }
39}
40
David Tolnayb79ee962016-09-04 09:39:20 -070041#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct TyParam {
43 pub ident: Ident,
44 pub bounds: Vec<TyParamBound>,
45 pub default: Option<Ty>,
46}
47
David Tolnay771ecf42016-09-23 19:26:37 -070048/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -070049/// `typeck::collect::compute_bounds` matches these against
50/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -070051/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -070052#[derive(Debug, Clone, Eq, PartialEq)]
53pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -070054 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070055 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070056}
57
David Tolnay771ecf42016-09-23 19:26:37 -070058/// A modifier on a bound, currently this is only used for `?Sized`, where the
59/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -070060#[derive(Debug, Copy, Clone, Eq, PartialEq)]
61pub enum TraitBoundModifier {
62 None,
63 Maybe,
64}
65
David Tolnay771ecf42016-09-23 19:26:37 -070066/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -070067#[derive(Debug, Clone, Eq, PartialEq, Default)]
68pub struct WhereClause {
69 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -070070}
71
72/// A single predicate in a `where` clause
73#[derive(Debug, Clone, Eq, PartialEq)]
74pub enum WherePredicate {
75 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
76 BoundPredicate(WhereBoundPredicate),
77 /// A lifetime predicate, e.g. `'a: 'b+'c`
78 RegionPredicate(WhereRegionPredicate),
79}
80
81/// A type bound.
82///
83/// E.g. `for<'c> Foo: Send+Clone+'c`
84#[derive(Debug, Clone, Eq, PartialEq)]
85pub struct WhereBoundPredicate {
86 /// Any lifetimes from a `for` binding
87 pub bound_lifetimes: Vec<LifetimeDef>,
88 /// The type being bounded
89 pub bounded_ty: Ty,
90 /// Trait and lifetime bounds (`Clone+Send+'static`)
91 pub bounds: Vec<TyParamBound>,
92}
93
94/// A lifetime predicate.
95///
96/// E.g. `'a: 'b+'c`
97#[derive(Debug, Clone, Eq, PartialEq)]
98pub struct WhereRegionPredicate {
99 pub lifetime: Lifetime,
100 pub bounds: Vec<Lifetime>,
101}
102
David Tolnay86eca752016-09-04 11:26:41 -0700103#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700104pub mod parsing {
105 use super::*;
David Tolnay55337722016-09-11 12:58:56 -0700106 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700107 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700108
David Tolnay3cf52982016-10-01 17:11:37 -0700109 named!(pub generics -> Generics, map!(
110 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700111 do_parse!(
112 punct!("<") >>
113 lifetimes: separated_list!(punct!(","), lifetime_def) >>
114 ty_params: opt_vec!(preceded!(
115 cond!(!lifetimes.is_empty(), punct!(",")),
116 separated_nonempty_list!(punct!(","), ty_param)
117 )) >>
118 punct!(">") >>
119 (lifetimes, ty_params)
120 )
121 |
122 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700123 ),
124 |(lifetimes, ty_params)| Generics {
125 lifetimes: lifetimes,
126 ty_params: ty_params,
127 where_clause: Default::default(),
128 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700129 ));
130
David Tolnayb5a7b142016-09-13 22:46:39 -0700131 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700132 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700133 map!(ident, |id| Lifetime {
134 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700135 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700136 ));
137
David Tolnayb5a7b142016-09-13 22:46:39 -0700138 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700139 life: lifetime >>
140 bounds: opt_vec!(preceded!(
141 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700142 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700143 )) >>
144 (LifetimeDef {
145 lifetime: life,
146 bounds: bounds,
147 })
148 ));
149
David Tolnayb5a7b142016-09-13 22:46:39 -0700150 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700151 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700152 punct!("<") >>
153 lifetimes: separated_list!(punct!(","), lifetime_def) >>
154 punct!(">") >>
155 (lifetimes)
156 )));
157
David Tolnayb5a7b142016-09-13 22:46:39 -0700158 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700159 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700160 bounds: opt_vec!(preceded!(
161 punct!(":"),
162 separated_nonempty_list!(punct!("+"), ty_param_bound)
163 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700164 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700165 punct!("="),
166 ty
167 )) >>
168 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700169 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700170 bounds: bounds,
171 default: default,
172 })
173 ));
174
David Tolnayb5a7b142016-09-13 22:46:39 -0700175 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700176 preceded!(punct!("?"), poly_trait_ref) => {
177 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
178 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700179 |
180 lifetime => { TyParamBound::Region }
181 |
David Tolnay55337722016-09-11 12:58:56 -0700182 poly_trait_ref => {
183 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
184 }
185 ));
186
David Tolnayb5a7b142016-09-13 22:46:39 -0700187 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700188 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700189 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700190 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
191 option!(punct!(",")) >>
192 (WhereClause { predicates: predicates })
193 )
194 |
195 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700196 ));
197
David Tolnayb5a7b142016-09-13 22:46:39 -0700198 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700199 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700200 ident: lifetime >>
201 punct!(":") >>
202 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
203 (WherePredicate::RegionPredicate(WhereRegionPredicate {
204 lifetime: ident,
205 bounds: bounds,
206 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700207 )
208 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700209 do_parse!(
210 bound_lifetimes: bound_lifetimes >>
211 bounded_ty: ty >>
212 punct!(":") >>
213 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
214 (WherePredicate::BoundPredicate(WhereBoundPredicate {
215 bound_lifetimes: bound_lifetimes,
216 bounded_ty: bounded_ty,
217 bounds: bounds,
218 }))
219 )
220 ));
221}
David Tolnay87d0b442016-09-04 11:52:12 -0700222
223#[cfg(feature = "printing")]
224mod printing {
225 use super::*;
226 use quote::{Tokens, ToTokens};
227
David Tolnay8ef93042016-09-04 14:08:40 -0700228 impl ToTokens for Generics {
229 fn to_tokens(&self, tokens: &mut Tokens) {
230 let has_lifetimes = !self.lifetimes.is_empty();
231 let has_ty_params = !self.ty_params.is_empty();
232 if has_lifetimes || has_ty_params {
233 tokens.append("<");
234 tokens.append_separated(&self.lifetimes, ",");
235 if has_lifetimes && has_ty_params {
236 tokens.append(",");
237 }
238 tokens.append_separated(&self.ty_params, ",");
239 tokens.append(">");
240 }
David Tolnay8ef93042016-09-04 14:08:40 -0700241 }
242 }
243
David Tolnay87d0b442016-09-04 11:52:12 -0700244 impl ToTokens for Lifetime {
245 fn to_tokens(&self, tokens: &mut Tokens) {
246 self.ident.to_tokens(tokens);
247 }
248 }
249
250 impl ToTokens for LifetimeDef {
251 fn to_tokens(&self, tokens: &mut Tokens) {
252 self.lifetime.to_tokens(tokens);
253 if !self.bounds.is_empty() {
254 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700255 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700256 }
257 }
258 }
259
David Tolnay8ef93042016-09-04 14:08:40 -0700260 impl ToTokens for TyParam {
261 fn to_tokens(&self, tokens: &mut Tokens) {
262 self.ident.to_tokens(tokens);
263 if !self.bounds.is_empty() {
264 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700265 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700266 }
267 if let Some(ref default) = self.default {
268 tokens.append("=");
269 default.to_tokens(tokens);
270 }
271 }
272 }
273
David Tolnay87d0b442016-09-04 11:52:12 -0700274 impl ToTokens for TyParamBound {
275 fn to_tokens(&self, tokens: &mut Tokens) {
276 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700277 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700278 TyParamBound::Trait(ref trait_ref, modifier) => {
279 match modifier {
280 TraitBoundModifier::None => {}
281 TraitBoundModifier::Maybe => tokens.append("?"),
282 }
283 trait_ref.to_tokens(tokens);
284 }
285 }
286 }
287 }
288
289 impl ToTokens for WhereClause {
290 fn to_tokens(&self, tokens: &mut Tokens) {
291 if !self.predicates.is_empty() {
292 tokens.append("where");
293 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700294 }
295 }
296 }
David Tolnay8ef93042016-09-04 14:08:40 -0700297
298 impl ToTokens for WherePredicate {
299 fn to_tokens(&self, tokens: &mut Tokens) {
300 match *self {
301 WherePredicate::BoundPredicate(ref predicate) => {
302 predicate.to_tokens(tokens);
303 }
304 WherePredicate::RegionPredicate(ref predicate) => {
305 predicate.to_tokens(tokens);
306 }
307 }
308 }
309 }
310
311 impl ToTokens for WhereBoundPredicate {
312 fn to_tokens(&self, tokens: &mut Tokens) {
313 if !self.bound_lifetimes.is_empty() {
314 tokens.append("for");
315 tokens.append("<");
316 tokens.append_separated(&self.bound_lifetimes, ",");
317 tokens.append(">");
318 }
319 self.bounded_ty.to_tokens(tokens);
320 if !self.bounds.is_empty() {
321 tokens.append(":");
322 tokens.append_separated(&self.bounds, "+");
323 }
324 }
325 }
326
327 impl ToTokens for WhereRegionPredicate {
328 fn to_tokens(&self, tokens: &mut Tokens) {
329 self.lifetime.to_tokens(tokens);
330 if !self.bounds.is_empty() {
331 tokens.append(":");
332 tokens.append_separated(&self.bounds, "+");
333 }
334 }
335 }
David Tolnay87d0b442016-09-04 11:52:12 -0700336}