blob: b3ee1c2edd029290a96ac9af1fd8d2f170df0815 [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
32#[derive(Debug, Clone, Eq, PartialEq)]
33pub struct TyParam {
34 pub ident: Ident,
35 pub bounds: Vec<TyParamBound>,
36 pub default: Option<Ty>,
37}
38
David Tolnay771ecf42016-09-23 19:26:37 -070039/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -070040/// `typeck::collect::compute_bounds` matches these against
41/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -070042/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -070043#[derive(Debug, Clone, Eq, PartialEq)]
44pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -070045 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070046 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070047}
48
David Tolnay771ecf42016-09-23 19:26:37 -070049/// A modifier on a bound, currently this is only used for `?Sized`, where the
50/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -070051#[derive(Debug, Copy, Clone, Eq, PartialEq)]
52pub enum TraitBoundModifier {
53 None,
54 Maybe,
55}
56
David Tolnay771ecf42016-09-23 19:26:37 -070057/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -070058#[derive(Debug, Clone, Eq, PartialEq, Default)]
59pub struct WhereClause {
60 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -070061}
62
63/// A single predicate in a `where` clause
64#[derive(Debug, Clone, Eq, PartialEq)]
65pub enum WherePredicate {
66 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
67 BoundPredicate(WhereBoundPredicate),
68 /// A lifetime predicate, e.g. `'a: 'b+'c`
69 RegionPredicate(WhereRegionPredicate),
70}
71
72/// A type bound.
73///
74/// E.g. `for<'c> Foo: Send+Clone+'c`
75#[derive(Debug, Clone, Eq, PartialEq)]
76pub struct WhereBoundPredicate {
77 /// Any lifetimes from a `for` binding
78 pub bound_lifetimes: Vec<LifetimeDef>,
79 /// The type being bounded
80 pub bounded_ty: Ty,
81 /// Trait and lifetime bounds (`Clone+Send+'static`)
82 pub bounds: Vec<TyParamBound>,
83}
84
85/// A lifetime predicate.
86///
87/// E.g. `'a: 'b+'c`
88#[derive(Debug, Clone, Eq, PartialEq)]
89pub struct WhereRegionPredicate {
90 pub lifetime: Lifetime,
91 pub bounds: Vec<Lifetime>,
92}
93
David Tolnay86eca752016-09-04 11:26:41 -070094#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070095pub mod parsing {
96 use super::*;
David Tolnay55337722016-09-11 12:58:56 -070097 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -070098 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -070099
David Tolnay3cf52982016-10-01 17:11:37 -0700100 named!(pub generics -> Generics, map!(
101 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700102 do_parse!(
103 punct!("<") >>
104 lifetimes: separated_list!(punct!(","), lifetime_def) >>
105 ty_params: opt_vec!(preceded!(
106 cond!(!lifetimes.is_empty(), punct!(",")),
107 separated_nonempty_list!(punct!(","), ty_param)
108 )) >>
109 punct!(">") >>
110 (lifetimes, ty_params)
111 )
112 |
113 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700114 ),
115 |(lifetimes, ty_params)| Generics {
116 lifetimes: lifetimes,
117 ty_params: ty_params,
118 where_clause: Default::default(),
119 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700120 ));
121
David Tolnayb5a7b142016-09-13 22:46:39 -0700122 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700123 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700124 map!(ident, |id| Lifetime {
125 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700126 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700127 ));
128
David Tolnayb5a7b142016-09-13 22:46:39 -0700129 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700130 life: lifetime >>
131 bounds: opt_vec!(preceded!(
132 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700133 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700134 )) >>
135 (LifetimeDef {
136 lifetime: life,
137 bounds: bounds,
138 })
139 ));
140
David Tolnayb5a7b142016-09-13 22:46:39 -0700141 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700142 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700143 punct!("<") >>
144 lifetimes: separated_list!(punct!(","), lifetime_def) >>
145 punct!(">") >>
146 (lifetimes)
147 )));
148
David Tolnayb5a7b142016-09-13 22:46:39 -0700149 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700150 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700151 bounds: opt_vec!(preceded!(
152 punct!(":"),
153 separated_nonempty_list!(punct!("+"), ty_param_bound)
154 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700155 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700156 punct!("="),
157 ty
158 )) >>
159 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700160 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700161 bounds: bounds,
162 default: default,
163 })
164 ));
165
David Tolnayb5a7b142016-09-13 22:46:39 -0700166 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700167 preceded!(punct!("?"), poly_trait_ref) => {
168 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
169 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700170 |
171 lifetime => { TyParamBound::Region }
172 |
David Tolnay55337722016-09-11 12:58:56 -0700173 poly_trait_ref => {
174 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
175 }
176 ));
177
David Tolnayb5a7b142016-09-13 22:46:39 -0700178 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700179 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700180 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700181 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
182 option!(punct!(",")) >>
183 (WhereClause { predicates: predicates })
184 )
185 |
186 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700187 ));
188
David Tolnayb5a7b142016-09-13 22:46:39 -0700189 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700190 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700191 ident: lifetime >>
192 punct!(":") >>
193 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
194 (WherePredicate::RegionPredicate(WhereRegionPredicate {
195 lifetime: ident,
196 bounds: bounds,
197 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700198 )
199 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700200 do_parse!(
201 bound_lifetimes: bound_lifetimes >>
202 bounded_ty: ty >>
203 punct!(":") >>
204 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
205 (WherePredicate::BoundPredicate(WhereBoundPredicate {
206 bound_lifetimes: bound_lifetimes,
207 bounded_ty: bounded_ty,
208 bounds: bounds,
209 }))
210 )
211 ));
212}
David Tolnay87d0b442016-09-04 11:52:12 -0700213
214#[cfg(feature = "printing")]
215mod printing {
216 use super::*;
217 use quote::{Tokens, ToTokens};
218
David Tolnay8ef93042016-09-04 14:08:40 -0700219 impl ToTokens for Generics {
220 fn to_tokens(&self, tokens: &mut Tokens) {
221 let has_lifetimes = !self.lifetimes.is_empty();
222 let has_ty_params = !self.ty_params.is_empty();
223 if has_lifetimes || has_ty_params {
224 tokens.append("<");
225 tokens.append_separated(&self.lifetimes, ",");
226 if has_lifetimes && has_ty_params {
227 tokens.append(",");
228 }
229 tokens.append_separated(&self.ty_params, ",");
230 tokens.append(">");
231 }
David Tolnay8ef93042016-09-04 14:08:40 -0700232 }
233 }
234
David Tolnay87d0b442016-09-04 11:52:12 -0700235 impl ToTokens for Lifetime {
236 fn to_tokens(&self, tokens: &mut Tokens) {
237 self.ident.to_tokens(tokens);
238 }
239 }
240
241 impl ToTokens for LifetimeDef {
242 fn to_tokens(&self, tokens: &mut Tokens) {
243 self.lifetime.to_tokens(tokens);
244 if !self.bounds.is_empty() {
245 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700246 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700247 }
248 }
249 }
250
David Tolnay8ef93042016-09-04 14:08:40 -0700251 impl ToTokens for TyParam {
252 fn to_tokens(&self, tokens: &mut Tokens) {
253 self.ident.to_tokens(tokens);
254 if !self.bounds.is_empty() {
255 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700256 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700257 }
258 if let Some(ref default) = self.default {
259 tokens.append("=");
260 default.to_tokens(tokens);
261 }
262 }
263 }
264
David Tolnay87d0b442016-09-04 11:52:12 -0700265 impl ToTokens for TyParamBound {
266 fn to_tokens(&self, tokens: &mut Tokens) {
267 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700268 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700269 TyParamBound::Trait(ref trait_ref, modifier) => {
270 match modifier {
271 TraitBoundModifier::None => {}
272 TraitBoundModifier::Maybe => tokens.append("?"),
273 }
274 trait_ref.to_tokens(tokens);
275 }
276 }
277 }
278 }
279
280 impl ToTokens for WhereClause {
281 fn to_tokens(&self, tokens: &mut Tokens) {
282 if !self.predicates.is_empty() {
283 tokens.append("where");
284 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700285 }
286 }
287 }
David Tolnay8ef93042016-09-04 14:08:40 -0700288
289 impl ToTokens for WherePredicate {
290 fn to_tokens(&self, tokens: &mut Tokens) {
291 match *self {
292 WherePredicate::BoundPredicate(ref predicate) => {
293 predicate.to_tokens(tokens);
294 }
295 WherePredicate::RegionPredicate(ref predicate) => {
296 predicate.to_tokens(tokens);
297 }
298 }
299 }
300 }
301
302 impl ToTokens for WhereBoundPredicate {
303 fn to_tokens(&self, tokens: &mut Tokens) {
304 if !self.bound_lifetimes.is_empty() {
305 tokens.append("for");
306 tokens.append("<");
307 tokens.append_separated(&self.bound_lifetimes, ",");
308 tokens.append(">");
309 }
310 self.bounded_ty.to_tokens(tokens);
311 if !self.bounds.is_empty() {
312 tokens.append(":");
313 tokens.append_separated(&self.bounds, "+");
314 }
315 }
316 }
317
318 impl ToTokens for WhereRegionPredicate {
319 fn to_tokens(&self, tokens: &mut Tokens) {
320 self.lifetime.to_tokens(tokens);
321 if !self.bounds.is_empty() {
322 tokens.append(":");
323 tokens.append_separated(&self.bounds, "+");
324 }
325 }
326 }
David Tolnay87d0b442016-09-04 11:52:12 -0700327}