blob: 40025c439f39420c3e8dcd5a74adb3d1f17f28c1 [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 Tolnay3cf52982016-10-01 17:11:37 -070092 named!(pub generics -> Generics, map!(
93 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()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700106 ),
107 |(lifetimes, ty_params)| Generics {
108 lifetimes: lifetimes,
109 ty_params: ty_params,
110 where_clause: Default::default(),
111 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700112 ));
113
David Tolnayb5a7b142016-09-13 22:46:39 -0700114 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700115 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700116 map!(ident, |id| Lifetime {
117 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700118 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700119 ));
120
David Tolnayb5a7b142016-09-13 22:46:39 -0700121 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700122 life: lifetime >>
123 bounds: opt_vec!(preceded!(
124 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700125 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700126 )) >>
127 (LifetimeDef {
128 lifetime: life,
129 bounds: bounds,
130 })
131 ));
132
David Tolnayb5a7b142016-09-13 22:46:39 -0700133 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700134 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700135 punct!("<") >>
136 lifetimes: separated_list!(punct!(","), lifetime_def) >>
137 punct!(">") >>
138 (lifetimes)
139 )));
140
David Tolnayb5a7b142016-09-13 22:46:39 -0700141 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700142 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700143 bounds: opt_vec!(preceded!(
144 punct!(":"),
145 separated_nonempty_list!(punct!("+"), ty_param_bound)
146 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700147 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700148 punct!("="),
149 ty
150 )) >>
151 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700152 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700153 bounds: bounds,
154 default: default,
155 })
156 ));
157
David Tolnayb5a7b142016-09-13 22:46:39 -0700158 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700159 preceded!(punct!("?"), poly_trait_ref) => {
160 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
161 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700162 |
163 lifetime => { TyParamBound::Region }
164 |
David Tolnay55337722016-09-11 12:58:56 -0700165 poly_trait_ref => {
166 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
167 }
168 ));
169
David Tolnayb5a7b142016-09-13 22:46:39 -0700170 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700171 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700172 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700173 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
174 option!(punct!(",")) >>
175 (WhereClause { predicates: predicates })
176 )
177 |
178 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700179 ));
180
David Tolnayb5a7b142016-09-13 22:46:39 -0700181 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700182 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700183 ident: lifetime >>
184 punct!(":") >>
185 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
186 (WherePredicate::RegionPredicate(WhereRegionPredicate {
187 lifetime: ident,
188 bounds: bounds,
189 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700190 )
191 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700192 do_parse!(
193 bound_lifetimes: bound_lifetimes >>
194 bounded_ty: ty >>
195 punct!(":") >>
196 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
197 (WherePredicate::BoundPredicate(WhereBoundPredicate {
198 bound_lifetimes: bound_lifetimes,
199 bounded_ty: bounded_ty,
200 bounds: bounds,
201 }))
202 )
203 ));
204}
David Tolnay87d0b442016-09-04 11:52:12 -0700205
206#[cfg(feature = "printing")]
207mod printing {
208 use super::*;
209 use quote::{Tokens, ToTokens};
210
David Tolnay8ef93042016-09-04 14:08:40 -0700211 impl ToTokens for Generics {
212 fn to_tokens(&self, tokens: &mut Tokens) {
213 let has_lifetimes = !self.lifetimes.is_empty();
214 let has_ty_params = !self.ty_params.is_empty();
215 if has_lifetimes || has_ty_params {
216 tokens.append("<");
217 tokens.append_separated(&self.lifetimes, ",");
218 if has_lifetimes && has_ty_params {
219 tokens.append(",");
220 }
221 tokens.append_separated(&self.ty_params, ",");
222 tokens.append(">");
223 }
David Tolnay8ef93042016-09-04 14:08:40 -0700224 }
225 }
226
David Tolnay87d0b442016-09-04 11:52:12 -0700227 impl ToTokens for Lifetime {
228 fn to_tokens(&self, tokens: &mut Tokens) {
229 self.ident.to_tokens(tokens);
230 }
231 }
232
233 impl ToTokens for LifetimeDef {
234 fn to_tokens(&self, tokens: &mut Tokens) {
235 self.lifetime.to_tokens(tokens);
236 if !self.bounds.is_empty() {
237 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700238 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700239 }
240 }
241 }
242
David Tolnay8ef93042016-09-04 14:08:40 -0700243 impl ToTokens for TyParam {
244 fn to_tokens(&self, tokens: &mut Tokens) {
245 self.ident.to_tokens(tokens);
246 if !self.bounds.is_empty() {
247 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700248 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700249 }
250 if let Some(ref default) = self.default {
251 tokens.append("=");
252 default.to_tokens(tokens);
253 }
254 }
255 }
256
David Tolnay87d0b442016-09-04 11:52:12 -0700257 impl ToTokens for TyParamBound {
258 fn to_tokens(&self, tokens: &mut Tokens) {
259 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700260 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700261 TyParamBound::Trait(ref trait_ref, modifier) => {
262 match modifier {
263 TraitBoundModifier::None => {}
264 TraitBoundModifier::Maybe => tokens.append("?"),
265 }
266 trait_ref.to_tokens(tokens);
267 }
268 }
269 }
270 }
271
272 impl ToTokens for WhereClause {
273 fn to_tokens(&self, tokens: &mut Tokens) {
274 if !self.predicates.is_empty() {
275 tokens.append("where");
276 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700277 }
278 }
279 }
David Tolnay8ef93042016-09-04 14:08:40 -0700280
281 impl ToTokens for WherePredicate {
282 fn to_tokens(&self, tokens: &mut Tokens) {
283 match *self {
284 WherePredicate::BoundPredicate(ref predicate) => {
285 predicate.to_tokens(tokens);
286 }
287 WherePredicate::RegionPredicate(ref predicate) => {
288 predicate.to_tokens(tokens);
289 }
290 }
291 }
292 }
293
294 impl ToTokens for WhereBoundPredicate {
295 fn to_tokens(&self, tokens: &mut Tokens) {
296 if !self.bound_lifetimes.is_empty() {
297 tokens.append("for");
298 tokens.append("<");
299 tokens.append_separated(&self.bound_lifetimes, ",");
300 tokens.append(">");
301 }
302 self.bounded_ty.to_tokens(tokens);
303 if !self.bounds.is_empty() {
304 tokens.append(":");
305 tokens.append_separated(&self.bounds, "+");
306 }
307 }
308 }
309
310 impl ToTokens for WhereRegionPredicate {
311 fn to_tokens(&self, tokens: &mut Tokens) {
312 self.lifetime.to_tokens(tokens);
313 if !self.bounds.is_empty() {
314 tokens.append(":");
315 tokens.append_separated(&self.bounds, "+");
316 }
317 }
318 }
David Tolnay87d0b442016-09-04 11:52:12 -0700319}