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