]> git.lizzy.rs Git - rust.git/blob - src/types.rs
Merge pull request #1568 from mathstuf/suffixes-typo
[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, colon_spaces, 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().unwrap().get_span().hi + BytePos(1);
210                 let list_lo = context
211                     .codemap
212                     .span_after(codemap::mk_sp(*span_lo, span_hi), "<");
213                 let separator = if path_context == PathContext::Expr {
214                     "::"
215                 } else {
216                     ""
217                 };
218
219                 // 1 for <
220                 let extra_offset = 1 + separator.len();
221                 // 1 for >
222                 // TODO bad visual indent
223                 let list_shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(1))
224                     .visual_indent(0);
225
226                 let items = itemize_list(context.codemap,
227                                          param_list.into_iter(),
228                                          ">",
229                                          |param| param.get_span().lo,
230                                          |param| param.get_span().hi,
231                                          |seg| seg.rewrite(context, list_shape),
232                                          list_lo,
233                                          span_hi);
234                 let list_str = try_opt!(format_item_list(items, list_shape, context.config));
235
236                 // Update position of last bracket.
237                 *span_lo = next_span_lo;
238
239                 if context.config.spaces_within_angle_brackets && list_str.len() > 0 {
240                     format!("{}< {} >", separator, list_str)
241                 } else {
242                     format!("{}<{}>", separator, list_str)
243                 }
244             }
245             ast::PathParameters::Parenthesized(ref data) => {
246                 let output = match data.output {
247                     Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
248                     None => FunctionRetTy::Default(codemap::DUMMY_SP),
249                 };
250                 try_opt!(format_function_type(data.inputs.iter().map(|x| &**x),
251                                               &output,
252                                               false,
253                                               data.span,
254                                               context,
255                                               shape))
256             }
257             _ => String::new(),
258         }
259     } else {
260         String::new()
261     };
262
263     Some(format!("{}{}", segment.identifier, params))
264 }
265
266 fn format_function_type<'a, I>(inputs: I,
267                                output: &FunctionRetTy,
268                                variadic: bool,
269                                span: Span,
270                                context: &RewriteContext,
271                                shape: Shape)
272                                -> Option<String>
273     where I: ExactSizeIterator,
274           <I as Iterator>::Item: Deref,
275           <I::Item as Deref>::Target: Rewrite + Spanned + 'a
276 {
277     // Code for handling variadics is somewhat duplicated for items, but they
278     // are different enough to need some serious refactoring to share code.
279     enum ArgumentKind<T>
280         where T: Deref,
281               <T as Deref>::Target: Rewrite + Spanned
282     {
283         Regular(Box<T>),
284         Variadic(BytePos),
285     }
286
287     let variadic_arg = if variadic {
288         let variadic_start = context.codemap.span_before(span, "...");
289         Some(ArgumentKind::Variadic(variadic_start))
290     } else {
291         None
292     };
293
294     // 2 for ()
295     let budget = try_opt!(shape.width.checked_sub(2));
296     // 1 for (
297     let offset = shape.indent + 1;
298     let list_lo = context.codemap.span_after(span, "(");
299     let items = itemize_list(context.codemap,
300                              // FIXME Would be nice to avoid this allocation,
301                              // but I couldn't get the types to work out.
302                              inputs
303                                  .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     colon_spaces(context.config.space_before_bound,
349                  context.config.space_after_bound_colon)
350 }
351
352 impl Rewrite for ast::WherePredicate {
353     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
354         // TODO: dead spans?
355         let result = match *self {
356             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
357                                                     ref bound_lifetimes,
358                                                     ref bounded_ty,
359                                                     ref bounds,
360                                                     ..
361                                                 }) => {
362                 let type_str = try_opt!(bounded_ty.rewrite(context, shape));
363
364                 let colon = type_bound_colon(context);
365
366                 if !bound_lifetimes.is_empty() {
367                     let lifetime_str: String = try_opt!(bound_lifetimes.iter()
368                                      .map(|lt| lt.rewrite(context, shape))
369                                      .intersperse(Some(", ".to_string()))
370                                      .collect());
371
372                     let joiner = match context.config.type_punctuation_density {
373                         TypeDensity::Compressed => "+",
374                         TypeDensity::Wide => " + ",
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(joiner.to_string()))
386                                                     .collect());
387
388                     if context.config.spaces_within_angle_brackets && lifetime_str.len() > 0 {
389                         format!("for< {} > {}{}{}",
390                                 lifetime_str,
391                                 type_str,
392                                 colon,
393                                 bounds_str)
394                     } else {
395                         format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)
396                     }
397                 } else {
398                     let joiner = match context.config.type_punctuation_density {
399                         TypeDensity::Compressed => "+",
400                         TypeDensity::Wide => " + ",
401                     };
402                     let used_width = type_str.len() + colon.len();
403                     let budget = try_opt!(shape.width.checked_sub(used_width));
404                     let bounds_str: String = try_opt!(bounds.iter()
405                                                     .map(|ty_bound| {
406                                                         ty_bound.rewrite(context,
407                                                                          Shape::legacy(budget,
408                                                                          shape.indent + used_width))
409                                                     })
410                                                     .intersperse(Some(joiner.to_string()))
411                                                     .collect());
412
413                     format!("{}{}{}", type_str, colon, bounds_str)
414                 }
415             }
416             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
417                                                      ref lifetime,
418                                                      ref bounds,
419                                                      ..
420                                                  }) => {
421                 try_opt!(rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape))
422             }
423             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
424                                                  ref lhs_ty,
425                                                  ref rhs_ty,
426                                                  ..
427                                              }) => {
428                 let lhs_ty_str = try_opt!(lhs_ty.rewrite(context, shape));
429                 // 3 = " = ".len()
430                 let used_width = 3 + lhs_ty_str.len();
431                 let budget = try_opt!(shape.width.checked_sub(used_width));
432                 let rhs_ty_str = try_opt!(rhs_ty.rewrite(context,
433                                                          Shape::legacy(budget,
434                                                                        shape.indent + used_width)));
435                 format!("{} = {}", lhs_ty_str, rhs_ty_str)
436             }
437         };
438
439         wrap_str(result, context.config.max_width, shape)
440     }
441 }
442
443 impl Rewrite for ast::LifetimeDef {
444     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
445         rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape)
446     }
447 }
448
449 fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime,
450                                    bounds: I,
451                                    context: &RewriteContext,
452                                    shape: Shape)
453                                    -> Option<String>
454     where I: ExactSizeIterator<Item = &'b ast::Lifetime>
455 {
456     let result = try_opt!(lt.rewrite(context, shape));
457
458     if bounds.len() == 0 {
459         Some(result)
460     } else {
461         let appendix: Vec<_> = try_opt!(bounds
462                                             .into_iter()
463                                             .map(|b| b.rewrite(context, shape))
464                                             .collect());
465         let colon = type_bound_colon(context);
466         let joiner = match context.config.type_punctuation_density {
467             TypeDensity::Compressed => "+",
468             TypeDensity::Wide => " + ",
469         };
470         let result = format!("{}{}{}", result, colon, appendix.join(joiner));
471         wrap_str(result, context.config.max_width, shape)
472     }
473 }
474
475 impl Rewrite for ast::TyParamBound {
476     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
477         match *self {
478             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
479                 tref.rewrite(context, shape)
480             }
481             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
482                 let budget = try_opt!(shape.width.checked_sub(1));
483                 Some(format!("?{}",
484                              try_opt!(tref.rewrite(context,
485                                                    Shape::legacy(budget, shape.indent + 1)))))
486             }
487             ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
488         }
489     }
490 }
491
492 impl Rewrite for ast::Lifetime {
493     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
494         wrap_str(pprust::lifetime_to_string(self),
495                  context.config.max_width,
496                  shape)
497     }
498 }
499
500 impl Rewrite for ast::TyParamBounds {
501     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
502         let joiner = match context.config.type_punctuation_density {
503             TypeDensity::Compressed => "+",
504             TypeDensity::Wide => " + ",
505         };
506         let strs: Vec<_> = try_opt!(self.iter().map(|b| b.rewrite(context, shape)).collect());
507         wrap_str(strs.join(joiner), context.config.max_width, shape)
508     }
509 }
510
511 impl Rewrite for ast::TyParam {
512     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
513         let mut result = String::with_capacity(128);
514         result.push_str(&self.ident.to_string());
515         if !self.bounds.is_empty() {
516             if context.config.space_before_bound {
517                 result.push_str(" ");
518             }
519             result.push_str(":");
520             if context.config.space_after_bound_colon {
521                 result.push_str(" ");
522             }
523             let joiner = match context.config.type_punctuation_density {
524                 TypeDensity::Compressed => "+",
525                 TypeDensity::Wide => " + ",
526             };
527             let bounds: String =
528                 try_opt!(self.bounds
529                              .iter()
530                              .map(|ty_bound| ty_bound.rewrite(context, shape))
531                              .intersperse(Some(joiner.to_string()))
532                              .collect());
533
534             result.push_str(&bounds);
535         }
536         if let Some(ref def) = self.default {
537
538             let eq_str = match context.config.type_punctuation_density {
539                 TypeDensity::Compressed => "=",
540                 TypeDensity::Wide => " = ",
541             };
542             result.push_str(eq_str);
543             let budget = try_opt!(shape.width.checked_sub(result.len()));
544             let rewrite = try_opt!(def.rewrite(context,
545                                                Shape::legacy(budget, shape.indent + result.len())));
546             result.push_str(&rewrite);
547         }
548
549         wrap_str(result, context.config.max_width, shape)
550     }
551 }
552
553 impl Rewrite for ast::PolyTraitRef {
554     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
555         if !self.bound_lifetimes.is_empty() {
556             let lifetime_str: String = try_opt!(self.bound_lifetimes
557                                                     .iter()
558                                                     .map(|lt| lt.rewrite(context, shape))
559                                                     .intersperse(Some(", ".to_string()))
560                                                     .collect());
561
562             // 6 is "for<> ".len()
563             let extra_offset = lifetime_str.len() + 6;
564             let max_path_width = try_opt!(shape.width.checked_sub(extra_offset));
565             let path_str = try_opt!(self.trait_ref.rewrite(context,
566                                                            Shape::legacy(max_path_width,
567                                                                          shape.indent +
568                                                                          extra_offset)));
569
570             Some(if context.config.spaces_within_angle_brackets && lifetime_str.len() > 0 {
571                      format!("for< {} > {}", lifetime_str, path_str)
572                  } else {
573                      format!("for<{}> {}", lifetime_str, path_str)
574                  })
575         } else {
576             self.trait_ref.rewrite(context, shape)
577         }
578     }
579 }
580
581 impl Rewrite for ast::TraitRef {
582     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
583         rewrite_path(context, PathContext::Type, None, &self.path, shape)
584     }
585 }
586
587 impl Rewrite for ast::Ty {
588     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
589         match self.node {
590             ast::TyKind::TraitObject(ref bounds) => bounds.rewrite(context, shape),
591             ast::TyKind::Ptr(ref mt) => {
592                 let prefix = match mt.mutbl {
593                     Mutability::Mutable => "*mut ",
594                     Mutability::Immutable => "*const ",
595                 };
596
597                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
598             }
599             ast::TyKind::Rptr(ref lifetime, ref mt) => {
600                 let mut_str = format_mutability(mt.mutbl);
601                 let mut_len = mut_str.len();
602                 Some(match *lifetime {
603                          Some(ref lifetime) => {
604                              let lt_budget = try_opt!(shape.width.checked_sub(2 + mut_len));
605                              let lt_str = try_opt!(lifetime.rewrite(context,
606                                                                     Shape::legacy(lt_budget,
607                                                                                   shape.indent +
608                                                                                   2 +
609                                                                                   mut_len)));
610                              let lt_len = lt_str.len();
611                              let budget = try_opt!(shape.width.checked_sub(2 + mut_len + lt_len));
612                              format!("&{} {}{}",
613                                      lt_str,
614                                      mut_str,
615                                      try_opt!(mt.ty.rewrite(context,
616                                                             Shape::legacy(budget,
617                                                                           shape.indent + 2 +
618                                                                           mut_len +
619                                                                           lt_len))))
620                          }
621                          None => {
622                              let budget = try_opt!(shape.width.checked_sub(1 + mut_len));
623                              format!("&{}{}",
624                                      mut_str,
625                                      try_opt!(mt.ty.rewrite(context,
626                                                             Shape::legacy(budget,
627                                                                           shape.indent + 1 +
628                                                                           mut_len))))
629                          }
630                      })
631             }
632             // FIXME: we drop any comments here, even though it's a silly place to put
633             // comments.
634             ast::TyKind::Paren(ref ty) => {
635                 let budget = try_opt!(shape.width.checked_sub(2));
636                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
637                     .map(|ty_str| if context.config.spaces_within_parens {
638                              format!("( {} )", ty_str)
639                          } else {
640                              format!("({})", ty_str)
641                          })
642             }
643             ast::TyKind::Slice(ref ty) => {
644                 let budget = if context.config.spaces_within_square_brackets {
645                     try_opt!(shape.width.checked_sub(4))
646                 } else {
647                     try_opt!(shape.width.checked_sub(2))
648                 };
649                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
650                     .map(|ty_str| if context.config.spaces_within_square_brackets {
651                              format!("[ {} ]", ty_str)
652                          } else {
653                              format!("[{}]", ty_str)
654                          })
655             }
656             ast::TyKind::Tup(ref items) => {
657                 rewrite_tuple(context, items.iter().map(|x| &**x), self.span, shape)
658             }
659             ast::TyKind::Path(ref q_self, ref path) => {
660                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
661             }
662             ast::TyKind::Array(ref ty, ref repeats) => {
663                 let use_spaces = context.config.spaces_within_square_brackets;
664                 let lbr = if use_spaces { "[ " } else { "[" };
665                 let rbr = if use_spaces { " ]" } else { "]" };
666                 rewrite_pair(&**ty, &**repeats, lbr, "; ", rbr, context, shape)
667             }
668             ast::TyKind::Infer => {
669                 if shape.width >= 1 {
670                     Some("_".to_owned())
671                 } else {
672                     None
673                 }
674             }
675             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
676             ast::TyKind::Never => Some(String::from("!")),
677             ast::TyKind::Mac(..) => None,
678             ast::TyKind::ImplicitSelf => Some(String::from("")),
679             ast::TyKind::ImplTrait(ref it) => {
680                 it.rewrite(context, shape)
681                     .map(|it_str| format!("impl {}", it_str))
682             }
683             ast::TyKind::Typeof(..) => unreachable!(),
684         }
685     }
686 }
687
688 fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
689                    span: Span,
690                    context: &RewriteContext,
691                    shape: Shape)
692                    -> Option<String> {
693     let mut result = String::with_capacity(128);
694
695     if !bare_fn.lifetimes.is_empty() {
696         result.push_str("for<");
697         // 6 = "for<> ".len(), 4 = "for<".
698         // This doesn't work out so nicely for mutliline situation with lots of
699         // rightward drift. If that is a problem, we could use the list stuff.
700         result.push_str(&try_opt!(bare_fn
701                                       .lifetimes
702                                       .iter()
703                                       .map(|l| {
704             l.rewrite(context,
705                       Shape::legacy(try_opt!(shape.width.checked_sub(6)), shape.indent + 4))
706         })
707                                       .intersperse(Some(", ".to_string()))
708                                       .collect::<Option<String>>()));
709         result.push_str("> ");
710     }
711
712     result.push_str(::utils::format_unsafety(bare_fn.unsafety));
713
714     if bare_fn.abi != abi::Abi::Rust {
715         result.push_str(&::utils::format_abi(bare_fn.abi, context.config.force_explicit_abi));
716     }
717
718     result.push_str("fn");
719
720     let budget = try_opt!(shape.width.checked_sub(result.len()));
721     let indent = shape.indent + result.len();
722
723     let rewrite = try_opt!(format_function_type(bare_fn.decl.inputs.iter(),
724                                                 &bare_fn.decl.output,
725                                                 bare_fn.decl.variadic,
726                                                 span,
727                                                 context,
728                                                 Shape::legacy(budget, indent)));
729
730     result.push_str(&rewrite);
731
732     Some(result)
733 }