blob: 46d7c43e3ba11cc3157f0a0139a452e8f2dc31d6 [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 Tolnay9bf4af82017-01-07 11:17:46 -08005#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -07006pub 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
David Tolnaye7678922016-10-13 20:44:03 -070012#[cfg(feature = "printing")]
13/// Returned by `Generics::split_for_impl`.
14#[derive(Debug)]
15pub struct ImplGenerics<'a>(&'a Generics);
16
17#[cfg(feature = "printing")]
18/// Returned by `Generics::split_for_impl`.
19#[derive(Debug)]
20pub struct TyGenerics<'a>(&'a Generics);
21
David Tolnayc879a502017-01-25 15:51:32 -080022#[cfg(feature = "printing")]
23/// Returned by `TyGenerics::as_turbofish`.
24#[derive(Debug)]
25pub struct Turbofish<'a>(&'a Generics);
26
David Tolnaye95cc9f2017-01-25 15:57:09 -080027#[cfg(feature = "printing")]
David Tolnayb153dbc2016-10-04 23:39:10 -070028impl Generics {
29 /// Split a type's generics into the pieces required for impl'ing a trait
30 /// for that type.
31 ///
32 /// ```
33 /// # extern crate syn;
34 /// # #[macro_use]
35 /// # extern crate quote;
36 /// # fn main() {
37 /// # let generics: syn::Generics = Default::default();
38 /// # let name = syn::Ident::new("MyType");
39 /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
40 /// quote! {
41 /// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
42 /// // ...
43 /// }
44 /// }
45 /// # ;
46 /// # }
47 /// ```
David Tolnaye7678922016-10-13 20:44:03 -070048 pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
49 (ImplGenerics(self), TyGenerics(self), &self.where_clause)
David Tolnayb153dbc2016-10-04 23:39:10 -070050 }
51}
52
David Tolnaye95cc9f2017-01-25 15:57:09 -080053#[cfg(feature = "printing")]
David Tolnayc879a502017-01-25 15:51:32 -080054impl<'a> TyGenerics<'a> {
David Tolnayc879a502017-01-25 15:51:32 -080055 /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
56 pub fn as_turbofish(&self) -> Turbofish {
57 Turbofish(self.0)
58 }
59}
60
David Tolnay9bf4af82017-01-07 11:17:46 -080061#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070062pub struct Lifetime {
63 pub ident: Ident,
64}
65
David Tolnay01405f02016-10-02 09:05:02 -070066impl Lifetime {
67 pub fn new<T: Into<Ident>>(t: T) -> Self {
David Tolnayff3b8ae2016-10-08 11:54:18 -070068 let id = Ident::new(t);
69 if !id.as_ref().starts_with('\'') {
70 panic!("lifetime name must start with apostrophe as in \"'a\", \
David Tolnay3bcfb722016-10-08 11:58:36 -070071 got {:?}",
72 id.as_ref());
David Tolnayff3b8ae2016-10-08 11:54:18 -070073 }
74 Lifetime { ident: id }
David Tolnay01405f02016-10-02 09:05:02 -070075 }
76}
77
David Tolnay771ecf42016-09-23 19:26:37 -070078/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnay9bf4af82017-01-07 11:17:46 -080079#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070080pub struct LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -070081 pub attrs: Vec<Attribute>,
David Tolnayb79ee962016-09-04 09:39:20 -070082 pub lifetime: Lifetime,
83 pub bounds: Vec<Lifetime>,
84}
85
David Tolnayf9505b52016-10-02 09:18:52 -070086impl LifetimeDef {
87 pub fn new<T: Into<Ident>>(t: T) -> Self {
88 LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -070089 attrs: Vec::new(),
David Tolnayf9505b52016-10-02 09:18:52 -070090 lifetime: Lifetime::new(t),
91 bounds: Vec::new(),
92 }
93 }
94}
95
David Tolnay9bf4af82017-01-07 11:17:46 -080096#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070097pub struct TyParam {
David Tolnaye7678922016-10-13 20:44:03 -070098 pub attrs: Vec<Attribute>,
David Tolnayb79ee962016-09-04 09:39:20 -070099 pub ident: Ident,
100 pub bounds: Vec<TyParamBound>,
101 pub default: Option<Ty>,
102}
103
David Tolnay771ecf42016-09-23 19:26:37 -0700104/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -0700105/// `typeck::collect::compute_bounds` matches these against
106/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -0700107/// detects Copy, Send and Sync.
David Tolnay9bf4af82017-01-07 11:17:46 -0800108#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700109pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -0700110 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -0700111 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -0700112}
113
David Tolnay771ecf42016-09-23 19:26:37 -0700114/// A modifier on a bound, currently this is only used for `?Sized`, where the
115/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay9bf4af82017-01-07 11:17:46 -0800116#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnay55337722016-09-11 12:58:56 -0700117pub enum TraitBoundModifier {
118 None,
119 Maybe,
120}
121
David Tolnay771ecf42016-09-23 19:26:37 -0700122/// A `where` clause in a definition
David Tolnay9bf4af82017-01-07 11:17:46 -0800123#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
David Tolnay55337722016-09-11 12:58:56 -0700124pub struct WhereClause {
125 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700126}
127
David Tolnayb153dbc2016-10-04 23:39:10 -0700128impl WhereClause {
129 pub fn none() -> Self {
David Tolnay2e737362016-10-05 23:44:15 -0700130 WhereClause { predicates: Vec::new() }
David Tolnayb153dbc2016-10-04 23:39:10 -0700131 }
132}
133
David Tolnayb79ee962016-09-04 09:39:20 -0700134/// A single predicate in a `where` clause
David Tolnay9bf4af82017-01-07 11:17:46 -0800135#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700136pub enum WherePredicate {
137 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
138 BoundPredicate(WhereBoundPredicate),
139 /// A lifetime predicate, e.g. `'a: 'b+'c`
140 RegionPredicate(WhereRegionPredicate),
David Tolnayf8e08832017-01-23 00:04:32 -0800141 /// An equality predicate (unsupported)
142 EqPredicate(WhereEqPredicate),
David Tolnayb79ee962016-09-04 09:39:20 -0700143}
144
145/// A type bound.
146///
147/// E.g. `for<'c> Foo: Send+Clone+'c`
David Tolnay9bf4af82017-01-07 11:17:46 -0800148#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700149pub struct WhereBoundPredicate {
150 /// Any lifetimes from a `for` binding
151 pub bound_lifetimes: Vec<LifetimeDef>,
152 /// The type being bounded
153 pub bounded_ty: Ty,
154 /// Trait and lifetime bounds (`Clone+Send+'static`)
155 pub bounds: Vec<TyParamBound>,
156}
157
158/// A lifetime predicate.
159///
160/// E.g. `'a: 'b+'c`
David Tolnay9bf4af82017-01-07 11:17:46 -0800161#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700162pub struct WhereRegionPredicate {
163 pub lifetime: Lifetime,
164 pub bounds: Vec<Lifetime>,
165}
166
David Tolnayf8e08832017-01-23 00:04:32 -0800167/// An equality predicate (unsupported).
168///
169/// E.g. `T=int`
170#[derive(Debug, Clone, Eq, PartialEq, Hash)]
171pub struct WhereEqPredicate {
172 pub lhs_ty: Ty,
173 pub rhs_ty: Ty,
174}
175
David Tolnay86eca752016-09-04 11:26:41 -0700176#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700177pub mod parsing {
178 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700179 use attr::parsing::outer_attr;
David Tolnay55337722016-09-11 12:58:56 -0700180 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700181 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700182
David Tolnay3cf52982016-10-01 17:11:37 -0700183 named!(pub generics -> Generics, map!(
184 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700185 do_parse!(
186 punct!("<") >>
187 lifetimes: separated_list!(punct!(","), lifetime_def) >>
188 ty_params: opt_vec!(preceded!(
189 cond!(!lifetimes.is_empty(), punct!(",")),
190 separated_nonempty_list!(punct!(","), ty_param)
191 )) >>
David Tolnay82a47d52016-10-30 13:01:38 -0700192 cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700193 punct!(">") >>
194 (lifetimes, ty_params)
195 )
196 |
197 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700198 ),
199 |(lifetimes, ty_params)| Generics {
200 lifetimes: lifetimes,
201 ty_params: ty_params,
202 where_clause: Default::default(),
203 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700204 ));
205
David Tolnayb5a7b142016-09-13 22:46:39 -0700206 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700207 punct!("'"),
David Tolnaye43ffb72016-10-24 22:33:31 -0700208 alt!(
209 map!(ident, |id| Lifetime {
210 ident: format!("'{}", id).into(),
211 })
212 |
213 map!(keyword!("static"), |_| Lifetime {
214 ident: "'static".into(),
215 })
216 )
David Tolnay9d8f1972016-09-04 11:58:48 -0700217 ));
218
David Tolnayb5a7b142016-09-13 22:46:39 -0700219 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700220 attrs: many0!(outer_attr) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700221 life: lifetime >>
222 bounds: opt_vec!(preceded!(
223 punct!(":"),
David Tolnayd95baae2016-10-30 00:47:53 -0700224 separated_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700225 )) >>
226 (LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -0700227 attrs: attrs,
David Tolnay9d8f1972016-09-04 11:58:48 -0700228 lifetime: life,
229 bounds: bounds,
230 })
231 ));
232
David Tolnayb5a7b142016-09-13 22:46:39 -0700233 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700234 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700235 punct!("<") >>
David Tolnayff46fd22016-10-08 13:53:28 -0700236 lifetimes: terminated_list!(punct!(","), lifetime_def) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700237 punct!(">") >>
238 (lifetimes)
239 )));
240
David Tolnayb5a7b142016-09-13 22:46:39 -0700241 named!(ty_param -> TyParam, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700242 attrs: many0!(outer_attr) >>
David Tolnay55337722016-09-11 12:58:56 -0700243 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700244 bounds: opt_vec!(preceded!(
245 punct!(":"),
246 separated_nonempty_list!(punct!("+"), ty_param_bound)
247 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700248 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700249 punct!("="),
250 ty
251 )) >>
252 (TyParam {
David Tolnaye7678922016-10-13 20:44:03 -0700253 attrs: attrs,
David Tolnay55337722016-09-11 12:58:56 -0700254 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700255 bounds: bounds,
256 default: default,
257 })
258 ));
259
David Tolnayb5a7b142016-09-13 22:46:39 -0700260 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700261 preceded!(punct!("?"), poly_trait_ref) => {
262 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
263 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700264 |
265 lifetime => { TyParamBound::Region }
266 |
David Tolnay55337722016-09-11 12:58:56 -0700267 poly_trait_ref => {
268 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
269 }
270 ));
271
David Tolnayb5a7b142016-09-13 22:46:39 -0700272 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700273 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700274 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700275 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
276 option!(punct!(",")) >>
277 (WhereClause { predicates: predicates })
278 )
279 |
280 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700281 ));
282
David Tolnayb5a7b142016-09-13 22:46:39 -0700283 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700284 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700285 ident: lifetime >>
David Tolnayd95baae2016-10-30 00:47:53 -0700286 bounds: opt_vec!(preceded!(
287 punct!(":"),
288 separated_list!(punct!("+"), lifetime)
289 )) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700290 (WherePredicate::RegionPredicate(WhereRegionPredicate {
291 lifetime: ident,
292 bounds: bounds,
293 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700294 )
295 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700296 do_parse!(
297 bound_lifetimes: bound_lifetimes >>
298 bounded_ty: ty >>
299 punct!(":") >>
300 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
301 (WherePredicate::BoundPredicate(WhereBoundPredicate {
302 bound_lifetimes: bound_lifetimes,
303 bounded_ty: bounded_ty,
304 bounds: bounds,
305 }))
306 )
307 ));
308}
David Tolnay87d0b442016-09-04 11:52:12 -0700309
310#[cfg(feature = "printing")]
311mod printing {
312 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700313 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700314 use quote::{Tokens, ToTokens};
315
David Tolnay8ef93042016-09-04 14:08:40 -0700316 impl ToTokens for Generics {
317 fn to_tokens(&self, tokens: &mut Tokens) {
318 let has_lifetimes = !self.lifetimes.is_empty();
319 let has_ty_params = !self.ty_params.is_empty();
320 if has_lifetimes || has_ty_params {
321 tokens.append("<");
322 tokens.append_separated(&self.lifetimes, ",");
323 if has_lifetimes && has_ty_params {
324 tokens.append(",");
325 }
326 tokens.append_separated(&self.ty_params, ",");
327 tokens.append(">");
328 }
David Tolnay8ef93042016-09-04 14:08:40 -0700329 }
330 }
331
David Tolnaye7678922016-10-13 20:44:03 -0700332 impl<'a> ToTokens for ImplGenerics<'a> {
333 fn to_tokens(&self, tokens: &mut Tokens) {
334 let has_lifetimes = !self.0.lifetimes.is_empty();
335 let has_ty_params = !self.0.ty_params.is_empty();
336 if has_lifetimes || has_ty_params {
337 tokens.append("<");
338 tokens.append_separated(&self.0.lifetimes, ",");
339 // Leave off the type parameter defaults
340 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
341 if i > 0 || has_lifetimes {
342 tokens.append(",");
343 }
344 tokens.append_all(ty_param.attrs.outer());
345 ty_param.ident.to_tokens(tokens);
346 if !ty_param.bounds.is_empty() {
347 tokens.append(":");
348 tokens.append_separated(&ty_param.bounds, "+");
349 }
350 }
351 tokens.append(">");
352 }
353 }
354 }
355
356 impl<'a> ToTokens for TyGenerics<'a> {
357 fn to_tokens(&self, tokens: &mut Tokens) {
358 let has_lifetimes = !self.0.lifetimes.is_empty();
359 let has_ty_params = !self.0.ty_params.is_empty();
360 if has_lifetimes || has_ty_params {
361 tokens.append("<");
362 // Leave off the lifetime bounds and attributes
363 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
364 tokens.append_separated(lifetimes, ",");
365 if has_lifetimes && has_ty_params {
366 tokens.append(",");
367 }
368 // Leave off the type parameter bounds, defaults, and attributes
369 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
370 tokens.append_separated(ty_params, ",");
371 tokens.append(">");
372 }
373 }
374 }
375
David Tolnayc879a502017-01-25 15:51:32 -0800376 impl<'a> ToTokens for Turbofish<'a> {
377 fn to_tokens(&self, tokens: &mut Tokens) {
378 let has_lifetimes = !self.0.lifetimes.is_empty();
379 let has_ty_params = !self.0.ty_params.is_empty();
380 if has_lifetimes || has_ty_params {
381 tokens.append("::");
382 TyGenerics(self.0).to_tokens(tokens);
383 }
384 }
385 }
386
David Tolnay87d0b442016-09-04 11:52:12 -0700387 impl ToTokens for Lifetime {
388 fn to_tokens(&self, tokens: &mut Tokens) {
389 self.ident.to_tokens(tokens);
390 }
391 }
392
393 impl ToTokens for LifetimeDef {
394 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700395 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700396 self.lifetime.to_tokens(tokens);
397 if !self.bounds.is_empty() {
398 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700399 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700400 }
401 }
402 }
403
David Tolnay8ef93042016-09-04 14:08:40 -0700404 impl ToTokens for TyParam {
405 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700406 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700407 self.ident.to_tokens(tokens);
408 if !self.bounds.is_empty() {
409 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700410 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700411 }
412 if let Some(ref default) = self.default {
413 tokens.append("=");
414 default.to_tokens(tokens);
415 }
416 }
417 }
418
David Tolnay87d0b442016-09-04 11:52:12 -0700419 impl ToTokens for TyParamBound {
420 fn to_tokens(&self, tokens: &mut Tokens) {
421 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700422 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700423 TyParamBound::Trait(ref trait_ref, modifier) => {
424 match modifier {
425 TraitBoundModifier::None => {}
426 TraitBoundModifier::Maybe => tokens.append("?"),
427 }
428 trait_ref.to_tokens(tokens);
429 }
430 }
431 }
432 }
433
434 impl ToTokens for WhereClause {
435 fn to_tokens(&self, tokens: &mut Tokens) {
436 if !self.predicates.is_empty() {
437 tokens.append("where");
438 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700439 }
440 }
441 }
David Tolnay8ef93042016-09-04 14:08:40 -0700442
443 impl ToTokens for WherePredicate {
444 fn to_tokens(&self, tokens: &mut Tokens) {
445 match *self {
446 WherePredicate::BoundPredicate(ref predicate) => {
447 predicate.to_tokens(tokens);
448 }
449 WherePredicate::RegionPredicate(ref predicate) => {
450 predicate.to_tokens(tokens);
451 }
David Tolnayf8e08832017-01-23 00:04:32 -0800452 WherePredicate::EqPredicate(ref predicate) => {
453 predicate.to_tokens(tokens);
454 }
David Tolnay8ef93042016-09-04 14:08:40 -0700455 }
456 }
457 }
458
459 impl ToTokens for WhereBoundPredicate {
460 fn to_tokens(&self, tokens: &mut Tokens) {
461 if !self.bound_lifetimes.is_empty() {
462 tokens.append("for");
463 tokens.append("<");
464 tokens.append_separated(&self.bound_lifetimes, ",");
465 tokens.append(">");
466 }
467 self.bounded_ty.to_tokens(tokens);
468 if !self.bounds.is_empty() {
469 tokens.append(":");
470 tokens.append_separated(&self.bounds, "+");
471 }
472 }
473 }
474
475 impl ToTokens for WhereRegionPredicate {
476 fn to_tokens(&self, tokens: &mut Tokens) {
477 self.lifetime.to_tokens(tokens);
478 if !self.bounds.is_empty() {
479 tokens.append(":");
480 tokens.append_separated(&self.bounds, "+");
481 }
482 }
483 }
David Tolnayf8e08832017-01-23 00:04:32 -0800484
485 impl ToTokens for WhereEqPredicate {
486 fn to_tokens(&self, tokens: &mut Tokens) {
487 self.lhs_ty.to_tokens(tokens);
488 tokens.append("=");
489 self.rhs_ty.to_tokens(tokens);
490 }
491 }
David Tolnay87d0b442016-09-04 11:52:12 -0700492}