blob: e7cc8736d31fb3b57224c74904dc163bcd35baf5 [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};
91 use nom::multispace;
92
David Tolnayb5a7b142016-09-13 22:46:39 -070093 named!(pub generics -> Generics, do_parse!(
94 bracketed: alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070095 do_parse!(
96 punct!("<") >>
97 lifetimes: separated_list!(punct!(","), lifetime_def) >>
98 ty_params: opt_vec!(preceded!(
99 cond!(!lifetimes.is_empty(), punct!(",")),
100 separated_nonempty_list!(punct!(","), ty_param)
101 )) >>
102 punct!(">") >>
103 (lifetimes, ty_params)
104 )
105 |
106 epsilon!() => { |_| (Vec::new(), Vec::new()) }
107 ) >>
David Tolnay55337722016-09-11 12:58:56 -0700108 where_clause: where_clause >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700109 (Generics {
110 lifetimes: bracketed.0,
111 ty_params: bracketed.1,
112 where_clause: where_clause,
113 })
114 ));
115
David Tolnayb5a7b142016-09-13 22:46:39 -0700116 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700117 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700118 map!(ident, |id| Lifetime {
119 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700120 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700121 ));
122
David Tolnayb5a7b142016-09-13 22:46:39 -0700123 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700124 life: lifetime >>
125 bounds: opt_vec!(preceded!(
126 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700127 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700128 )) >>
129 (LifetimeDef {
130 lifetime: life,
131 bounds: bounds,
132 })
133 ));
134
David Tolnayb5a7b142016-09-13 22:46:39 -0700135 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700136 punct!("for") >>
137 punct!("<") >>
138 lifetimes: separated_list!(punct!(","), lifetime_def) >>
139 punct!(">") >>
140 (lifetimes)
141 )));
142
David Tolnayb5a7b142016-09-13 22:46:39 -0700143 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700144 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700145 bounds: opt_vec!(preceded!(
146 punct!(":"),
147 separated_nonempty_list!(punct!("+"), ty_param_bound)
148 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700149 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700150 punct!("="),
151 ty
152 )) >>
153 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700154 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700155 bounds: bounds,
156 default: default,
157 })
158 ));
159
David Tolnayb5a7b142016-09-13 22:46:39 -0700160 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700161 preceded!(punct!("?"), poly_trait_ref) => {
162 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
163 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700164 |
165 lifetime => { TyParamBound::Region }
166 |
David Tolnay55337722016-09-11 12:58:56 -0700167 poly_trait_ref => {
168 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
169 }
170 ));
171
David Tolnayb5a7b142016-09-13 22:46:39 -0700172 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700173 do_parse!(
174 punct!("where") >>
175 multispace >>
176 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
177 option!(punct!(",")) >>
178 (WhereClause { predicates: predicates })
179 )
180 |
181 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700182 ));
183
David Tolnayb5a7b142016-09-13 22:46:39 -0700184 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700185 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700186 ident: lifetime >>
187 punct!(":") >>
188 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
189 (WherePredicate::RegionPredicate(WhereRegionPredicate {
190 lifetime: ident,
191 bounds: bounds,
192 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700193 )
194 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700195 do_parse!(
196 bound_lifetimes: bound_lifetimes >>
197 bounded_ty: ty >>
198 punct!(":") >>
199 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
200 (WherePredicate::BoundPredicate(WhereBoundPredicate {
201 bound_lifetimes: bound_lifetimes,
202 bounded_ty: bounded_ty,
203 bounds: bounds,
204 }))
205 )
206 ));
207}
David Tolnay87d0b442016-09-04 11:52:12 -0700208
209#[cfg(feature = "printing")]
210mod printing {
211 use super::*;
212 use quote::{Tokens, ToTokens};
213
David Tolnay8ef93042016-09-04 14:08:40 -0700214 impl ToTokens for Generics {
215 fn to_tokens(&self, tokens: &mut Tokens) {
216 let has_lifetimes = !self.lifetimes.is_empty();
217 let has_ty_params = !self.ty_params.is_empty();
218 if has_lifetimes || has_ty_params {
219 tokens.append("<");
220 tokens.append_separated(&self.lifetimes, ",");
221 if has_lifetimes && has_ty_params {
222 tokens.append(",");
223 }
224 tokens.append_separated(&self.ty_params, ",");
225 tokens.append(">");
226 }
David Tolnay8ef93042016-09-04 14:08:40 -0700227 }
228 }
229
David Tolnay87d0b442016-09-04 11:52:12 -0700230 impl ToTokens for Lifetime {
231 fn to_tokens(&self, tokens: &mut Tokens) {
232 self.ident.to_tokens(tokens);
233 }
234 }
235
236 impl ToTokens for LifetimeDef {
237 fn to_tokens(&self, tokens: &mut Tokens) {
238 self.lifetime.to_tokens(tokens);
239 if !self.bounds.is_empty() {
240 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700241 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700242 }
243 }
244 }
245
David Tolnay8ef93042016-09-04 14:08:40 -0700246 impl ToTokens for TyParam {
247 fn to_tokens(&self, tokens: &mut Tokens) {
248 self.ident.to_tokens(tokens);
249 if !self.bounds.is_empty() {
250 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700251 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700252 }
253 if let Some(ref default) = self.default {
254 tokens.append("=");
255 default.to_tokens(tokens);
256 }
257 }
258 }
259
David Tolnay87d0b442016-09-04 11:52:12 -0700260 impl ToTokens for TyParamBound {
261 fn to_tokens(&self, tokens: &mut Tokens) {
262 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700263 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700264 TyParamBound::Trait(ref trait_ref, modifier) => {
265 match modifier {
266 TraitBoundModifier::None => {}
267 TraitBoundModifier::Maybe => tokens.append("?"),
268 }
269 trait_ref.to_tokens(tokens);
270 }
271 }
272 }
273 }
274
275 impl ToTokens for WhereClause {
276 fn to_tokens(&self, tokens: &mut Tokens) {
277 if !self.predicates.is_empty() {
278 tokens.append("where");
279 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700280 }
281 }
282 }
David Tolnay8ef93042016-09-04 14:08:40 -0700283
284 impl ToTokens for WherePredicate {
285 fn to_tokens(&self, tokens: &mut Tokens) {
286 match *self {
287 WherePredicate::BoundPredicate(ref predicate) => {
288 predicate.to_tokens(tokens);
289 }
290 WherePredicate::RegionPredicate(ref predicate) => {
291 predicate.to_tokens(tokens);
292 }
293 }
294 }
295 }
296
297 impl ToTokens for WhereBoundPredicate {
298 fn to_tokens(&self, tokens: &mut Tokens) {
299 if !self.bound_lifetimes.is_empty() {
300 tokens.append("for");
301 tokens.append("<");
302 tokens.append_separated(&self.bound_lifetimes, ",");
303 tokens.append(">");
304 }
305 self.bounded_ty.to_tokens(tokens);
306 if !self.bounds.is_empty() {
307 tokens.append(":");
308 tokens.append_separated(&self.bounds, "+");
309 }
310 }
311 }
312
313 impl ToTokens for WhereRegionPredicate {
314 fn to_tokens(&self, tokens: &mut Tokens) {
315 self.lifetime.to_tokens(tokens);
316 if !self.bounds.is_empty() {
317 tokens.append(":");
318 tokens.append_separated(&self.bounds, "+");
319 }
320 }
321 }
David Tolnay87d0b442016-09-04 11:52:12 -0700322}