]> git.lizzy.rs Git - rust.git/blob - src/types.rs
More space for qself paths
[rust.git] / src / types.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::ops::Deref;
12 use std::iter::ExactSizeIterator;
13
14 use syntax::abi;
15 use syntax::ast::{self, Mutability, FunctionRetTy};
16 use syntax::codemap::{self, Span, BytePos};
17 use syntax::print::pprust;
18 use syntax::symbol::keywords;
19
20 use {Shape, Spanned};
21 use codemap::SpanUtils;
22 use lists::{format_item_list, itemize_list, format_fn_args};
23 use rewrite::{Rewrite, RewriteContext};
24 use utils::{extra_offset, format_mutability, wrap_str};
25 use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
26 use config::TypeDensity;
27 use itertools::Itertools;
28
29 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
30 pub enum PathContext {
31     Expr,
32     Type,
33     Import,
34 }
35
36 // Does not wrap on simple segments.
37 pub fn rewrite_path(context: &RewriteContext,
38                     path_context: PathContext,
39                     qself: Option<&ast::QSelf>,
40                     path: &ast::Path,
41                     shape: Shape)
42                     -> Option<String> {
43     let skip_count = qself.map_or(0, |x| x.position);
44
45     let mut result = if path.is_global() && qself.is_none() &&
46                         path_context != PathContext::Import {
47         "::".to_owned()
48     } else {
49         String::new()
50     };
51
52     let mut span_lo = path.span.lo;
53
54     if let Some(qself) = qself {
55         result.push('<');
56         if context.config.spaces_within_angle_brackets {
57             result.push_str(" ")
58         }
59
60         let fmt_ty = try_opt!(qself.ty.rewrite(context, shape));
61         result.push_str(&fmt_ty);
62
63         if skip_count > 0 {
64             result.push_str(" as ");
65             if path.is_global() && path_context != PathContext::Import {
66                 result.push_str("::");
67             }
68
69             let extra_offset = extra_offset(&result, shape);
70             // 3 = ">::".len()
71             let shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(3));
72
73             result = try_opt!(rewrite_path_segments(PathContext::Type,
74                                                     result,
75                                                     path.segments.iter().take(skip_count),
76                                                     span_lo,
77                                                     path.span.hi,
78                                                     context,
79                                                     shape));
80         }
81
82         if context.config.spaces_within_angle_brackets {
83             result.push_str(" ")
84         }
85
86         result.push_str(">::");
87         span_lo = qself.ty.span.hi + BytePos(1);
88     }
89
90     rewrite_path_segments(path_context,
91                           result,
92                           path.segments.iter().skip(skip_count),
93                           span_lo,
94                           path.span.hi,
95                           context,
96                           shape)
97 }
98
99 fn rewrite_path_segments<'a, I>(path_context: PathContext,
100                                 mut buffer: String,
101                                 iter: I,
102                                 mut span_lo: BytePos,
103                                 span_hi: BytePos,
104                                 context: &RewriteContext,
105                                 shape: Shape)
106                                 -> Option<String>
107     where I: Iterator<Item = &'a ast::PathSegment>
108 {
109     let mut first = true;
110     let shape = shape.visual_indent(0);
111
112     for segment in iter {
113         // Indicates a global path, shouldn't be rendered.
114         if segment.identifier.name == keywords::CrateRoot.name() {
115             continue;
116         }
117         if first {
118             first = false;
119         } else {
120             buffer.push_str("::");
121         }
122
123         let extra_offset = extra_offset(&buffer, shape);
124         let new_shape = try_opt!(shape.shrink_left(extra_offset));
125         let segment_string = try_opt!(rewrite_segment(path_context,
126                                                       segment,
127                                                       &mut span_lo,
128                                                       span_hi,
129                                                       context,
130                                                       new_shape));
131
132         buffer.push_str(&segment_string);
133     }
134
135     Some(buffer)
136 }
137
138 #[derive(Debug)]
139 enum SegmentParam<'a> {
140     LifeTime(&'a ast::Lifetime),
141     Type(&'a ast::Ty),
142     Binding(&'a ast::TypeBinding),
143 }
144
145 impl<'a> SegmentParam<'a> {
146     fn get_span(&self) -> Span {
147         match *self {
148             SegmentParam::LifeTime(lt) => lt.span,
149             SegmentParam::Type(ty) => ty.span,
150             SegmentParam::Binding(binding) => binding.span,
151         }
152     }
153 }
154
155 impl<'a> Rewrite for SegmentParam<'a> {
156     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
157         match *self {
158             SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
159             SegmentParam::Type(ty) => ty.rewrite(context, shape),
160             SegmentParam::Binding(binding) => {
161                 let mut result = match context.config.type_punctuation_density {
162                     TypeDensity::Wide => format!("{} = ", binding.ident),
163                     TypeDensity::Compressed => format!("{}=", binding.ident),
164                 };
165                 let budget = try_opt!(shape.width.checked_sub(result.len()));
166                 let rewrite = try_opt!(binding.ty.rewrite(context,
167                                                           Shape::legacy(budget,
168                                                                         shape.indent +
169                                                                         result.len())));
170                 result.push_str(&rewrite);
171                 Some(result)
172             }
173         }
174     }
175 }
176
177 // Formats a path segment. There are some hacks involved to correctly determine
178 // the segment's associated span since it's not part of the AST.
179 //
180 // The span_lo is assumed to be greater than the end of any previous segment's
181 // parameters and lesser or equal than the start of current segment.
182 //
183 // span_hi is assumed equal to the end of the entire path.
184 //
185 // When the segment contains a positive number of parameters, we update span_lo
186 // so that invariants described above will hold for the next segment.
187 fn rewrite_segment(path_context: PathContext,
188                    segment: &ast::PathSegment,
189                    span_lo: &mut BytePos,
190                    span_hi: BytePos,
191                    context: &RewriteContext,
192                    shape: Shape)
193                    -> Option<String> {
194     let ident_len = segment.identifier.to_string().len();
195     let shape = try_opt!(shape.shrink_left(ident_len));
196
197     let params = if let Some(ref params) = segment.parameters {
198         match **params {
199             ast::PathParameters::AngleBracketed(ref data) if !data.lifetimes.is_empty() ||
200                                                              !data.types.is_empty() ||
201                                                              !data.bindings.is_empty() => {
202                 let param_list = data.lifetimes
203                     .iter()
204                     .map(SegmentParam::LifeTime)
205                     .chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
206                     .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
207                     .collect::<Vec<_>>();
208
209                 let next_span_lo = param_list.last()
210                     .unwrap()
211                     .get_span()
212                     .hi + BytePos(1);
213                 let list_lo = context.codemap.span_after(codemap::mk_sp(*span_lo, span_hi), "<");
214                 let separator = if path_context == PathContext::Expr {
215                     "::"
216                 } else {
217                     ""
218                 };
219
220                 // 1 for <
221                 let extra_offset = 1 + separator.len();
222                 // 1 for >
223                 // TODO bad visual indent
224                 let list_shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(1))
225                     .visual_indent(0);
226
227                 let items = itemize_list(context.codemap,
228                                          param_list.into_iter(),
229                                          ">",
230                                          |param| param.get_span().lo,
231                                          |param| param.get_span().hi,
232                                          |seg| seg.rewrite(context, list_shape),
233                                          list_lo,
234                                          span_hi);
235                 let list_str = try_opt!(format_item_list(items, list_shape, context.config));
236
237                 // Update position of last bracket.
238                 *span_lo = next_span_lo;
239
240                 if context.config.spaces_within_angle_brackets && list_str.len() > 0 {
241                     format!("{}< {} >", separator, list_str)
242                 } else {
243                     format!("{}<{}>", separator, list_str)
244                 }
245             }
246             ast::PathParameters::Parenthesized(ref data) => {
247                 let output = match data.output {
248                     Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
249                     None => FunctionRetTy::Default(codemap::DUMMY_SP),
250                 };
251                 try_opt!(format_function_type(data.inputs.iter().map(|x| &**x),
252                                               &output,
253                                               false,
254                                               data.span,
255                                               context,
256                                               shape))
257             }
258             _ => String::new(),
259         }
260     } else {
261         String::new()
262     };
263
264     Some(format!("{}{}", segment.identifier, params))
265 }
266
267 fn format_function_type<'a, I>(inputs: I,
268                                output: &FunctionRetTy,
269                                variadic: bool,
270                                span: Span,
271                                context: &RewriteContext,
272                                shape: Shape)
273                                -> Option<String>
274     where I: ExactSizeIterator,
275           <I as Iterator>::Item: Deref,
276           <I::Item as Deref>::Target: Rewrite + Spanned + 'a
277 {
278     // Code for handling variadics is somewhat duplicated for items, but they
279     // are different enough to need some serious refactoring to share code.
280     enum ArgumentKind<T>
281         where T: Deref,
282               <T as Deref>::Target: Rewrite + Spanned
283     {
284         Regular(Box<T>),
285         Variadic(BytePos),
286     }
287
288     let variadic_arg = if variadic {
289         let variadic_start = context.codemap.span_before(span, "...");
290         Some(ArgumentKind::Variadic(variadic_start))
291     } else {
292         None
293     };
294
295     // 2 for ()
296     let budget = try_opt!(shape.width.checked_sub(2));
297     // 1 for (
298     let offset = shape.indent + 1;
299     let list_lo = context.codemap.span_after(span, "(");
300     let items = itemize_list(context.codemap,
301                              // FIXME Would be nice to avoid this allocation,
302                              // but I couldn't get the types to work out.
303                              inputs.map(|i| ArgumentKind::Regular(Box::new(i)))
304                                  .chain(variadic_arg),
305                              ")",
306                              |arg| match *arg {
307                                  ArgumentKind::Regular(ref ty) => ty.span().lo,
308                                  ArgumentKind::Variadic(start) => start,
309                              },
310                              |arg| match *arg {
311                                  ArgumentKind::Regular(ref ty) => ty.span().hi,
312                                  ArgumentKind::Variadic(start) => start + BytePos(3),
313                              },
314                              |arg| match *arg {
315                                  ArgumentKind::Regular(ref ty) => {
316                                      ty.rewrite(context, Shape::legacy(budget, offset))
317                                  }
318                                  ArgumentKind::Variadic(_) => Some("...".to_owned()),
319                              },
320                              list_lo,
321                              span.hi);
322
323     let list_str = try_opt!(format_fn_args(items, Shape::legacy(budget, offset), context.config));
324
325     let output = match *output {
326         FunctionRetTy::Ty(ref ty) => {
327             let budget = try_opt!(shape.width.checked_sub(4));
328             let type_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, offset + 4)));
329             format!(" -> {}", type_str)
330         }
331         FunctionRetTy::Default(..) => String::new(),
332     };
333
334     let infix = if !output.is_empty() && output.len() + list_str.len() > shape.width {
335         format!("\n{}", (offset - 1).to_string(context.config))
336     } else {
337         String::new()
338     };
339
340     Some(if context.config.spaces_within_parens {
341              format!("( {} ){}{}", list_str, infix, output)
342          } else {
343              format!("({}){}{}", list_str, infix, output)
344          })
345 }
346
347 fn type_bound_colon(context: &RewriteContext) -> &'static str {
348     match (context.config.space_before_bound, context.config.space_after_bound_colon) {
349         (true, true) => " : ",
350         (true, false) => " :",
351         (false, true) => ": ",
352         (false, false) => ":",
353     }
354 }
355
356 impl Rewrite for ast::WherePredicate {
357     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
358         // TODO: dead spans?
359         let result = match *self {
360             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { ref bound_lifetimes,
361                                                                            ref bounded_ty,
362                                                                            ref bounds,
363                                                                            .. }) => {
364                 let type_str = try_opt!(bounded_ty.rewrite(context, shape));
365
366                 let colon = type_bound_colon(context);
367
368                 if !bound_lifetimes.is_empty() {
369                     let lifetime_str: String = try_opt!(bound_lifetimes.iter()
370                                                                .map(|lt| {
371                                                                    lt.rewrite(context, shape)
372                                                                })
373                                                                .intersperse(Some(", ".to_string()))
374                                                                .collect());
375
376                     // 6 = "for<> ".len()
377                     let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6;
378                     let budget = try_opt!(shape.width.checked_sub(used_width));
379                     let bounds_str: String = try_opt!(bounds.iter()
380                                                     .map(|ty_bound| {
381                                                         ty_bound.rewrite(context,
382                                                                          Shape::legacy(budget,
383                                                                          shape.indent + used_width))
384                                                     })
385                                                     .intersperse(Some(" + ".to_string()))
386                                                     .collect());
387
388                     if context.config.spaces_within_angle_brackets && lifetime_str.len() > 0 {
389                         format!("for< {} > {}{}{}", lifetime_str, type_str, colon, bounds_str)
390                     } else {
391                         format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)
392                     }
393                 } else {
394                     let used_width = type_str.len() + colon.len();
395                     let budget = try_opt!(shape.width.checked_sub(used_width));
396                     let bounds_str: String = try_opt!(bounds.iter()
397                                                     .map(|ty_bound| {
398                                                         ty_bound.rewrite(context,
399                                                                          Shape::legacy(budget,
400                                                                          shape.indent + used_width))
401                                                     })
402                                                     .intersperse(Some(" + ".to_string()))
403                                                     .collect());
404
405                     format!("{}{}{}", type_str, colon, bounds_str)
406                 }
407             }
408             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { ref lifetime,
409                                                                              ref bounds,
410                                                                              .. }) => {
411                 try_opt!(rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape))
412             }
413             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { ref lhs_ty,
414                                                                      ref rhs_ty,
415                                                                      .. }) => {
416                 let lhs_ty_str = try_opt!(lhs_ty.rewrite(context, shape));
417                 // 3 = " = ".len()
418                 let used_width = 3 + lhs_ty_str.len();
419                 let budget = try_opt!(shape.width.checked_sub(used_width));
420                 let rhs_ty_str = try_opt!(rhs_ty.rewrite(context,
421                                                          Shape::legacy(budget,
422                                                                        shape.indent + used_width)));
423                 format!("{} = {}", lhs_ty_str, rhs_ty_str)
424             }
425         };
426
427         wrap_str(result, context.config.max_width, shape)
428     }
429 }
430
431 impl Rewrite for ast::LifetimeDef {
432     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
433         rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape)
434     }
435 }
436
437 fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime,
438                                    bounds: I,
439                                    context: &RewriteContext,
440                                    shape: Shape)
441                                    -> Option<String>
442     where I: ExactSizeIterator<Item = &'b ast::Lifetime>
443 {
444     let result = try_opt!(lt.rewrite(context, shape));
445
446     if bounds.len() == 0 {
447         Some(result)
448     } else {
449         let appendix: Vec<_> =
450             try_opt!(bounds.into_iter().map(|b| b.rewrite(context, shape)).collect());
451         let colon = type_bound_colon(context);
452         let result = format!("{}{}{}", result, colon, appendix.join(" + "));
453         wrap_str(result, context.config.max_width, shape)
454     }
455 }
456
457 impl Rewrite for ast::TyParamBound {
458     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
459         match *self {
460             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
461                 tref.rewrite(context, shape)
462             }
463             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
464                 let budget = try_opt!(shape.width.checked_sub(1));
465                 Some(format!("?{}",
466                              try_opt!(tref.rewrite(context,
467                                                    Shape::legacy(budget, shape.indent + 1)))))
468             }
469             ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
470         }
471     }
472 }
473
474 impl Rewrite for ast::Lifetime {
475     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
476         wrap_str(pprust::lifetime_to_string(self),
477                  context.config.max_width,
478                  shape)
479     }
480 }
481
482 impl Rewrite for ast::TyParamBounds {
483     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
484         let joiner = match context.config.type_punctuation_density {
485             TypeDensity::Compressed => "+",
486             TypeDensity::Wide => " + ",
487         };
488         let strs: Vec<_> = try_opt!(self.iter().map(|b| b.rewrite(context, shape)).collect());
489         wrap_str(strs.join(joiner), context.config.max_width, shape)
490     }
491 }
492
493 impl Rewrite for ast::TyParam {
494     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
495         let mut result = String::with_capacity(128);
496         result.push_str(&self.ident.to_string());
497         if !self.bounds.is_empty() {
498             if context.config.space_before_bound {
499                 result.push_str(" ");
500             }
501             result.push_str(":");
502             if context.config.space_after_bound_colon {
503                 result.push_str(" ");
504             }
505
506             let bounds: String =
507                 try_opt!(self.bounds
508                              .iter()
509                              .map(|ty_bound| ty_bound.rewrite(context, shape))
510                              .intersperse(Some(" + ".to_string()))
511                              .collect());
512
513             result.push_str(&bounds);
514         }
515         if let Some(ref def) = self.default {
516
517             let eq_str = match context.config.type_punctuation_density {
518                 TypeDensity::Compressed => "=",
519                 TypeDensity::Wide => " = ",
520             };
521             result.push_str(eq_str);
522             let budget = try_opt!(shape.width.checked_sub(result.len()));
523             let rewrite = try_opt!(def.rewrite(context,
524                                                Shape::legacy(budget, shape.indent + result.len())));
525             result.push_str(&rewrite);
526         }
527
528         wrap_str(result, context.config.max_width, shape)
529     }
530 }
531
532 impl Rewrite for ast::PolyTraitRef {
533     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
534         if !self.bound_lifetimes.is_empty() {
535             let lifetime_str: String = try_opt!(self.bound_lifetimes
536                                                     .iter()
537                                                     .map(|lt| lt.rewrite(context, shape))
538                                                     .intersperse(Some(", ".to_string()))
539                                                     .collect());
540
541             // 6 is "for<> ".len()
542             let extra_offset = lifetime_str.len() + 6;
543             let max_path_width = try_opt!(shape.width.checked_sub(extra_offset));
544             let path_str = try_opt!(self.trait_ref.rewrite(context,
545                                                            Shape::legacy(max_path_width,
546                                                                          shape.indent +
547                                                                          extra_offset)));
548
549             Some(if context.config.spaces_within_angle_brackets && lifetime_str.len() > 0 {
550                      format!("for< {} > {}", lifetime_str, path_str)
551                  } else {
552                      format!("for<{}> {}", lifetime_str, path_str)
553                  })
554         } else {
555             self.trait_ref.rewrite(context, shape)
556         }
557     }
558 }
559
560 impl Rewrite for ast::TraitRef {
561     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
562         rewrite_path(context, PathContext::Type, None, &self.path, shape)
563     }
564 }
565
566 impl Rewrite for ast::Ty {
567     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
568         match self.node {
569             ast::TyKind::TraitObject(ref bounds) => bounds.rewrite(context, shape),
570             ast::TyKind::Ptr(ref mt) => {
571                 let prefix = match mt.mutbl {
572                     Mutability::Mutable => "*mut ",
573                     Mutability::Immutable => "*const ",
574                 };
575
576                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
577             }
578             ast::TyKind::Rptr(ref lifetime, ref mt) => {
579                 let mut_str = format_mutability(mt.mutbl);
580                 let mut_len = mut_str.len();
581                 Some(match *lifetime {
582                          Some(ref lifetime) => {
583                     let lt_budget = try_opt!(shape.width.checked_sub(2 + mut_len));
584                     let lt_str = try_opt!(lifetime.rewrite(context,
585                                                            Shape::legacy(lt_budget,
586                                                                          shape.indent + 2 +
587                                                                          mut_len)));
588                     let lt_len = lt_str.len();
589                     let budget = try_opt!(shape.width.checked_sub(2 + mut_len + lt_len));
590                     format!("&{} {}{}",
591                             lt_str,
592                             mut_str,
593                             try_opt!(mt.ty.rewrite(context,
594                                                    Shape::legacy(budget,
595                                                                  shape.indent + 2 + mut_len +
596                                                                  lt_len))))
597                 }
598                          None => {
599                     let budget = try_opt!(shape.width.checked_sub(1 + mut_len));
600                     format!("&{}{}",
601                             mut_str,
602                             try_opt!(mt.ty.rewrite(context,
603                                                    Shape::legacy(budget,
604                                                                  shape.indent + 1 + mut_len))))
605                 }
606                      })
607             }
608             // FIXME: we drop any comments here, even though it's a silly place to put
609             // comments.
610             ast::TyKind::Paren(ref ty) => {
611                 let budget = try_opt!(shape.width.checked_sub(2));
612                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
613                     .map(|ty_str| if context.config.spaces_within_parens {
614                              format!("( {} )", ty_str)
615                          } else {
616                              format!("({})", ty_str)
617                          })
618             }
619             ast::TyKind::Slice(ref ty) => {
620                 let budget = if context.config.spaces_within_square_brackets {
621                     try_opt!(shape.width.checked_sub(4))
622                 } else {
623                     try_opt!(shape.width.checked_sub(2))
624                 };
625                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
626                     .map(|ty_str| if context.config.spaces_within_square_brackets {
627                              format!("[ {} ]", ty_str)
628                          } else {
629                              format!("[{}]", ty_str)
630                          })
631             }
632             ast::TyKind::Tup(ref items) => {
633                 rewrite_tuple(context, items.iter().map(|x| &**x), self.span, shape)
634             }
635             ast::TyKind::Path(ref q_self, ref path) => {
636                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
637             }
638             ast::TyKind::Array(ref ty, ref repeats) => {
639                 let use_spaces = context.config.spaces_within_square_brackets;
640                 let lbr = if use_spaces { "[ " } else { "[" };
641                 let rbr = if use_spaces { " ]" } else { "]" };
642                 rewrite_pair(&**ty, &**repeats, lbr, "; ", rbr, context, shape)
643             }
644             ast::TyKind::Infer => {
645                 if shape.width >= 1 {
646                     Some("_".to_owned())
647                 } else {
648                     None
649                 }
650             }
651             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
652             ast::TyKind::Never => Some(String::from("!")),
653             ast::TyKind::Mac(..) => None,
654             ast::TyKind::ImplicitSelf => Some(String::from("")),
655             ast::TyKind::ImplTrait(ref it) => {
656                 it.rewrite(context, shape).map(|it_str| format!("impl {}", it_str))
657             }
658             ast::TyKind::Typeof(..) => unreachable!(),
659         }
660     }
661 }
662
663 fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
664                    span: Span,
665                    context: &RewriteContext,
666                    shape: Shape)
667                    -> Option<String> {
668     let mut result = String::with_capacity(128);
669
670     if !bare_fn.lifetimes.is_empty() {
671         result.push_str("for<");
672         // 6 = "for<> ".len(), 4 = "for<".
673         // This doesn't work out so nicely for mutliline situation with lots of
674         // rightward drift. If that is a problem, we could use the list stuff.
675         result.push_str(&try_opt!(bare_fn.lifetimes
676                                       .iter()
677                                       .map(|l| {
678                                                l.rewrite(context,
679                       Shape::legacy(try_opt!(shape.width.checked_sub(6)), shape.indent + 4))
680                                            })
681                                       .intersperse(Some(", ".to_string()))
682                                       .collect::<Option<String>>()));
683         result.push_str("> ");
684     }
685
686     result.push_str(::utils::format_unsafety(bare_fn.unsafety));
687
688     if bare_fn.abi != abi::Abi::Rust {
689         result.push_str(&::utils::format_abi(bare_fn.abi, context.config.force_explicit_abi));
690     }
691
692     result.push_str("fn");
693
694     let budget = try_opt!(shape.width.checked_sub(result.len()));
695     let indent = shape.indent + result.len();
696
697     let rewrite = try_opt!(format_function_type(bare_fn.decl.inputs.iter(),
698                                                 &bare_fn.decl.output,
699                                                 bare_fn.decl.variadic,
700                                                 span,
701                                                 context,
702                                                 Shape::legacy(budget, indent)));
703
704     result.push_str(&rewrite);
705
706     Some(result)
707 }