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