]> git.lizzy.rs Git - rust.git/blob - src/types.rs
Preserve trailing comma inside array
[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 config::lists::*;
15 use syntax::ast::{self, FunctionRetTy, Mutability};
16 use syntax::codemap::{self, BytePos, Span};
17 use syntax::symbol::keywords;
18
19 use codemap::SpanUtils;
20 use config::{IndentStyle, TypeDensity};
21 use expr::{rewrite_assign_rhs, rewrite_pair, rewrite_tuple, rewrite_unary_prefix, PairParts,
22            ToExpr};
23 use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
24 use macros::{rewrite_macro, MacroPosition};
25 use overflow;
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.ident.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> Spanned for SegmentParam<'a> {
156     fn span(&self) -> Span {
157         match *self {
158             SegmentParam::LifeTime(lt) => lt.ident.span,
159             SegmentParam::Type(ty) => ty.span,
160             SegmentParam::Binding(binding) => binding.span,
161         }
162     }
163 }
164
165 impl<'a> ToExpr for SegmentParam<'a> {
166     fn to_expr(&self) -> Option<&ast::Expr> {
167         None
168     }
169
170     fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
171         match *self {
172             SegmentParam::Type(ty) => ty.can_be_overflowed(context, len),
173             _ => false,
174         }
175     }
176 }
177
178 impl<'a> Rewrite for SegmentParam<'a> {
179     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
180         match *self {
181             SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
182             SegmentParam::Type(ty) => ty.rewrite(context, shape),
183             SegmentParam::Binding(binding) => {
184                 let mut result = match context.config.type_punctuation_density() {
185                     TypeDensity::Wide => format!("{} = ", binding.ident),
186                     TypeDensity::Compressed => format!("{}=", binding.ident),
187                 };
188                 let budget = shape.width.checked_sub(result.len())?;
189                 let rewrite = binding
190                     .ty
191                     .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
192                 result.push_str(&rewrite);
193                 Some(result)
194             }
195         }
196     }
197 }
198
199 // Formats a path segment. There are some hacks involved to correctly determine
200 // the segment's associated span since it's not part of the AST.
201 //
202 // The span_lo is assumed to be greater than the end of any previous segment's
203 // parameters and lesser or equal than the start of current segment.
204 //
205 // span_hi is assumed equal to the end of the entire path.
206 //
207 // When the segment contains a positive number of parameters, we update span_lo
208 // so that invariants described above will hold for the next segment.
209 fn rewrite_segment(
210     path_context: PathContext,
211     segment: &ast::PathSegment,
212     span_lo: &mut BytePos,
213     span_hi: BytePos,
214     context: &RewriteContext,
215     shape: Shape,
216 ) -> Option<String> {
217     let mut result = String::with_capacity(128);
218     result.push_str(&segment.ident.name.as_str());
219
220     let ident_len = result.len();
221     let shape = if context.use_block_indent() {
222         shape.offset_left(ident_len)?
223     } else {
224         shape.shrink_left(ident_len)?
225     };
226
227     if let Some(ref params) = segment.parameters {
228         match **params {
229             ast::PathParameters::AngleBracketed(ref data)
230                 if !data.lifetimes.is_empty() || !data.types.is_empty()
231                     || !data.bindings.is_empty() =>
232             {
233                 let param_list = data.lifetimes
234                     .iter()
235                     .map(SegmentParam::LifeTime)
236                     .chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
237                     .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
238                     .collect::<Vec<_>>();
239
240                 let separator = if path_context == PathContext::Expr {
241                     "::"
242                 } else {
243                     ""
244                 };
245                 result.push_str(separator);
246
247                 let generics_str = overflow::rewrite_with_angle_brackets(
248                     context,
249                     "",
250                     &param_list.iter().map(|e| &*e).collect::<Vec<_>>(),
251                     shape,
252                     mk_sp(*span_lo, span_hi),
253                 )?;
254
255                 // Update position of last bracket.
256                 *span_lo = context
257                     .snippet_provider
258                     .span_after(mk_sp(*span_lo, span_hi), "<");
259
260                 result.push_str(&generics_str)
261             }
262             ast::PathParameters::Parenthesized(ref data) => {
263                 let output = match data.output {
264                     Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
265                     None => FunctionRetTy::Default(codemap::DUMMY_SP),
266                 };
267                 result.push_str(&format_function_type(
268                     data.inputs.iter().map(|x| &**x),
269                     &output,
270                     false,
271                     data.span,
272                     context,
273                     shape,
274                 )?);
275             }
276             _ => (),
277         }
278     }
279
280     Some(result)
281 }
282
283 fn format_function_type<'a, I>(
284     inputs: I,
285     output: &FunctionRetTy,
286     variadic: bool,
287     span: Span,
288     context: &RewriteContext,
289     shape: Shape,
290 ) -> Option<String>
291 where
292     I: ExactSizeIterator,
293     <I as Iterator>::Item: Deref,
294     <I::Item as Deref>::Target: Rewrite + Spanned + 'a,
295 {
296     // Code for handling variadics is somewhat duplicated for items, but they
297     // are different enough to need some serious refactoring to share code.
298     enum ArgumentKind<T>
299     where
300         T: Deref,
301         <T as Deref>::Target: Rewrite + Spanned,
302     {
303         Regular(Box<T>),
304         Variadic(BytePos),
305     }
306
307     let variadic_arg = if variadic {
308         let variadic_start = context.snippet_provider.span_before(span, "...");
309         Some(ArgumentKind::Variadic(variadic_start))
310     } else {
311         None
312     };
313
314     // 2 for ()
315     let budget = shape.width.checked_sub(2)?;
316     // 1 for (
317     let offset = match context.config.indent_style() {
318         IndentStyle::Block => {
319             shape
320                 .block()
321                 .block_indent(context.config.tab_spaces())
322                 .indent
323         }
324         IndentStyle::Visual => shape.indent + 1,
325     };
326     let list_shape = Shape::legacy(budget, offset);
327     let list_lo = context.snippet_provider.span_after(span, "(");
328     let items = itemize_list(
329         context.snippet_provider,
330         // FIXME Would be nice to avoid this allocation,
331         // but I couldn't get the types to work out.
332         inputs
333             .map(|i| ArgumentKind::Regular(Box::new(i)))
334             .chain(variadic_arg),
335         ")",
336         ",",
337         |arg| match *arg {
338             ArgumentKind::Regular(ref ty) => ty.span().lo(),
339             ArgumentKind::Variadic(start) => start,
340         },
341         |arg| match *arg {
342             ArgumentKind::Regular(ref ty) => ty.span().hi(),
343             ArgumentKind::Variadic(start) => start + BytePos(3),
344         },
345         |arg| match *arg {
346             ArgumentKind::Regular(ref ty) => ty.rewrite(context, list_shape),
347             ArgumentKind::Variadic(_) => Some("...".to_owned()),
348         },
349         list_lo,
350         span.hi(),
351         false,
352     );
353
354     let item_vec: Vec<_> = items.collect();
355
356     let tactic = definitive_tactic(
357         &*item_vec,
358         ListTactic::HorizontalVertical,
359         Separator::Comma,
360         budget,
361     );
362
363     let fmt = ListFormatting {
364         tactic,
365         separator: ",",
366         trailing_separator: if !context.use_block_indent() || variadic {
367             SeparatorTactic::Never
368         } else {
369             context.config.trailing_comma()
370         },
371         separator_place: SeparatorPlace::Back,
372         shape: list_shape,
373         ends_with_newline: tactic.ends_with_newline(context.config.indent_style()),
374         preserve_newline: true,
375         config: context.config,
376     };
377
378     let list_str = write_list(&item_vec, &fmt)?;
379
380     let ty_shape = match context.config.indent_style() {
381         // 4 = " -> "
382         IndentStyle::Block => shape.offset_left(4)?,
383         IndentStyle::Visual => shape.block_left(4)?,
384     };
385     let output = match *output {
386         FunctionRetTy::Ty(ref ty) => {
387             let type_str = ty.rewrite(context, ty_shape)?;
388             format!(" -> {}", type_str)
389         }
390         FunctionRetTy::Default(..) => String::new(),
391     };
392
393     let args = if (!list_str.contains('\n') || list_str.is_empty()) && !output.contains('\n')
394         || !context.use_block_indent()
395     {
396         format!("({})", list_str)
397     } else {
398         format!(
399             "({}{}{})",
400             offset.to_string_with_newline(context.config),
401             list_str,
402             shape.block().indent.to_string_with_newline(context.config),
403         )
404     };
405     if last_line_width(&args) + first_line_width(&output) <= shape.width {
406         Some(format!("{}{}", args, output))
407     } else {
408         Some(format!(
409             "{}\n{}{}",
410             args,
411             offset.to_string(context.config),
412             output.trim_left()
413         ))
414     }
415 }
416
417 fn type_bound_colon(context: &RewriteContext) -> &'static str {
418     colon_spaces(
419         context.config.space_before_colon(),
420         context.config.space_after_colon(),
421     )
422 }
423
424 impl Rewrite for ast::WherePredicate {
425     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
426         // TODO: dead spans?
427         let result = match *self {
428             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
429                 ref bound_generic_params,
430                 ref bounded_ty,
431                 ref bounds,
432                 ..
433             }) => {
434                 let type_str = bounded_ty.rewrite(context, shape)?;
435                 let colon = type_bound_colon(context).trim_right();
436                 let lhs = if let Some(lifetime_str) =
437                     rewrite_lifetime_param(context, shape, bound_generic_params)
438                 {
439                     if context.config.spaces_within_parens_and_brackets()
440                         && !lifetime_str.is_empty()
441                     {
442                         format!("for< {} > {}{}", lifetime_str, type_str, colon)
443                     } else {
444                         format!("for<{}> {}{}", lifetime_str, type_str, colon)
445                     }
446                 } else {
447                     format!("{}{}", type_str, colon)
448                 };
449
450                 rewrite_assign_rhs(context, lhs, bounds, shape)?
451             }
452             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
453                 ref lifetime,
454                 ref bounds,
455                 ..
456             }) => rewrite_bounded_lifetime(lifetime, bounds, context, shape)?,
457             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
458                 ref lhs_ty,
459                 ref rhs_ty,
460                 ..
461             }) => {
462                 let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
463                 rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
464             }
465         };
466
467         Some(result)
468     }
469 }
470
471 impl Rewrite for ast::LifetimeDef {
472     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
473         rewrite_bounded_lifetime(&self.lifetime, &self.bounds, context, shape)
474     }
475 }
476
477 fn rewrite_bounded_lifetime(
478     lt: &ast::Lifetime,
479     bounds: &[ast::Lifetime],
480     context: &RewriteContext,
481     shape: Shape,
482 ) -> Option<String> {
483     let result = lt.rewrite(context, shape)?;
484
485     if bounds.is_empty() {
486         Some(result)
487     } else {
488         let colon = type_bound_colon(context);
489         let overhead = last_line_width(&result) + colon.len();
490         let result = format!(
491             "{}{}{}",
492             result,
493             colon,
494             join_bounds(context, shape.sub_width(overhead)?, bounds, true)?
495         );
496         Some(result)
497     }
498 }
499
500 impl Rewrite for ast::TyParamBound {
501     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
502         match *self {
503             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
504                 tref.rewrite(context, shape)
505             }
506             ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => Some(
507                 format!("?{}", tref.rewrite(context, shape.offset_left(1)?)?),
508             ),
509             ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
510         }
511     }
512 }
513
514 impl Rewrite for ast::Lifetime {
515     fn rewrite(&self, _: &RewriteContext, _: Shape) -> Option<String> {
516         Some(self.ident.to_string())
517     }
518 }
519
520 /// A simple wrapper over type param bounds in trait.
521 #[derive(new)]
522 pub struct TraitTyParamBounds<'a> {
523     inner: &'a ast::TyParamBounds,
524 }
525
526 impl<'a> Rewrite for TraitTyParamBounds<'a> {
527     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
528         join_bounds(context, shape, self.inner, false)
529     }
530 }
531
532 impl Rewrite for ast::TyParamBounds {
533     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
534         join_bounds(context, shape, self, true)
535     }
536 }
537
538 impl Rewrite for ast::TyParam {
539     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
540         let mut result = String::with_capacity(128);
541         // FIXME: If there are more than one attributes, this will force multiline.
542         match self.attrs.rewrite(context, shape) {
543             Some(ref rw) if !rw.is_empty() => result.push_str(&format!("{} ", rw)),
544             _ => (),
545         }
546         result.push_str(&self.ident.to_string());
547         if !self.bounds.is_empty() {
548             result.push_str(type_bound_colon(context));
549             result.push_str(&self.bounds.rewrite(context, shape)?)
550         }
551         if let Some(ref def) = self.default {
552             let eq_str = match context.config.type_punctuation_density() {
553                 TypeDensity::Compressed => "=",
554                 TypeDensity::Wide => " = ",
555             };
556             result.push_str(eq_str);
557             let budget = shape.width.checked_sub(result.len())?;
558             let rewrite = def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
559             result.push_str(&rewrite);
560         }
561
562         Some(result)
563     }
564 }
565
566 impl Rewrite for ast::PolyTraitRef {
567     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
568         if let Some(lifetime_str) =
569             rewrite_lifetime_param(context, shape, &self.bound_generic_params)
570         {
571             // 6 is "for<> ".len()
572             let extra_offset = lifetime_str.len() + 6;
573             let path_str = self.trait_ref
574                 .rewrite(context, shape.offset_left(extra_offset)?)?;
575
576             Some(
577                 if context.config.spaces_within_parens_and_brackets() && !lifetime_str.is_empty() {
578                     format!("for< {} > {}", lifetime_str, path_str)
579                 } else {
580                     format!("for<{}> {}", lifetime_str, path_str)
581                 },
582             )
583         } else {
584             self.trait_ref.rewrite(context, shape)
585         }
586     }
587 }
588
589 impl Rewrite for ast::TraitRef {
590     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
591         rewrite_path(context, PathContext::Type, None, &self.path, shape)
592     }
593 }
594
595 impl Rewrite for ast::Ty {
596     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
597         match self.node {
598             ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
599                 // we have to consider 'dyn' keyword is used or not!!!
600                 let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
601                 // 4 is length of 'dyn '
602                 let shape = if is_dyn { shape.offset_left(4)? } else { shape };
603                 let res = bounds.rewrite(context, shape)?;
604                 if is_dyn {
605                     Some(format!("dyn {}", res))
606                 } else {
607                     Some(res)
608                 }
609             }
610             ast::TyKind::Ptr(ref mt) => {
611                 let prefix = match mt.mutbl {
612                     Mutability::Mutable => "*mut ",
613                     Mutability::Immutable => "*const ",
614                 };
615
616                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
617             }
618             ast::TyKind::Rptr(ref lifetime, ref mt) => {
619                 let mut_str = format_mutability(mt.mutbl);
620                 let mut_len = mut_str.len();
621                 Some(match *lifetime {
622                     Some(ref lifetime) => {
623                         let lt_budget = shape.width.checked_sub(2 + mut_len)?;
624                         let lt_str = lifetime.rewrite(
625                             context,
626                             Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
627                         )?;
628                         let lt_len = lt_str.len();
629                         let budget = shape.width.checked_sub(2 + mut_len + lt_len)?;
630                         format!(
631                             "&{} {}{}",
632                             lt_str,
633                             mut_str,
634                             mt.ty.rewrite(
635                                 context,
636                                 Shape::legacy(budget, shape.indent + 2 + mut_len + lt_len)
637                             )?
638                         )
639                     }
640                     None => {
641                         let budget = shape.width.checked_sub(1 + mut_len)?;
642                         format!(
643                             "&{}{}",
644                             mut_str,
645                             mt.ty.rewrite(
646                                 context,
647                                 Shape::legacy(budget, shape.indent + 1 + mut_len)
648                             )?
649                         )
650                     }
651                 })
652             }
653             // FIXME: we drop any comments here, even though it's a silly place to put
654             // comments.
655             ast::TyKind::Paren(ref ty) => {
656                 let budget = shape.width.checked_sub(2)?;
657                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
658                     .map(|ty_str| {
659                         if context.config.spaces_within_parens_and_brackets() {
660                             format!("( {} )", ty_str)
661                         } else {
662                             format!("({})", ty_str)
663                         }
664                     })
665             }
666             ast::TyKind::Slice(ref ty) => {
667                 let budget = if context.config.spaces_within_parens_and_brackets() {
668                     shape.width.checked_sub(4)?
669                 } else {
670                     shape.width.checked_sub(2)?
671                 };
672                 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
673                     .map(|ty_str| {
674                         if context.config.spaces_within_parens_and_brackets() {
675                             format!("[ {} ]", ty_str)
676                         } else {
677                             format!("[{}]", ty_str)
678                         }
679                     })
680             }
681             ast::TyKind::Tup(ref items) => rewrite_tuple(
682                 context,
683                 &::utils::ptr_vec_to_ref_vec(items),
684                 self.span,
685                 shape,
686             ),
687             ast::TyKind::Path(ref q_self, ref path) => {
688                 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
689             }
690             ast::TyKind::Array(ref ty, ref repeats) => {
691                 let use_spaces = context.config.spaces_within_parens_and_brackets();
692                 let lbr = if use_spaces { "[ " } else { "[" };
693                 let rbr = if use_spaces { " ]" } else { "]" };
694                 rewrite_pair(
695                     &**ty,
696                     &**repeats,
697                     PairParts::new(lbr, "; ", rbr),
698                     context,
699                     shape,
700                     SeparatorPlace::Back,
701                 )
702             }
703             ast::TyKind::Infer => {
704                 if shape.width >= 1 {
705                     Some("_".to_owned())
706                 } else {
707                     None
708                 }
709             }
710             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
711             ast::TyKind::Never => Some(String::from("!")),
712             ast::TyKind::Mac(ref mac) => {
713                 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
714             }
715             ast::TyKind::ImplicitSelf => Some(String::from("")),
716             ast::TyKind::ImplTrait(ref it) => it.rewrite(context, shape)
717                 .map(|it_str| format!("impl {}", it_str)),
718             ast::TyKind::Err | ast::TyKind::Typeof(..) => unreachable!(),
719         }
720     }
721 }
722
723 fn rewrite_bare_fn(
724     bare_fn: &ast::BareFnTy,
725     span: Span,
726     context: &RewriteContext,
727     shape: Shape,
728 ) -> Option<String> {
729     let mut result = String::with_capacity(128);
730
731     if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
732     {
733         result.push_str("for<");
734         // 6 = "for<> ".len(), 4 = "for<".
735         // This doesn't work out so nicely for multiline situation with lots of
736         // rightward drift. If that is a problem, we could use the list stuff.
737         result.push_str(lifetime_str);
738         result.push_str("> ");
739     }
740
741     result.push_str(::utils::format_unsafety(bare_fn.unsafety));
742
743     result.push_str(&format_abi(
744         bare_fn.abi,
745         context.config.force_explicit_abi(),
746         false,
747     ));
748
749     result.push_str("fn");
750
751     let func_ty_shape = shape.offset_left(result.len())?;
752
753     let rewrite = format_function_type(
754         bare_fn.decl.inputs.iter(),
755         &bare_fn.decl.output,
756         bare_fn.decl.variadic,
757         span,
758         context,
759         func_ty_shape,
760     )?;
761
762     result.push_str(&rewrite);
763
764     Some(result)
765 }
766
767 fn join_bounds<T>(
768     context: &RewriteContext,
769     shape: Shape,
770     items: &[T],
771     need_indent: bool,
772 ) -> Option<String>
773 where
774     T: Rewrite,
775 {
776     // Try to join types in a single line
777     let joiner = match context.config.type_punctuation_density() {
778         TypeDensity::Compressed => "+",
779         TypeDensity::Wide => " + ",
780     };
781     let type_strs = items
782         .iter()
783         .map(|item| item.rewrite(context, shape))
784         .collect::<Option<Vec<_>>>()?;
785     let result = type_strs.join(joiner);
786     if items.len() == 1 || (!result.contains('\n') && result.len() <= shape.width) {
787         return Some(result);
788     }
789
790     // We need to use multiple lines.
791     let (type_strs, offset) = if need_indent {
792         // Rewrite with additional indentation.
793         let nested_shape = shape.block_indent(context.config.tab_spaces());
794         let type_strs = items
795             .iter()
796             .map(|item| item.rewrite(context, nested_shape))
797             .collect::<Option<Vec<_>>>()?;
798         (type_strs, nested_shape.indent)
799     } else {
800         (type_strs, shape.indent)
801     };
802
803     let joiner = format!("{}+ ", offset.to_string_with_newline(context.config));
804     Some(type_strs.join(&joiner))
805 }
806
807 pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {
808     match ty.node {
809         ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
810         ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
811             can_be_overflowed_type(context, &*mutty.ty, len)
812         }
813         _ => false,
814     }
815 }
816
817 /// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
818 fn rewrite_lifetime_param(
819     context: &RewriteContext,
820     shape: Shape,
821     generic_params: &[ast::GenericParam],
822 ) -> Option<String> {
823     let result = generic_params
824         .iter()
825         .filter(|p| p.is_lifetime_param())
826         .map(|lt| lt.rewrite(context, shape))
827         .collect::<Option<Vec<_>>>()?
828         .join(", ");
829     if result.is_empty() {
830         None
831     } else {
832         Some(result)
833     }
834 }