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