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