]> git.lizzy.rs Git - rust.git/blob - src/types.rs
Fixes compilation with rust version 2017-12-21
[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_generic_params,
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_generic_params.iter().filter(|p| p.is_lifetime_param()).count() > 0 {
426                     let lifetime_str: String = bound_generic_params
427                         .iter()
428                         .filter_map(|p| match p {
429                             &ast::GenericParam::Lifetime(ref l) => Some(l),
430                             _ => None,
431                         })
432                         .map(|lt| lt.rewrite(context, shape))
433                         .collect::<Option<Vec<_>>>()?
434                         .join(", ");
435
436                     // 6 = "for<> ".len()
437                     let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6;
438                     let ty_shape = shape.offset_left(used_width)?;
439                     let bounds = bounds
440                         .iter()
441                         .map(|ty_bound| ty_bound.rewrite(context, ty_shape))
442                         .collect::<Option<Vec<_>>>()?;
443                     let bounds_str = join_bounds(context, ty_shape, &bounds);
444
445                     if context.config.spaces_within_parens_and_brackets()
446                         && !lifetime_str.is_empty()
447                     {
448                         format!(
449                             "for< {} > {}{}{}",
450                             lifetime_str, type_str, colon, bounds_str
451                         )
452                     } else {
453                         format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)
454                     }
455                 } else {
456                     let used_width = type_str.len() + colon.len();
457                     let ty_shape = match context.config.indent_style() {
458                         IndentStyle::Visual => shape.block_left(used_width)?,
459                         IndentStyle::Block => shape,
460                     };
461                     let bounds = bounds
462                         .iter()
463                         .map(|ty_bound| ty_bound.rewrite(context, ty_shape))
464                         .collect::<Option<Vec<_>>>()?;
465                     let overhead = type_str.len() + colon.len();
466                     let bounds_str = join_bounds(context, ty_shape.sub_width(overhead)?, &bounds);
467
468                     format!("{}{}{}", type_str, colon, bounds_str)
469                 }
470             }
471             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
472                 ref lifetime,
473                 ref bounds,
474                 ..
475             }) => rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape)?,
476             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
477                 ref lhs_ty,
478                 ref rhs_ty,
479                 ..
480             }) => {
481                 let lhs_ty_str = lhs_ty.rewrite(context, shape)?;
482                 // 3 = " = ".len()
483                 let used_width = 3 + lhs_ty_str.len();
484                 let budget = shape.width.checked_sub(used_width)?;
485                 let rhs_ty_str =
486                     rhs_ty.rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
487                 format!("{} = {}", lhs_ty_str, rhs_ty_str)
488             }
489         };
490
491         Some(result)
492     }
493 }
494
495 impl Rewrite for ast::LifetimeDef {
496     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
497         rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape)
498     }
499 }
500
501 fn rewrite_bounded_lifetime<'b, I>(
502     lt: &ast::Lifetime,
503     bounds: I,
504     context: &RewriteContext,
505     shape: Shape,
506 ) -> Option<String>
507 where
508     I: ExactSizeIterator<Item = &'b ast::Lifetime>,
509 {
510     let result = lt.rewrite(context, shape)?;
511
512     if bounds.len() == 0 {
513         Some(result)
514     } else {
515         let appendix = bounds
516             .into_iter()
517             .map(|b| b.rewrite(context, shape))
518             .collect::<Option<Vec<_>>>()?;
519         let colon = type_bound_colon(context);
520         let overhead = last_line_width(&result) + colon.len();
521         let result = format!(
522             "{}{}{}",
523             result,
524             colon,
525             join_bounds(context, shape.sub_width(overhead)?, &appendix)
526         );
527         Some(result)
528     }
529 }
530
531 impl Rewrite for ast::TyParamBound {
532     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
533         match *self {
534             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
535                 tref.rewrite(context, shape)
536             }
537             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
538                 Some(format!(
539                     "?{}",
540                     tref.rewrite(context, shape.offset_left(1)?)?
541                 ))
542             }
543             ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
544         }
545     }
546 }
547
548 impl Rewrite for ast::Lifetime {
549     fn rewrite(&self, _: &RewriteContext, _: Shape) -> Option<String> {
550         Some(pprust::lifetime_to_string(self))
551     }
552 }
553
554 impl Rewrite for ast::TyParamBounds {
555     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
556         let strs = self.iter()
557             .map(|b| b.rewrite(context, shape))
558             .collect::<Option<Vec<_>>>()?;
559         Some(join_bounds(context, shape, &strs))
560     }
561 }
562
563 impl Rewrite for ast::TyParam {
564     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
565         let mut result = String::with_capacity(128);
566         // FIXME: If there are more than one attributes, this will force multiline.
567         match self.attrs.rewrite(context, shape) {
568             Some(ref rw) if !rw.is_empty() => result.push_str(&format!("{} ", rw)),
569             _ => (),
570         }
571         result.push_str(&self.ident.to_string());
572         if !self.bounds.is_empty() {
573             result.push_str(type_bound_colon(context));
574             let strs = self.bounds
575                 .iter()
576                 .map(|ty_bound| ty_bound.rewrite(context, shape))
577                 .collect::<Option<Vec<_>>>()?;
578             result.push_str(&join_bounds(context, shape, &strs));
579         }
580         if let Some(ref def) = self.default {
581             let eq_str = match context.config.type_punctuation_density() {
582                 TypeDensity::Compressed => "=",
583                 TypeDensity::Wide => " = ",
584             };
585             result.push_str(eq_str);
586             let budget = shape.width.checked_sub(result.len())?;
587             let rewrite = def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
588             result.push_str(&rewrite);
589         }
590
591         Some(result)
592     }
593 }
594
595 impl Rewrite for ast::PolyTraitRef {
596     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
597         if self.bound_generic_params.iter().filter(|p| p.is_lifetime_param()).count() > 0 {
598             let lifetime_str: String = self.bound_generic_params
599                 .iter()
600                 .filter_map(|p| match p {
601                     &ast::GenericParam::Lifetime(ref l) => Some(l),
602                     _ => None,
603                 })
604                 .map(|lt| lt.rewrite(context, shape))
605                 .collect::<Option<Vec<_>>>()?
606                 .join(", ");
607
608             // 6 is "for<> ".len()
609             let extra_offset = lifetime_str.len() + 6;
610             let path_str = self.trait_ref
611                 .rewrite(context, shape.offset_left(extra_offset)?)?;
612
613             Some(
614                 if context.config.spaces_within_parens_and_brackets() && !lifetime_str.is_empty() {
615                     format!("for< {} > {}", lifetime_str, path_str)
616                 } else {
617                     format!("for<{}> {}", lifetime_str, path_str)
618                 },
619             )
620         } else {
621             self.trait_ref.rewrite(context, shape)
622         }
623     }
624 }
625
626 impl Rewrite for ast::TraitRef {
627     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
628         rewrite_path(context, PathContext::Type, None, &self.path, shape)
629     }
630 }
631
632 impl Rewrite for ast::Ty {
633     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
634         match self.node {
635             ast::TyKind::TraitObject(ref bounds, ..) => bounds.rewrite(context, shape),
636             ast::TyKind::Ptr(ref mt) => {
637                 let prefix = match mt.mutbl {
638                     Mutability::Mutable => "*mut ",
639                     Mutability::Immutable => "*const ",
640                 };
641
642                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
643             }
644             ast::TyKind::Rptr(ref lifetime, ref mt) => {
645                 let mut_str = format_mutability(mt.mutbl);
646                 let mut_len = mut_str.len();
647                 Some(match *lifetime {
648                     Some(ref lifetime) => {
649                         let lt_budget = shape.width.checked_sub(2 + mut_len)?;
650                         let lt_str = lifetime.rewrite(
651                             context,
652                             Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
653                         )?;
654                         let lt_len = lt_str.len();
655                         let budget = shape.width.checked_sub(2 + mut_len + lt_len)?;
656                         format!(
657                             "&{} {}{}",
658                             lt_str,
659                             mut_str,
660                             mt.ty.rewrite(
661                                 context,
662                                 Shape::legacy(budget, shape.indent + 2 + mut_len + lt_len)
663                             )?
664                         )
665                     }
666                     None => {
667                         let budget = shape.width.checked_sub(1 + mut_len)?;
668                         format!(
669                             "&{}{}",
670                             mut_str,
671                             mt.ty.rewrite(
672                                 context,
673                                 Shape::legacy(budget, shape.indent + 1 + mut_len)
674                             )?
675                         )
676                     }
677                 })
678             }
679             // FIXME: we drop any comments here, even though it's a silly place to put
680             // comments.
681             ast::TyKind::Paren(ref ty) => {
682                 let budget = shape.width.checked_sub(2)?;
683                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
684                     .map(|ty_str| {
685                         if context.config.spaces_within_parens_and_brackets() {
686                             format!("( {} )", ty_str)
687                         } else {
688                             format!("({})", ty_str)
689                         }
690                     })
691             }
692             ast::TyKind::Slice(ref ty) => {
693                 let budget = if context.config.spaces_within_parens_and_brackets() {
694                     shape.width.checked_sub(4)?
695                 } else {
696                     shape.width.checked_sub(2)?
697                 };
698                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
699                     .map(|ty_str| {
700                         if context.config.spaces_within_parens_and_brackets() {
701                             format!("[ {} ]", ty_str)
702                         } else {
703                             format!("[{}]", ty_str)
704                         }
705                     })
706             }
707             ast::TyKind::Tup(ref items) => rewrite_tuple(
708                 context,
709                 &::utils::ptr_vec_to_ref_vec(items),
710                 self.span,
711                 shape,
712             ),
713             ast::TyKind::Path(ref q_self, ref path) => {
714                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
715             }
716             ast::TyKind::Array(ref ty, ref repeats) => {
717                 let use_spaces = context.config.spaces_within_parens_and_brackets();
718                 let lbr = if use_spaces { "[ " } else { "[" };
719                 let rbr = if use_spaces { " ]" } else { "]" };
720                 rewrite_pair(
721                     &**ty,
722                     &**repeats,
723                     PairParts::new(lbr, "; ", rbr),
724                     context,
725                     shape,
726                     SeparatorPlace::Back,
727                 )
728             }
729             ast::TyKind::Infer => {
730                 if shape.width >= 1 {
731                     Some("_".to_owned())
732                 } else {
733                     None
734                 }
735             }
736             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
737             ast::TyKind::Never => Some(String::from("!")),
738             ast::TyKind::Mac(ref mac) => {
739                 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
740             }
741             ast::TyKind::ImplicitSelf => Some(String::from("")),
742             ast::TyKind::ImplTrait(ref it) => it.rewrite(context, shape)
743                 .map(|it_str| format!("impl {}", it_str)),
744             ast::TyKind::Err | ast::TyKind::Typeof(..) => unreachable!(),
745         }
746     }
747 }
748
749 fn rewrite_bare_fn(
750     bare_fn: &ast::BareFnTy,
751     span: Span,
752     context: &RewriteContext,
753     shape: Shape,
754 ) -> Option<String> {
755     let mut result = String::with_capacity(128);
756
757     if bare_fn.generic_params.iter().filter(|p| p.is_lifetime_param()).count() > 0 {
758         result.push_str("for<");
759         // 6 = "for<> ".len(), 4 = "for<".
760         // This doesn't work out so nicely for mutliline situation with lots of
761         // rightward drift. If that is a problem, we could use the list stuff.
762         result.push_str(&bare_fn
763             .generic_params
764             .iter()
765             .filter_map(|p| match p {
766                 &ast::GenericParam::Lifetime(ref l) => Some(l),
767                 _ => None,
768             })
769             .map(|l| {
770                 l.rewrite(
771                     context,
772                     Shape::legacy(shape.width.checked_sub(6)?, shape.indent + 4),
773                 )
774             })
775             .collect::<Option<Vec<_>>>()?
776             .join(", "));
777         result.push_str("> ");
778     }
779
780     result.push_str(::utils::format_unsafety(bare_fn.unsafety));
781
782     result.push_str(&format_abi(
783         bare_fn.abi,
784         context.config.force_explicit_abi(),
785         false,
786     ));
787
788     result.push_str("fn");
789
790     let func_ty_shape = shape.offset_left(result.len())?;
791
792     let rewrite = format_function_type(
793         bare_fn.decl.inputs.iter(),
794         &bare_fn.decl.output,
795         bare_fn.decl.variadic,
796         span,
797         context,
798         func_ty_shape,
799     )?;
800
801     result.push_str(&rewrite);
802
803     Some(result)
804 }
805
806 pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &[String]) -> String {
807     // Try to join types in a single line
808     let joiner = match context.config.type_punctuation_density() {
809         TypeDensity::Compressed => "+",
810         TypeDensity::Wide => " + ",
811     };
812     let result = type_strs.join(joiner);
813     if result.contains('\n') || result.len() > shape.width {
814         let joiner_indent = shape.indent.block_indent(context.config);
815         let joiner = format!("\n{}+ ", joiner_indent.to_string(context.config));
816         type_strs.join(&joiner)
817     } else {
818         result
819     }
820 }
821
822 pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {
823     match ty.node {
824         ast::TyKind::Path(..) | ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
825         ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
826             can_be_overflowed_type(context, &*mutty.ty, len)
827         }
828         _ => false,
829     }
830 }