1 use std::iter::ExactSizeIterator;
4 use rustc_ast::ast::{self, AttrVec, FnRetTy, Mutability};
5 use rustc_span::{symbol::kw, symbol::Ident, BytePos, Pos, Span};
7 use crate::config::lists::*;
8 use crate::config::{IndentStyle, TypeDensity, Version};
10 format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
12 use crate::items::StructParts;
14 definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
16 use crate::macros::{rewrite_macro, MacroPosition};
18 use crate::pairs::{rewrite_pair, PairParts};
19 use crate::rewrite::{Rewrite, RewriteContext};
20 use crate::shape::Shape;
21 use crate::source_map::SpanUtils;
22 use crate::spanned::Spanned;
24 colon_spaces, extra_offset, first_line_width, format_extern, format_mutability,
25 last_line_extendable, last_line_width, mk_sp, rewrite_ident,
27 use crate::DEFAULT_VISIBILITY;
29 comment::{combine_strs_with_missing_comments, contains_comment},
30 items::format_struct_struct,
33 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
34 pub(crate) enum PathContext {
40 // Does not wrap on simple segments.
41 pub(crate) fn rewrite_path(
42 context: &RewriteContext<'_>,
43 path_context: PathContext,
44 qself: Option<&ast::QSelf>,
48 let skip_count = qself.map_or(0, |x| x.position);
50 let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import {
56 let mut span_lo = path.span.lo();
58 if let Some(qself) = qself {
61 let fmt_ty = qself.ty.rewrite(context, shape)?;
62 result.push_str(&fmt_ty);
65 result.push_str(" as ");
66 if path.is_global() && path_context != PathContext::Import {
67 result.push_str("::");
71 let shape = shape.sub_width(3)?;
73 result = rewrite_path_segments(
76 path.segments.iter().take(skip_count),
84 result.push_str(">::");
85 span_lo = qself.ty.span.hi() + BytePos(1);
88 rewrite_path_segments(
91 path.segments.iter().skip(skip_count),
99 fn rewrite_path_segments<'a, I>(
100 path_context: PathContext,
103 mut span_lo: BytePos,
105 context: &RewriteContext<'_>,
109 I: Iterator<Item = &'a ast::PathSegment>,
111 let mut first = true;
112 let shape = shape.visual_indent(0);
114 for segment in iter {
115 // Indicates a global path, shouldn't be rendered.
116 if segment.ident.name == kw::PathRoot {
122 buffer.push_str("::");
125 let extra_offset = extra_offset(&buffer, shape);
126 let new_shape = shape.shrink_left(extra_offset)?;
127 let segment_string = rewrite_segment(
136 buffer.push_str(&segment_string);
143 pub(crate) enum SegmentParam<'a> {
144 Const(&'a ast::AnonConst),
145 LifeTime(&'a ast::Lifetime),
147 Binding(&'a ast::AssocTyConstraint),
150 impl<'a> SegmentParam<'a> {
151 fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam<'_> {
153 ast::GenericArg::Lifetime(ref lt) => SegmentParam::LifeTime(lt),
154 ast::GenericArg::Type(ref ty) => SegmentParam::Type(ty),
155 ast::GenericArg::Const(const_) => SegmentParam::Const(const_),
160 impl<'a> Spanned for SegmentParam<'a> {
161 fn span(&self) -> Span {
163 SegmentParam::Const(const_) => const_.value.span,
164 SegmentParam::LifeTime(lt) => lt.ident.span,
165 SegmentParam::Type(ty) => ty.span,
166 SegmentParam::Binding(binding) => binding.span,
171 impl<'a> Rewrite for SegmentParam<'a> {
172 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
174 SegmentParam::Const(const_) => const_.rewrite(context, shape),
175 SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
176 SegmentParam::Type(ty) => ty.rewrite(context, shape),
177 SegmentParam::Binding(assoc_ty_constraint) => {
178 let mut result = match assoc_ty_constraint.kind {
179 ast::AssocTyConstraintKind::Bound { .. } => {
180 format!("{}: ", rewrite_ident(context, assoc_ty_constraint.ident))
182 ast::AssocTyConstraintKind::Equality { .. } => {
183 match context.config.type_punctuation_density() {
184 TypeDensity::Wide => {
185 format!("{} = ", rewrite_ident(context, assoc_ty_constraint.ident))
187 TypeDensity::Compressed => {
188 format!("{}=", rewrite_ident(context, assoc_ty_constraint.ident))
194 let budget = shape.width.checked_sub(result.len())?;
195 let rewrite = assoc_ty_constraint
197 .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
198 result.push_str(&rewrite);
205 impl Rewrite for ast::AssocTyConstraintKind {
206 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
208 ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
209 ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
214 // Formats a path segment. There are some hacks involved to correctly determine
215 // the segment's associated span since it's not part of the AST.
217 // The span_lo is assumed to be greater than the end of any previous segment's
218 // parameters and lesser or equal than the start of current segment.
220 // span_hi is assumed equal to the end of the entire path.
222 // When the segment contains a positive number of parameters, we update span_lo
223 // so that invariants described above will hold for the next segment.
225 path_context: PathContext,
226 segment: &ast::PathSegment,
227 span_lo: &mut BytePos,
229 context: &RewriteContext<'_>,
231 ) -> Option<String> {
232 let mut result = String::with_capacity(128);
233 result.push_str(rewrite_ident(context, segment.ident));
235 let ident_len = result.len();
236 let shape = if context.use_block_indent() {
237 shape.offset_left(ident_len)?
239 shape.shrink_left(ident_len)?
242 if let Some(ref args) = segment.args {
244 ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
245 let param_list = data
249 ast::AngleBracketedArg::Arg(generic_arg) => {
250 SegmentParam::from_generic_arg(generic_arg)
252 ast::AngleBracketedArg::Constraint(constraint) => {
253 SegmentParam::Binding(constraint)
256 .collect::<Vec<_>>();
258 // HACK: squeeze out the span between the identifier and the parameters.
259 // The hack is requried so that we don't remove the separator inside macro calls.
260 // This does not work in the presence of comment, hoping that people are
261 // sane about where to put their comment.
262 let separator_snippet = context
263 .snippet(mk_sp(segment.ident.span.hi(), data.span.lo()))
265 let force_separator = context.inside_macro() && separator_snippet.starts_with("::");
266 let separator = if path_context == PathContext::Expr || force_separator {
271 result.push_str(separator);
273 let generics_str = overflow::rewrite_with_angle_brackets(
278 mk_sp(*span_lo, span_hi),
281 // Update position of last bracket.
284 .span_after(mk_sp(*span_lo, span_hi), "<");
286 result.push_str(&generics_str)
288 ast::GenericArgs::Parenthesized(ref data) => {
289 result.push_str(&format_function_type(
290 data.inputs.iter().map(|x| &**x),
305 fn format_function_type<'a, I>(
310 context: &RewriteContext<'_>,
314 I: ExactSizeIterator,
315 <I as Iterator>::Item: Deref,
316 <I::Item as Deref>::Target: Rewrite + Spanned + 'a,
318 debug!("format_function_type {:#?}", shape);
320 let ty_shape = match context.config.indent_style() {
322 IndentStyle::Block => shape.offset_left(4)?,
323 IndentStyle::Visual => shape.block_left(4)?,
325 let output = match *output {
326 FnRetTy::Ty(ref ty) => {
327 let type_str = ty.rewrite(context, ty_shape)?;
328 format!(" -> {}", type_str)
330 FnRetTy::Default(..) => String::new(),
333 let list_shape = if context.use_block_indent() {
335 shape.block().indent.block_indent(context.config),
340 let budget = shape.width.checked_sub(2)?;
342 let offset = shape.indent + 1;
343 Shape::legacy(budget, offset)
346 let is_inputs_empty = inputs.len() == 0;
347 let list_lo = context.snippet_provider.span_after(span, "(");
348 let (list_str, tactic) = if is_inputs_empty {
349 let tactic = get_tactics(&[], &output, shape);
350 let list_hi = context.snippet_provider.span_before(span, ")");
351 let comment = context
353 .span_to_snippet(mk_sp(list_lo, list_hi))?
355 let comment = if comment.starts_with("//") {
358 &list_shape.indent.to_string_with_newline(context.config),
360 &shape.block().indent.to_string_with_newline(context.config)
367 let items = itemize_list(
368 context.snippet_provider,
372 |arg| arg.span().lo(),
373 |arg| arg.span().hi(),
374 |arg| arg.rewrite(context, list_shape),
380 let item_vec: Vec<_> = items.collect();
381 let tactic = get_tactics(&item_vec, &output, shape);
382 let trailing_separator = if !context.use_block_indent() || variadic {
383 SeparatorTactic::Never
385 context.config.trailing_comma()
388 let fmt = ListFormatting::new(list_shape, context.config)
390 .trailing_separator(trailing_separator)
391 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
392 .preserve_newline(true);
393 (write_list(&item_vec, &fmt)?, tactic)
396 let args = if tactic == DefinitiveListTactic::Horizontal
397 || !context.use_block_indent()
400 format!("({})", list_str)
404 list_shape.indent.to_string_with_newline(context.config),
406 shape.block().indent.to_string_with_newline(context.config),
409 if output.is_empty() || last_line_width(&args) + first_line_width(&output) <= shape.width {
410 Some(format!("{}{}", args, output))
415 list_shape.indent.to_string(context.config),
421 fn type_bound_colon(context: &RewriteContext<'_>) -> &'static str {
422 colon_spaces(context.config)
425 // If the return type is multi-lined, then force to use multiple lines for
426 // arguments as well.
427 fn get_tactics(item_vec: &[ListItem], output: &str, shape: Shape) -> DefinitiveListTactic {
428 if output.contains('\n') {
429 DefinitiveListTactic::Vertical
433 ListTactic::HorizontalVertical,
435 // 2 is for the case of ',\n'
436 shape.width.saturating_sub(2 + output.len()),
441 impl Rewrite for ast::WherePredicate {
442 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
443 // FIXME: dead spans?
444 let result = match *self {
445 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
446 ref bound_generic_params,
451 let type_str = bounded_ty.rewrite(context, shape)?;
452 let colon = type_bound_colon(context).trim_end();
453 let lhs = if let Some(lifetime_str) =
454 rewrite_lifetime_param(context, shape, bound_generic_params)
456 format!("for<{}> {}{}", lifetime_str, type_str, colon)
458 format!("{}{}", type_str, colon)
461 rewrite_assign_rhs(context, lhs, bounds, shape)?
463 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
467 }) => rewrite_bounded_lifetime(lifetime, bounds, context, shape)?,
468 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
473 let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
474 rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
482 impl Rewrite for ast::GenericArg {
483 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
485 ast::GenericArg::Lifetime(ref lt) => lt.rewrite(context, shape),
486 ast::GenericArg::Type(ref ty) => ty.rewrite(context, shape),
487 ast::GenericArg::Const(ref const_) => const_.rewrite(context, shape),
492 fn rewrite_bounded_lifetime(
494 bounds: &[ast::GenericBound],
495 context: &RewriteContext<'_>,
497 ) -> Option<String> {
498 let result = lt.rewrite(context, shape)?;
500 if bounds.is_empty() {
503 let colon = type_bound_colon(context);
504 let overhead = last_line_width(&result) + colon.len();
505 let result = format!(
509 join_bounds(context, shape.sub_width(overhead)?, bounds, true)?
515 impl Rewrite for ast::AnonConst {
516 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
517 format_expr(&self.value, ExprType::SubExpression, context, shape)
521 impl Rewrite for ast::Lifetime {
522 fn rewrite(&self, context: &RewriteContext<'_>, _: Shape) -> Option<String> {
523 Some(rewrite_ident(context, self.ident).to_owned())
527 impl Rewrite for ast::GenericBound {
528 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
530 ast::GenericBound::Trait(ref poly_trait_ref, trait_bound_modifier) => {
531 let snippet = context.snippet(self.span());
532 let has_paren = snippet.starts_with('(') && snippet.ends_with(')');
533 let rewrite = match trait_bound_modifier {
534 ast::TraitBoundModifier::None => poly_trait_ref.rewrite(context, shape),
535 ast::TraitBoundModifier::Maybe => poly_trait_ref
536 .rewrite(context, shape.offset_left(1)?)
537 .map(|s| format!("?{}", s)),
538 ast::TraitBoundModifier::MaybeConst => poly_trait_ref
539 .rewrite(context, shape.offset_left(7)?)
540 .map(|s| format!("?const {}", s)),
541 ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
542 .rewrite(context, shape.offset_left(8)?)
543 .map(|s| format!("?const ?{}", s)),
545 rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
547 ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape),
552 impl Rewrite for ast::GenericBounds {
553 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
555 return Some(String::new());
558 join_bounds(context, shape, self, true)
562 impl Rewrite for ast::GenericParam {
563 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
564 let mut result = String::with_capacity(128);
565 // FIXME: If there are more than one attributes, this will force multiline.
566 match self.attrs.rewrite(context, shape) {
567 Some(ref rw) if !rw.is_empty() => result.push_str(&format!("{} ", rw)),
571 if let ast::GenericParamKind::Const {
577 result.push_str("const ");
578 result.push_str(rewrite_ident(context, self.ident));
579 result.push_str(": ");
580 result.push_str(&ty.rewrite(context, shape)?);
582 result.push_str(rewrite_ident(context, self.ident));
585 if !self.bounds.is_empty() {
586 result.push_str(type_bound_colon(context));
587 result.push_str(&self.bounds.rewrite(context, shape)?)
589 if let ast::GenericParamKind::Type {
590 default: Some(ref def),
593 let eq_str = match context.config.type_punctuation_density() {
594 TypeDensity::Compressed => "=",
595 TypeDensity::Wide => " = ",
597 result.push_str(eq_str);
598 let budget = shape.width.checked_sub(result.len())?;
600 def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
601 result.push_str(&rewrite);
608 impl Rewrite for ast::PolyTraitRef {
609 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
610 if let Some(lifetime_str) =
611 rewrite_lifetime_param(context, shape, &self.bound_generic_params)
613 // 6 is "for<> ".len()
614 let extra_offset = lifetime_str.len() + 6;
617 .rewrite(context, shape.offset_left(extra_offset)?)?;
619 Some(format!("for<{}> {}", lifetime_str, path_str))
621 self.trait_ref.rewrite(context, shape)
626 impl Rewrite for ast::TraitRef {
627 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
628 rewrite_path(context, PathContext::Type, None, &self.path, shape)
632 impl Rewrite for ast::Ty {
633 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
635 ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
636 // we have to consider 'dyn' keyword is used or not!!!
637 let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
638 // 4 is length of 'dyn '
639 let shape = if is_dyn { shape.offset_left(4)? } else { shape };
640 let mut res = bounds.rewrite(context, shape)?;
641 // We may have falsely removed a trailing `+` inside macro call.
642 if context.inside_macro() && bounds.len() == 1 {
643 if context.snippet(self.span).ends_with('+') && !res.ends_with('+') {
648 Some(format!("dyn {}", res))
653 ast::TyKind::Ptr(ref mt) => {
654 let prefix = match mt.mutbl {
655 Mutability::Mut => "*mut ",
656 Mutability::Not => "*const ",
659 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
661 ast::TyKind::Rptr(ref lifetime, ref mt) => {
662 let mut_str = format_mutability(mt.mutbl);
663 let mut_len = mut_str.len();
664 let mut result = String::with_capacity(128);
665 result.push_str("&");
666 let ref_hi = context.snippet_provider.span_after(self.span(), "&");
667 let mut cmnt_lo = ref_hi;
669 if let Some(ref lifetime) = *lifetime {
670 let lt_budget = shape.width.checked_sub(2 + mut_len)?;
671 let lt_str = lifetime.rewrite(
673 Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
675 let before_lt_span = mk_sp(cmnt_lo, lifetime.ident.span.lo());
676 if contains_comment(context.snippet(before_lt_span)) {
677 result = combine_strs_with_missing_comments(
686 result.push_str(<_str);
688 result.push_str(" ");
689 cmnt_lo = lifetime.ident.span.hi();
692 if ast::Mutability::Mut == mt.mutbl {
693 let mut_hi = context.snippet_provider.span_after(self.span(), "mut");
694 let before_mut_span = mk_sp(cmnt_lo, mut_hi - BytePos::from_usize(3));
695 if contains_comment(context.snippet(before_mut_span)) {
696 result = combine_strs_with_missing_comments(
705 result.push_str(mut_str);
710 let before_ty_span = mk_sp(cmnt_lo, mt.ty.span.lo());
711 if contains_comment(context.snippet(before_ty_span)) {
712 result = combine_strs_with_missing_comments(
715 &mt.ty.rewrite(&context, shape)?,
721 let used_width = last_line_width(&result);
722 let budget = shape.width.checked_sub(used_width)?;
725 .rewrite(&context, Shape::legacy(budget, shape.indent + used_width))?;
726 result.push_str(&ty_str);
731 // FIXME: we drop any comments here, even though it's a silly place to put
733 ast::TyKind::Paren(ref ty) => {
734 if context.config.version() == Version::One
735 || context.config.indent_style() == IndentStyle::Visual
737 let budget = shape.width.checked_sub(2)?;
739 .rewrite(context, Shape::legacy(budget, shape.indent + 1))
740 .map(|ty_str| format!("({})", ty_str));
744 if let Some(sh) = shape.sub_width(2) {
745 if let Some(ref s) = ty.rewrite(context, sh) {
746 if !s.contains('\n') {
747 return Some(format!("({})", s));
752 let indent_str = shape.indent.to_string_with_newline(context.config);
754 .block_indent(context.config.tab_spaces())
755 .with_max_width(context.config);
756 let rw = ty.rewrite(context, shape)?;
759 shape.to_string_with_newline(context.config),
764 ast::TyKind::Slice(ref ty) => {
765 let budget = shape.width.checked_sub(4)?;
766 ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
767 .map(|ty_str| format!("[{}]", ty_str))
769 ast::TyKind::Tup(ref items) => {
770 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
772 ast::TyKind::AnonymousStruct(ref fields, recovered) => {
773 let ident = Ident::new(
775 mk_sp(self.span.lo(), self.span.lo() + BytePos(6)),
777 let data = ast::VariantData::Struct(fields.clone(), recovered);
778 let variant = ast::Variant {
779 attrs: AttrVec::new(),
782 vis: DEFAULT_VISIBILITY,
786 is_placeholder: false,
788 format_struct_struct(
790 &StructParts::from_variant(&variant),
796 ast::TyKind::AnonymousUnion(ref fields, recovered) => {
797 let ident = Ident::new(
799 mk_sp(self.span.lo(), self.span.lo() + BytePos(5)),
801 let data = ast::VariantData::Struct(fields.clone(), recovered);
802 let variant = ast::Variant {
803 attrs: AttrVec::new(),
806 vis: DEFAULT_VISIBILITY,
810 is_placeholder: false,
812 format_struct_struct(
814 &StructParts::from_variant(&variant),
820 ast::TyKind::Path(ref q_self, ref path) => {
821 rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
823 ast::TyKind::Array(ref ty, ref repeats) => rewrite_pair(
826 PairParts::new("[", "; ", "]"),
829 SeparatorPlace::Back,
831 ast::TyKind::Infer => {
832 if shape.width >= 1 {
838 ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
839 ast::TyKind::Never => Some(String::from("!")),
840 ast::TyKind::MacCall(ref mac) => {
841 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
843 ast::TyKind::ImplicitSelf => Some(String::from("")),
844 ast::TyKind::ImplTrait(_, ref it) => {
845 // Empty trait is not a parser error.
847 return Some("impl".to_owned());
849 let rw = if context.config.version() == Version::One {
850 it.rewrite(context, shape)
852 join_bounds(context, shape, it, false)
855 let space = if it_str.is_empty() { "" } else { " " };
856 format!("impl{}{}", space, it_str)
859 ast::TyKind::CVarArgs => Some("...".to_owned()),
860 ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
861 ast::TyKind::Typeof(ref anon_const) => rewrite_call(
864 &[anon_const.value.clone()],
873 bare_fn: &ast::BareFnTy,
875 context: &RewriteContext<'_>,
877 ) -> Option<String> {
878 debug!("rewrite_bare_fn {:#?}", shape);
880 let mut result = String::with_capacity(128);
882 if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
884 result.push_str("for<");
885 // 6 = "for<> ".len(), 4 = "for<".
886 // This doesn't work out so nicely for multiline situation with lots of
887 // rightward drift. If that is a problem, we could use the list stuff.
888 result.push_str(lifetime_str);
889 result.push_str("> ");
892 result.push_str(crate::utils::format_unsafety(bare_fn.unsafety));
894 result.push_str(&format_extern(
896 context.config.force_explicit_abi(),
900 result.push_str("fn");
902 let func_ty_shape = if context.use_block_indent() {
903 shape.offset_left(result.len())?
905 shape.visual_indent(result.len()).sub_width(result.len())?
908 let rewrite = format_function_type(
909 bare_fn.decl.inputs.iter(),
910 &bare_fn.decl.output,
911 bare_fn.decl.c_variadic(),
917 result.push_str(&rewrite);
922 fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
923 let is_trait = |b: &ast::GenericBound| match b {
924 ast::GenericBound::Outlives(..) => false,
925 ast::GenericBound::Trait(..) => true,
927 let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
928 let last_trait_index = generic_bounds.iter().rposition(is_trait);
929 let first_lifetime_index = generic_bounds.iter().position(is_lifetime);
930 match (last_trait_index, first_lifetime_index) {
931 (Some(last_trait_index), Some(first_lifetime_index)) => {
932 last_trait_index < first_lifetime_index
939 context: &RewriteContext<'_>,
941 items: &[ast::GenericBound],
943 ) -> Option<String> {
944 join_bounds_inner(context, shape, items, need_indent, false)
947 fn join_bounds_inner(
948 context: &RewriteContext<'_>,
950 items: &[ast::GenericBound],
953 ) -> Option<String> {
954 debug_assert!(!items.is_empty());
956 let generic_bounds_in_order = is_generic_bounds_in_order(items);
957 let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
958 ast::GenericBound::Outlives(..) => true,
959 ast::GenericBound::Trait(..) => last_line_extendable(s),
962 let result = items.iter().enumerate().try_fold(
963 (String::new(), None, false),
964 |(strs, prev_trailing_span, prev_extendable), (i, item)| {
965 let trailing_span = if i < items.len() - 1 {
968 .span_before(mk_sp(items[i + 1].span().lo(), item.span().hi()), "+");
970 Some(mk_sp(item.span().hi(), hi))
974 let (leading_span, has_leading_comment) = if i > 0 {
977 .span_after(mk_sp(items[i - 1].span().hi(), item.span().lo()), "+");
979 let span = mk_sp(lo, item.span().lo());
981 let has_comments = contains_comment(context.snippet(span));
983 (Some(mk_sp(lo, item.span().lo())), has_comments)
987 let prev_has_trailing_comment = match prev_trailing_span {
988 Some(ts) => contains_comment(context.snippet(ts)),
992 let shape = if need_indent && force_newline {
994 .block_indent(context.config.tab_spaces())
995 .with_max_width(context.config)
999 let whitespace = if force_newline && (!prev_extendable || !generic_bounds_in_order) {
1002 .to_string_with_newline(context.config)
1008 let joiner = match context.config.type_punctuation_density() {
1009 TypeDensity::Compressed => String::from("+"),
1010 TypeDensity::Wide => whitespace + "+ ",
1012 let joiner = if has_leading_comment {
1017 let joiner = if prev_has_trailing_comment {
1023 let (extendable, trailing_str) = if i == 0 {
1024 let bound_str = item.rewrite(context, shape)?;
1025 (is_bound_extendable(&bound_str, item), bound_str)
1027 let bound_str = &item.rewrite(context, shape)?;
1028 match leading_span {
1029 Some(ls) if has_leading_comment => (
1030 is_bound_extendable(bound_str, item),
1031 combine_strs_with_missing_comments(
1032 context, joiner, bound_str, ls, shape, true,
1036 is_bound_extendable(bound_str, item),
1037 String::from(joiner) + bound_str,
1041 match prev_trailing_span {
1042 Some(ts) if prev_has_trailing_comment => combine_strs_with_missing_comments(
1050 .map(|v| (v, trailing_span, extendable)),
1052 String::from(strs) + &trailing_str,
1062 && (result.0.contains('\n') || result.0.len() > shape.width)
1064 join_bounds_inner(context, shape, items, need_indent, true)
1070 pub(crate) fn can_be_overflowed_type(
1071 context: &RewriteContext<'_>,
1076 ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
1077 ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
1078 can_be_overflowed_type(context, &*mutty.ty, len)
1084 /// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
1085 fn rewrite_lifetime_param(
1086 context: &RewriteContext<'_>,
1088 generic_params: &[ast::GenericParam],
1089 ) -> Option<String> {
1090 let result = generic_params
1092 .filter(|p| match p.kind {
1093 ast::GenericParamKind::Lifetime => true,
1096 .map(|lt| lt.rewrite(context, shape))
1097 .collect::<Option<Vec<_>>>()?
1099 if result.is_empty() {