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