blob: d92d2b4ba4adaec62e34db5307b01fdf8c511fd8 [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 {
David Tolnaydaaf7742016-10-03 11:11:43 -070019 Lifetime { ident: Ident::new(t) }
David Tolnay01405f02016-10-02 09:05:02 -070020 }
21}
22
David Tolnay771ecf42016-09-23 19:26:37 -070023/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070024#[derive(Debug, Clone, Eq, PartialEq)]
25pub struct LifetimeDef {
26 pub lifetime: Lifetime,
27 pub bounds: Vec<Lifetime>,
28}
29
David Tolnayf9505b52016-10-02 09:18:52 -070030impl LifetimeDef {
31 pub fn new<T: Into<Ident>>(t: T) -> Self {
32 LifetimeDef {
33 lifetime: Lifetime::new(t),
34 bounds: Vec::new(),
35 }
36 }
37}
38
David Tolnayb79ee962016-09-04 09:39:20 -070039#[derive(Debug, Clone, Eq, PartialEq)]
40pub struct TyParam {
41 pub ident: Ident,
42 pub bounds: Vec<TyParamBound>,
43 pub default: Option<Ty>,
44}
45
David Tolnay771ecf42016-09-23 19:26:37 -070046/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -070047/// `typeck::collect::compute_bounds` matches these against
48/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -070049/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -070050#[derive(Debug, Clone, Eq, PartialEq)]
51pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -070052 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070053 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070054}
55
David Tolnay771ecf42016-09-23 19:26:37 -070056/// A modifier on a bound, currently this is only used for `?Sized`, where the
57/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -070058#[derive(Debug, Copy, Clone, Eq, PartialEq)]
59pub enum TraitBoundModifier {
60 None,
61 Maybe,
62}
63
David Tolnay771ecf42016-09-23 19:26:37 -070064/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -070065#[derive(Debug, Clone, Eq, PartialEq, Default)]
66pub struct WhereClause {
67 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -070068}
69
70/// A single predicate in a `where` clause
71#[derive(Debug, Clone, Eq, PartialEq)]
72pub enum WherePredicate {
73 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
74 BoundPredicate(WhereBoundPredicate),
75 /// A lifetime predicate, e.g. `'a: 'b+'c`
76 RegionPredicate(WhereRegionPredicate),
77}
78
79/// A type bound.
80///
81/// E.g. `for<'c> Foo: Send+Clone+'c`
82#[derive(Debug, Clone, Eq, PartialEq)]
83pub struct WhereBoundPredicate {
84 /// Any lifetimes from a `for` binding
85 pub bound_lifetimes: Vec<LifetimeDef>,
86 /// The type being bounded
87 pub bounded_ty: Ty,
88 /// Trait and lifetime bounds (`Clone+Send+'static`)
89 pub bounds: Vec<TyParamBound>,
90}
91
92/// A lifetime predicate.
93///
94/// E.g. `'a: 'b+'c`
95#[derive(Debug, Clone, Eq, PartialEq)]
96pub struct WhereRegionPredicate {
97 pub lifetime: Lifetime,
98 pub bounds: Vec<Lifetime>,
99}
100
David Tolnay86eca752016-09-04 11:26:41 -0700101#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700102pub mod parsing {
103 use super::*;
David Tolnay55337722016-09-11 12:58:56 -0700104 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700105 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700106
David Tolnay3cf52982016-10-01 17:11:37 -0700107 named!(pub generics -> Generics, map!(
108 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700109 do_parse!(
110 punct!("<") >>
111 lifetimes: separated_list!(punct!(","), lifetime_def) >>
112 ty_params: opt_vec!(preceded!(
113 cond!(!lifetimes.is_empty(), punct!(",")),
114 separated_nonempty_list!(punct!(","), ty_param)
115 )) >>
116 punct!(">") >>
117 (lifetimes, ty_params)
118 )
119 |
120 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700121 ),
122 |(lifetimes, ty_params)| Generics {
123 lifetimes: lifetimes,
124 ty_params: ty_params,
125 where_clause: Default::default(),
126 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700127 ));
128
David Tolnayb5a7b142016-09-13 22:46:39 -0700129 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700130 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700131 map!(ident, |id| Lifetime {
132 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700133 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700134 ));
135
David Tolnayb5a7b142016-09-13 22:46:39 -0700136 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700137 life: lifetime >>
138 bounds: opt_vec!(preceded!(
139 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700140 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700141 )) >>
142 (LifetimeDef {
143 lifetime: life,
144 bounds: bounds,
145 })
146 ));
147
David Tolnayb5a7b142016-09-13 22:46:39 -0700148 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700149 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700150 punct!("<") >>
151 lifetimes: separated_list!(punct!(","), lifetime_def) >>
152 punct!(">") >>
153 (lifetimes)
154 )));
155
David Tolnayb5a7b142016-09-13 22:46:39 -0700156 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700157 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700158 bounds: opt_vec!(preceded!(
159 punct!(":"),
160 separated_nonempty_list!(punct!("+"), ty_param_bound)
161 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700162 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700163 punct!("="),
164 ty
165 )) >>
166 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700167 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700168 bounds: bounds,
169 default: default,
170 })
171 ));
172
David Tolnayb5a7b142016-09-13 22:46:39 -0700173 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700174 preceded!(punct!("?"), poly_trait_ref) => {
175 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
176 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700177 |
178 lifetime => { TyParamBound::Region }
179 |
David Tolnay55337722016-09-11 12:58:56 -0700180 poly_trait_ref => {
181 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
182 }
183 ));
184
David Tolnayb5a7b142016-09-13 22:46:39 -0700185 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700186 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700187 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700188 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
189 option!(punct!(",")) >>
190 (WhereClause { predicates: predicates })
191 )
192 |
193 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700194 ));
195
David Tolnayb5a7b142016-09-13 22:46:39 -0700196 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700197 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700198 ident: lifetime >>
199 punct!(":") >>
200 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
201 (WherePredicate::RegionPredicate(WhereRegionPredicate {
202 lifetime: ident,
203 bounds: bounds,
204 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700205 )
206 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700207 do_parse!(
208 bound_lifetimes: bound_lifetimes >>
209 bounded_ty: ty >>
210 punct!(":") >>
211 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
212 (WherePredicate::BoundPredicate(WhereBoundPredicate {
213 bound_lifetimes: bound_lifetimes,
214 bounded_ty: bounded_ty,
215 bounds: bounds,
216 }))
217 )
218 ));
219}
David Tolnay87d0b442016-09-04 11:52:12 -0700220
221#[cfg(feature = "printing")]
222mod printing {
223 use super::*;
224 use quote::{Tokens, ToTokens};
225
David Tolnay8ef93042016-09-04 14:08:40 -0700226 impl ToTokens for Generics {
227 fn to_tokens(&self, tokens: &mut Tokens) {
228 let has_lifetimes = !self.lifetimes.is_empty();
229 let has_ty_params = !self.ty_params.is_empty();
230 if has_lifetimes || has_ty_params {
231 tokens.append("<");
232 tokens.append_separated(&self.lifetimes, ",");
233 if has_lifetimes && has_ty_params {
234 tokens.append(",");
235 }
236 tokens.append_separated(&self.ty_params, ",");
237 tokens.append(">");
238 }
David Tolnay8ef93042016-09-04 14:08:40 -0700239 }
240 }
241
David Tolnay87d0b442016-09-04 11:52:12 -0700242 impl ToTokens for Lifetime {
243 fn to_tokens(&self, tokens: &mut Tokens) {
244 self.ident.to_tokens(tokens);
245 }
246 }
247
248 impl ToTokens for LifetimeDef {
249 fn to_tokens(&self, tokens: &mut Tokens) {
250 self.lifetime.to_tokens(tokens);
251 if !self.bounds.is_empty() {
252 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700253 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700254 }
255 }
256 }
257
David Tolnay8ef93042016-09-04 14:08:40 -0700258 impl ToTokens for TyParam {
259 fn to_tokens(&self, tokens: &mut Tokens) {
260 self.ident.to_tokens(tokens);
261 if !self.bounds.is_empty() {
262 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700263 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700264 }
265 if let Some(ref default) = self.default {
266 tokens.append("=");
267 default.to_tokens(tokens);
268 }
269 }
270 }
271
David Tolnay87d0b442016-09-04 11:52:12 -0700272 impl ToTokens for TyParamBound {
273 fn to_tokens(&self, tokens: &mut Tokens) {
274 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700275 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700276 TyParamBound::Trait(ref trait_ref, modifier) => {
277 match modifier {
278 TraitBoundModifier::None => {}
279 TraitBoundModifier::Maybe => tokens.append("?"),
280 }
281 trait_ref.to_tokens(tokens);
282 }
283 }
284 }
285 }
286
287 impl ToTokens for WhereClause {
288 fn to_tokens(&self, tokens: &mut Tokens) {
289 if !self.predicates.is_empty() {
290 tokens.append("where");
291 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700292 }
293 }
294 }
David Tolnay8ef93042016-09-04 14:08:40 -0700295
296 impl ToTokens for WherePredicate {
297 fn to_tokens(&self, tokens: &mut Tokens) {
298 match *self {
299 WherePredicate::BoundPredicate(ref predicate) => {
300 predicate.to_tokens(tokens);
301 }
302 WherePredicate::RegionPredicate(ref predicate) => {
303 predicate.to_tokens(tokens);
304 }
305 }
306 }
307 }
308
309 impl ToTokens for WhereBoundPredicate {
310 fn to_tokens(&self, tokens: &mut Tokens) {
311 if !self.bound_lifetimes.is_empty() {
312 tokens.append("for");
313 tokens.append("<");
314 tokens.append_separated(&self.bound_lifetimes, ",");
315 tokens.append(">");
316 }
317 self.bounded_ty.to_tokens(tokens);
318 if !self.bounds.is_empty() {
319 tokens.append(":");
320 tokens.append_separated(&self.bounds, "+");
321 }
322 }
323 }
324
325 impl ToTokens for WhereRegionPredicate {
326 fn to_tokens(&self, tokens: &mut Tokens) {
327 self.lifetime.to_tokens(tokens);
328 if !self.bounds.is_empty() {
329 tokens.append(":");
330 tokens.append_separated(&self.bounds, "+");
331 }
332 }
333 }
David Tolnay87d0b442016-09-04 11:52:12 -0700334}