blob: c0d5c9447f44377e263f39222fd12ef8ecee6f09 [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 Tolnay771ecf42016-09-23 19:26:37 -070017/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070018#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct LifetimeDef {
20 pub lifetime: Lifetime,
21 pub bounds: Vec<Lifetime>,
22}
23
24#[derive(Debug, Clone, Eq, PartialEq)]
25pub struct TyParam {
26 pub ident: Ident,
27 pub bounds: Vec<TyParamBound>,
28 pub default: Option<Ty>,
29}
30
David Tolnay771ecf42016-09-23 19:26:37 -070031/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -070032/// `typeck::collect::compute_bounds` matches these against
33/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -070034/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -070035#[derive(Debug, Clone, Eq, PartialEq)]
36pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -070037 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070038 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070039}
40
David Tolnay771ecf42016-09-23 19:26:37 -070041/// A modifier on a bound, currently this is only used for `?Sized`, where the
42/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -070043#[derive(Debug, Copy, Clone, Eq, PartialEq)]
44pub enum TraitBoundModifier {
45 None,
46 Maybe,
47}
48
David Tolnay771ecf42016-09-23 19:26:37 -070049/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -070050#[derive(Debug, Clone, Eq, PartialEq, Default)]
51pub struct WhereClause {
52 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -070053}
54
55/// A single predicate in a `where` clause
56#[derive(Debug, Clone, Eq, PartialEq)]
57pub enum WherePredicate {
58 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
59 BoundPredicate(WhereBoundPredicate),
60 /// A lifetime predicate, e.g. `'a: 'b+'c`
61 RegionPredicate(WhereRegionPredicate),
62}
63
64/// A type bound.
65///
66/// E.g. `for<'c> Foo: Send+Clone+'c`
67#[derive(Debug, Clone, Eq, PartialEq)]
68pub struct WhereBoundPredicate {
69 /// Any lifetimes from a `for` binding
70 pub bound_lifetimes: Vec<LifetimeDef>,
71 /// The type being bounded
72 pub bounded_ty: Ty,
73 /// Trait and lifetime bounds (`Clone+Send+'static`)
74 pub bounds: Vec<TyParamBound>,
75}
76
77/// A lifetime predicate.
78///
79/// E.g. `'a: 'b+'c`
80#[derive(Debug, Clone, Eq, PartialEq)]
81pub struct WhereRegionPredicate {
82 pub lifetime: Lifetime,
83 pub bounds: Vec<Lifetime>,
84}
85
David Tolnay86eca752016-09-04 11:26:41 -070086#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070087pub mod parsing {
88 use super::*;
David Tolnay55337722016-09-11 12:58:56 -070089 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -070090 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -070091
David Tolnayb5a7b142016-09-13 22:46:39 -070092 named!(pub generics -> Generics, do_parse!(
93 bracketed: alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070094 do_parse!(
95 punct!("<") >>
96 lifetimes: separated_list!(punct!(","), lifetime_def) >>
97 ty_params: opt_vec!(preceded!(
98 cond!(!lifetimes.is_empty(), punct!(",")),
99 separated_nonempty_list!(punct!(","), ty_param)
100 )) >>
101 punct!(">") >>
102 (lifetimes, ty_params)
103 )
104 |
105 epsilon!() => { |_| (Vec::new(), Vec::new()) }
106 ) >>
David Tolnay55337722016-09-11 12:58:56 -0700107 where_clause: where_clause >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700108 (Generics {
109 lifetimes: bracketed.0,
110 ty_params: bracketed.1,
111 where_clause: where_clause,
112 })
113 ));
114
David Tolnayb5a7b142016-09-13 22:46:39 -0700115 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700116 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700117 map!(ident, |id| Lifetime {
118 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700119 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700120 ));
121
David Tolnayb5a7b142016-09-13 22:46:39 -0700122 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700123 life: lifetime >>
124 bounds: opt_vec!(preceded!(
125 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700126 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700127 )) >>
128 (LifetimeDef {
129 lifetime: life,
130 bounds: bounds,
131 })
132 ));
133
David Tolnayb5a7b142016-09-13 22:46:39 -0700134 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700135 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700136 punct!("<") >>
137 lifetimes: separated_list!(punct!(","), lifetime_def) >>
138 punct!(">") >>
139 (lifetimes)
140 )));
141
David Tolnayb5a7b142016-09-13 22:46:39 -0700142 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700143 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700144 bounds: opt_vec!(preceded!(
145 punct!(":"),
146 separated_nonempty_list!(punct!("+"), ty_param_bound)
147 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700148 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700149 punct!("="),
150 ty
151 )) >>
152 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700153 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700154 bounds: bounds,
155 default: default,
156 })
157 ));
158
David Tolnayb5a7b142016-09-13 22:46:39 -0700159 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700160 preceded!(punct!("?"), poly_trait_ref) => {
161 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
162 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700163 |
164 lifetime => { TyParamBound::Region }
165 |
David Tolnay55337722016-09-11 12:58:56 -0700166 poly_trait_ref => {
167 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
168 }
169 ));
170
David Tolnayb5a7b142016-09-13 22:46:39 -0700171 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700172 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700173 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700174 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
175 option!(punct!(",")) >>
176 (WhereClause { predicates: predicates })
177 )
178 |
179 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700180 ));
181
David Tolnayb5a7b142016-09-13 22:46:39 -0700182 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700183 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700184 ident: lifetime >>
185 punct!(":") >>
186 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
187 (WherePredicate::RegionPredicate(WhereRegionPredicate {
188 lifetime: ident,
189 bounds: bounds,
190 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700191 )
192 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700193 do_parse!(
194 bound_lifetimes: bound_lifetimes >>
195 bounded_ty: ty >>
196 punct!(":") >>
197 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
198 (WherePredicate::BoundPredicate(WhereBoundPredicate {
199 bound_lifetimes: bound_lifetimes,
200 bounded_ty: bounded_ty,
201 bounds: bounds,
202 }))
203 )
204 ));
205}
David Tolnay87d0b442016-09-04 11:52:12 -0700206
207#[cfg(feature = "printing")]
208mod printing {
209 use super::*;
210 use quote::{Tokens, ToTokens};
211
David Tolnay8ef93042016-09-04 14:08:40 -0700212 impl ToTokens for Generics {
213 fn to_tokens(&self, tokens: &mut Tokens) {
214 let has_lifetimes = !self.lifetimes.is_empty();
215 let has_ty_params = !self.ty_params.is_empty();
216 if has_lifetimes || has_ty_params {
217 tokens.append("<");
218 tokens.append_separated(&self.lifetimes, ",");
219 if has_lifetimes && has_ty_params {
220 tokens.append(",");
221 }
222 tokens.append_separated(&self.ty_params, ",");
223 tokens.append(">");
224 }
David Tolnay8ef93042016-09-04 14:08:40 -0700225 }
226 }
227
David Tolnay87d0b442016-09-04 11:52:12 -0700228 impl ToTokens for Lifetime {
229 fn to_tokens(&self, tokens: &mut Tokens) {
230 self.ident.to_tokens(tokens);
231 }
232 }
233
234 impl ToTokens for LifetimeDef {
235 fn to_tokens(&self, tokens: &mut Tokens) {
236 self.lifetime.to_tokens(tokens);
237 if !self.bounds.is_empty() {
238 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700239 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700240 }
241 }
242 }
243
David Tolnay8ef93042016-09-04 14:08:40 -0700244 impl ToTokens for TyParam {
245 fn to_tokens(&self, tokens: &mut Tokens) {
246 self.ident.to_tokens(tokens);
247 if !self.bounds.is_empty() {
248 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700249 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700250 }
251 if let Some(ref default) = self.default {
252 tokens.append("=");
253 default.to_tokens(tokens);
254 }
255 }
256 }
257
David Tolnay87d0b442016-09-04 11:52:12 -0700258 impl ToTokens for TyParamBound {
259 fn to_tokens(&self, tokens: &mut Tokens) {
260 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700261 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700262 TyParamBound::Trait(ref trait_ref, modifier) => {
263 match modifier {
264 TraitBoundModifier::None => {}
265 TraitBoundModifier::Maybe => tokens.append("?"),
266 }
267 trait_ref.to_tokens(tokens);
268 }
269 }
270 }
271 }
272
273 impl ToTokens for WhereClause {
274 fn to_tokens(&self, tokens: &mut Tokens) {
275 if !self.predicates.is_empty() {
276 tokens.append("where");
277 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700278 }
279 }
280 }
David Tolnay8ef93042016-09-04 14:08:40 -0700281
282 impl ToTokens for WherePredicate {
283 fn to_tokens(&self, tokens: &mut Tokens) {
284 match *self {
285 WherePredicate::BoundPredicate(ref predicate) => {
286 predicate.to_tokens(tokens);
287 }
288 WherePredicate::RegionPredicate(ref predicate) => {
289 predicate.to_tokens(tokens);
290 }
291 }
292 }
293 }
294
295 impl ToTokens for WhereBoundPredicate {
296 fn to_tokens(&self, tokens: &mut Tokens) {
297 if !self.bound_lifetimes.is_empty() {
298 tokens.append("for");
299 tokens.append("<");
300 tokens.append_separated(&self.bound_lifetimes, ",");
301 tokens.append(">");
302 }
303 self.bounded_ty.to_tokens(tokens);
304 if !self.bounds.is_empty() {
305 tokens.append(":");
306 tokens.append_separated(&self.bounds, "+");
307 }
308 }
309 }
310
311 impl ToTokens for WhereRegionPredicate {
312 fn to_tokens(&self, tokens: &mut Tokens) {
313 self.lifetime.to_tokens(tokens);
314 if !self.bounds.is_empty() {
315 tokens.append(":");
316 tokens.append_separated(&self.bounds, "+");
317 }
318 }
319 }
David Tolnay87d0b442016-09-04 11:52:12 -0700320}