]> git.lizzy.rs Git - rust.git/blob - src/types.rs
Foramt macro on types
[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::ast::{self, FunctionRetTy, Mutability};
15 use syntax::codemap::{self, BytePos, Span};
16 use syntax::print::pprust;
17 use syntax::symbol::keywords;
18
19 use spanned::Spanned;
20 use codemap::SpanUtils;
21 use config::{IndentStyle, TypeDensity};
22 use expr::{rewrite_pair, rewrite_tuple, rewrite_unary_prefix, wrap_args_with_parens, PairParts};
23 use items::{format_generics_item_list, generics_shape_from_config};
24 use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListTactic, Separator,
25             SeparatorPlace, SeparatorTactic};
26 use macros::{rewrite_macro, MacroPosition};
27 use rewrite::{Rewrite, RewriteContext};
28 use shape::Shape;
29 use utils::{colon_spaces, extra_offset, first_line_width, format_abi, format_mutability,
30             last_line_width, mk_sp};
31
32 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
33 pub enum PathContext {
34     Expr,
35     Type,
36     Import,
37 }
38
39 // Does not wrap on simple segments.
40 pub fn rewrite_path(
41     context: &RewriteContext,
42     path_context: PathContext,
43     qself: Option<&ast::QSelf>,
44     path: &ast::Path,
45     shape: Shape,
46 ) -> Option<String> {
47     let skip_count = qself.map_or(0, |x| x.position);
48
49     let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import {
50         "::".to_owned()
51     } else {
52         String::new()
53     };
54
55     let mut span_lo = path.span.lo();
56
57     if let Some(qself) = qself {
58         result.push('<');
59         if context.config.spaces_within_parens_and_brackets() {
60             result.push_str(" ")
61         }
62
63         let fmt_ty = qself.ty.rewrite(context, shape)?;
64         result.push_str(&fmt_ty);
65
66         if skip_count > 0 {
67             result.push_str(" as ");
68             if path.is_global() && path_context != PathContext::Import {
69                 result.push_str("::");
70             }
71
72             // 3 = ">::".len()
73             let shape = shape.sub_width(3)?;
74
75             result = 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_parens_and_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 = shape.shrink_left(extra_offset)?;
133         let segment_string = 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 = shape.width.checked_sub(result.len())?;
176                 let rewrite = binding
177                     .ty
178                     .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
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 = 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             {
213                 let param_list = data.lifetimes
214                     .iter()
215                     .map(SegmentParam::LifeTime)
216                     .chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
217                     .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
218                     .collect::<Vec<_>>();
219
220                 let next_span_lo = param_list.last().unwrap().get_span().hi() + BytePos(1);
221                 let list_lo = context.codemap.span_after(mk_sp(*span_lo, span_hi), "<");
222                 let separator = if path_context == PathContext::Expr {
223                     "::"
224                 } else {
225                     ""
226                 };
227
228                 let generics_shape =
229                     generics_shape_from_config(context.config, shape, separator.len())?;
230                 let one_line_width = shape.width.checked_sub(separator.len() + 2)?;
231                 let items = itemize_list(
232                     context.codemap,
233                     param_list.into_iter(),
234                     ">",
235                     ",",
236                     |param| param.get_span().lo(),
237                     |param| param.get_span().hi(),
238                     |seg| seg.rewrite(context, generics_shape),
239                     list_lo,
240                     span_hi,
241                     false,
242                 );
243                 let generics_str =
244                     format_generics_item_list(context, items, generics_shape, one_line_width)?;
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                 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 = shape.width.checked_sub(2)?;
307     // 1 for (
308     let offset = match context.config.indent_style() {
309         IndentStyle::Block => {
310             shape
311                 .block()
312                 .block_indent(context.config.tab_spaces())
313                 .indent
314         }
315         IndentStyle::Visual => shape.indent + 1,
316     };
317     let list_shape = Shape::legacy(budget, offset);
318     let list_lo = context.codemap.span_after(span, "(");
319     let items = itemize_list(
320         context.codemap,
321         // FIXME Would be nice to avoid this allocation,
322         // but I couldn't get the types to work out.
323         inputs
324             .map(|i| ArgumentKind::Regular(Box::new(i)))
325             .chain(variadic_arg),
326         ")",
327         ",",
328         |arg| match *arg {
329             ArgumentKind::Regular(ref ty) => ty.span().lo(),
330             ArgumentKind::Variadic(start) => start,
331         },
332         |arg| match *arg {
333             ArgumentKind::Regular(ref ty) => ty.span().hi(),
334             ArgumentKind::Variadic(start) => start + BytePos(3),
335         },
336         |arg| match *arg {
337             ArgumentKind::Regular(ref ty) => ty.rewrite(context, list_shape),
338             ArgumentKind::Variadic(_) => Some("...".to_owned()),
339         },
340         list_lo,
341         span.hi(),
342         false,
343     );
344
345     let item_vec: Vec<_> = items.collect();
346
347     let tactic = definitive_tactic(
348         &*item_vec,
349         ListTactic::HorizontalVertical,
350         Separator::Comma,
351         budget,
352     );
353
354     let fmt = ListFormatting {
355         tactic: tactic,
356         separator: ",",
357         trailing_separator: if !context.use_block_indent() || variadic {
358             SeparatorTactic::Never
359         } else {
360             context.config.trailing_comma()
361         },
362         separator_place: SeparatorPlace::Back,
363         shape: list_shape,
364         ends_with_newline: tactic.ends_with_newline(context.config.indent_style()),
365         preserve_newline: true,
366         config: context.config,
367     };
368
369     let list_str = write_list(&item_vec, &fmt)?;
370
371     let ty_shape = match context.config.indent_style() {
372         // 4 = " -> "
373         IndentStyle::Block => shape.offset_left(4)?,
374         IndentStyle::Visual => shape.block_left(4)?,
375     };
376     let output = match *output {
377         FunctionRetTy::Ty(ref ty) => {
378             let type_str = ty.rewrite(context, ty_shape)?;
379             format!(" -> {}", type_str)
380         }
381         FunctionRetTy::Default(..) => String::new(),
382     };
383
384     let extendable = (!list_str.contains('\n') || list_str.is_empty()) && !output.contains('\n');
385     let args = wrap_args_with_parens(
386         context,
387         &list_str,
388         extendable,
389         shape.sub_width(first_line_width(&output))?,
390         Shape::indented(offset, context.config),
391     );
392     if last_line_width(&args) + first_line_width(&output) <= shape.width {
393         Some(format!("{}{}", args, output))
394     } else {
395         Some(format!(
396             "{}\n{}{}",
397             args,
398             offset.to_string(context.config),
399             output.trim_left()
400         ))
401     }
402 }
403
404 fn type_bound_colon(context: &RewriteContext) -> &'static str {
405     colon_spaces(
406         context.config.space_before_colon(),
407         context.config.space_after_colon(),
408     )
409 }
410
411 impl Rewrite for ast::WherePredicate {
412     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
413         // TODO: dead spans?
414         let result = match *self {
415             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
416                 ref bound_lifetimes,
417                 ref bounded_ty,
418                 ref bounds,
419                 ..
420             }) => {
421                 let type_str = bounded_ty.rewrite(context, shape)?;
422
423                 let colon = type_bound_colon(context);
424
425                 if !bound_lifetimes.is_empty() {
426                     let lifetime_str: String = bound_lifetimes
427                         .iter()
428                         .map(|lt| lt.rewrite(context, shape))
429                         .collect::<Option<Vec<_>>>()?
430                         .join(", ");
431
432                     // 6 = "for<> ".len()
433                     let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6;
434                     let ty_shape = shape.offset_left(used_width)?;
435                     let bounds = bounds
436                         .iter()
437                         .map(|ty_bound| ty_bound.rewrite(context, ty_shape))
438                         .collect::<Option<Vec<_>>>()?;
439                     let bounds_str = join_bounds(context, ty_shape, &bounds);
440
441                     if context.config.spaces_within_parens_and_brackets()
442                         && !lifetime_str.is_empty()
443                     {
444                         format!(
445                             "for< {} > {}{}{}",
446                             lifetime_str, type_str, colon, bounds_str
447                         )
448                     } else {
449                         format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)
450                     }
451                 } else {
452                     let used_width = type_str.len() + colon.len();
453                     let ty_shape = match context.config.indent_style() {
454                         IndentStyle::Visual => shape.block_left(used_width)?,
455                         IndentStyle::Block => shape,
456                     };
457                     let bounds = bounds
458                         .iter()
459                         .map(|ty_bound| ty_bound.rewrite(context, ty_shape))
460                         .collect::<Option<Vec<_>>>()?;
461                     let overhead = type_str.len() + colon.len();
462                     let bounds_str = join_bounds(context, ty_shape.sub_width(overhead)?, &bounds);
463
464                     format!("{}{}{}", type_str, colon, bounds_str)
465                 }
466             }
467             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
468                 ref lifetime,
469                 ref bounds,
470                 ..
471             }) => rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape)?,
472             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
473                 ref lhs_ty,
474                 ref rhs_ty,
475                 ..
476             }) => {
477                 let lhs_ty_str = lhs_ty.rewrite(context, shape)?;
478                 // 3 = " = ".len()
479                 let used_width = 3 + lhs_ty_str.len();
480                 let budget = shape.width.checked_sub(used_width)?;
481                 let rhs_ty_str =
482                     rhs_ty.rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
483                 format!("{} = {}", lhs_ty_str, rhs_ty_str)
484             }
485         };
486
487         Some(result)
488     }
489 }
490
491 impl Rewrite for ast::LifetimeDef {
492     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
493         rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape)
494     }
495 }
496
497 fn rewrite_bounded_lifetime<'b, I>(
498     lt: &ast::Lifetime,
499     bounds: I,
500     context: &RewriteContext,
501     shape: Shape,
502 ) -> Option<String>
503 where
504     I: ExactSizeIterator<Item = &'b ast::Lifetime>,
505 {
506     let result = lt.rewrite(context, shape)?;
507
508     if bounds.len() == 0 {
509         Some(result)
510     } else {
511         let appendix = bounds
512             .into_iter()
513             .map(|b| b.rewrite(context, shape))
514             .collect::<Option<Vec<_>>>()?;
515         let colon = type_bound_colon(context);
516         let overhead = last_line_width(&result) + colon.len();
517         let result = format!(
518             "{}{}{}",
519             result,
520             colon,
521             join_bounds(context, shape.sub_width(overhead)?, &appendix)
522         );
523         Some(result)
524     }
525 }
526
527 impl Rewrite for ast::TyParamBound {
528     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
529         match *self {
530             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
531                 tref.rewrite(context, shape)
532             }
533             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
534                 Some(format!(
535                     "?{}",
536                     tref.rewrite(context, shape.offset_left(1)?)?
537                 ))
538             }
539             ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
540         }
541     }
542 }
543
544 impl Rewrite for ast::Lifetime {
545     fn rewrite(&self, _: &RewriteContext, _: Shape) -> Option<String> {
546         Some(pprust::lifetime_to_string(self))
547     }
548 }
549
550 impl Rewrite for ast::TyParamBounds {
551     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
552         let strs = self.iter()
553             .map(|b| b.rewrite(context, shape))
554             .collect::<Option<Vec<_>>>()?;
555         Some(join_bounds(context, shape, &strs))
556     }
557 }
558
559 impl Rewrite for ast::TyParam {
560     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
561         let mut result = String::with_capacity(128);
562         // FIXME: If there are more than one attributes, this will force multiline.
563         match self.attrs.rewrite(context, shape) {
564             Some(ref rw) if !rw.is_empty() => result.push_str(&format!("{} ", rw)),
565             _ => (),
566         }
567         result.push_str(&self.ident.to_string());
568         if !self.bounds.is_empty() {
569             result.push_str(type_bound_colon(context));
570             let strs = self.bounds
571                 .iter()
572                 .map(|ty_bound| ty_bound.rewrite(context, shape))
573                 .collect::<Option<Vec<_>>>()?;
574             result.push_str(&join_bounds(context, shape, &strs));
575         }
576         if let Some(ref def) = self.default {
577             let eq_str = match context.config.type_punctuation_density() {
578                 TypeDensity::Compressed => "=",
579                 TypeDensity::Wide => " = ",
580             };
581             result.push_str(eq_str);
582             let budget = shape.width.checked_sub(result.len())?;
583             let rewrite = def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
584             result.push_str(&rewrite);
585         }
586
587         Some(result)
588     }
589 }
590
591 impl Rewrite for ast::PolyTraitRef {
592     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
593         if !self.bound_lifetimes.is_empty() {
594             let lifetime_str: String = self.bound_lifetimes
595                 .iter()
596                 .map(|lt| lt.rewrite(context, shape))
597                 .collect::<Option<Vec<_>>>()?
598                 .join(", ");
599
600             // 6 is "for<> ".len()
601             let extra_offset = lifetime_str.len() + 6;
602             let path_str = self.trait_ref
603                 .rewrite(context, shape.offset_left(extra_offset)?)?;
604
605             Some(
606                 if context.config.spaces_within_parens_and_brackets() && !lifetime_str.is_empty() {
607                     format!("for< {} > {}", lifetime_str, path_str)
608                 } else {
609                     format!("for<{}> {}", lifetime_str, path_str)
610                 },
611             )
612         } else {
613             self.trait_ref.rewrite(context, shape)
614         }
615     }
616 }
617
618 impl Rewrite for ast::TraitRef {
619     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
620         rewrite_path(context, PathContext::Type, None, &self.path, shape)
621     }
622 }
623
624 impl Rewrite for ast::Ty {
625     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
626         match self.node {
627             ast::TyKind::TraitObject(ref bounds, ..) => bounds.rewrite(context, shape),
628             ast::TyKind::Ptr(ref mt) => {
629                 let prefix = match mt.mutbl {
630                     Mutability::Mutable => "*mut ",
631                     Mutability::Immutable => "*const ",
632                 };
633
634                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
635             }
636             ast::TyKind::Rptr(ref lifetime, ref mt) => {
637                 let mut_str = format_mutability(mt.mutbl);
638                 let mut_len = mut_str.len();
639                 Some(match *lifetime {
640                     Some(ref lifetime) => {
641                         let lt_budget = shape.width.checked_sub(2 + mut_len)?;
642                         let lt_str = lifetime.rewrite(
643                             context,
644                             Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
645                         )?;
646                         let lt_len = lt_str.len();
647                         let budget = shape.width.checked_sub(2 + mut_len + lt_len)?;
648                         format!(
649                             "&{} {}{}",
650                             lt_str,
651                             mut_str,
652                             mt.ty.rewrite(
653                                 context,
654                                 Shape::legacy(budget, shape.indent + 2 + mut_len + lt_len)
655                             )?
656                         )
657                     }
658                     None => {
659                         let budget = shape.width.checked_sub(1 + mut_len)?;
660                         format!(
661                             "&{}{}",
662                             mut_str,
663                             mt.ty.rewrite(
664                                 context,
665                                 Shape::legacy(budget, shape.indent + 1 + mut_len)
666                             )?
667                         )
668                     }
669                 })
670             }
671             // FIXME: we drop any comments here, even though it's a silly place to put
672             // comments.
673             ast::TyKind::Paren(ref ty) => {
674                 let budget = shape.width.checked_sub(2)?;
675                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
676                     .map(|ty_str| {
677                         if context.config.spaces_within_parens_and_brackets() {
678                             format!("( {} )", ty_str)
679                         } else {
680                             format!("({})", ty_str)
681                         }
682                     })
683             }
684             ast::TyKind::Slice(ref ty) => {
685                 let budget = if context.config.spaces_within_parens_and_brackets() {
686                     shape.width.checked_sub(4)?
687                 } else {
688                     shape.width.checked_sub(2)?
689                 };
690                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
691                     .map(|ty_str| {
692                         if context.config.spaces_within_parens_and_brackets() {
693                             format!("[ {} ]", ty_str)
694                         } else {
695                             format!("[{}]", ty_str)
696                         }
697                     })
698             }
699             ast::TyKind::Tup(ref items) => rewrite_tuple(
700                 context,
701                 &::utils::ptr_vec_to_ref_vec(items),
702                 self.span,
703                 shape,
704             ),
705             ast::TyKind::Path(ref q_self, ref path) => {
706                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
707             }
708             ast::TyKind::Array(ref ty, ref repeats) => {
709                 let use_spaces = context.config.spaces_within_parens_and_brackets();
710                 let lbr = if use_spaces { "[ " } else { "[" };
711                 let rbr = if use_spaces { " ]" } else { "]" };
712                 rewrite_pair(
713                     &**ty,
714                     &**repeats,
715                     PairParts::new(lbr, "; ", rbr),
716                     context,
717                     shape,
718                     SeparatorPlace::Back,
719                 )
720             }
721             ast::TyKind::Infer => {
722                 if shape.width >= 1 {
723                     Some("_".to_owned())
724                 } else {
725                     None
726                 }
727             }
728             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
729             ast::TyKind::Never => Some(String::from("!")),
730             ast::TyKind::Mac(ref mac) => {
731                 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
732             }
733             ast::TyKind::ImplicitSelf => Some(String::from("")),
734             ast::TyKind::ImplTrait(ref it) => it.rewrite(context, shape)
735                 .map(|it_str| format!("impl {}", it_str)),
736             ast::TyKind::Err | ast::TyKind::Typeof(..) => unreachable!(),
737         }
738     }
739 }
740
741 fn rewrite_bare_fn(
742     bare_fn: &ast::BareFnTy,
743     span: Span,
744     context: &RewriteContext,
745     shape: Shape,
746 ) -> Option<String> {
747     let mut result = String::with_capacity(128);
748
749     if !bare_fn.lifetimes.is_empty() {
750         result.push_str("for<");
751         // 6 = "for<> ".len(), 4 = "for<".
752         // This doesn't work out so nicely for mutliline situation with lots of
753         // rightward drift. If that is a problem, we could use the list stuff.
754         result.push_str(&bare_fn
755             .lifetimes
756             .iter()
757             .map(|l| {
758                 l.rewrite(
759                     context,
760                     Shape::legacy(shape.width.checked_sub(6)?, shape.indent + 4),
761                 )
762             })
763             .collect::<Option<Vec<_>>>()?
764             .join(", "));
765         result.push_str("> ");
766     }
767
768     result.push_str(::utils::format_unsafety(bare_fn.unsafety));
769
770     result.push_str(&format_abi(
771         bare_fn.abi,
772         context.config.force_explicit_abi(),
773         false,
774     ));
775
776     result.push_str("fn");
777
778     let func_ty_shape = shape.offset_left(result.len())?;
779
780     let rewrite = format_function_type(
781         bare_fn.decl.inputs.iter(),
782         &bare_fn.decl.output,
783         bare_fn.decl.variadic,
784         span,
785         context,
786         func_ty_shape,
787     )?;
788
789     result.push_str(&rewrite);
790
791     Some(result)
792 }
793
794 pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &[String]) -> String {
795     // Try to join types in a single line
796     let joiner = match context.config.type_punctuation_density() {
797         TypeDensity::Compressed => "+",
798         TypeDensity::Wide => " + ",
799     };
800     let result = type_strs.join(joiner);
801     if result.contains('\n') || result.len() > shape.width {
802         let joiner_indent = shape.indent.block_indent(context.config);
803         let joiner = format!("\n{}+ ", joiner_indent.to_string(context.config));
804         type_strs.join(&joiner)
805     } else {
806         result
807     }
808 }
809
810 pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {
811     match ty.node {
812         ast::TyKind::Path(..) | ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
813         ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
814             can_be_overflowed_type(context, &*mutty.ty, len)
815         }
816         _ => false,
817     }
818 }