1use std::ops::Deref;
2
3use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
4use rustc_span::{BytePos, Pos, Span, symbol::kw};
5use tracing::debug;
6
7use crate::comment::{combine_strs_with_missing_comments, contains_comment};
8use crate::config::lists::*;
9use crate::config::{IndentStyle, StyleEdition, TypeDensity};
10use crate::expr::{
11 ExprType, RhsAssignKind, format_expr, rewrite_assign_rhs, rewrite_tuple, rewrite_unary_prefix,
12};
13use crate::lists::{
14 ListFormatting, ListItem, Separator, definitive_tactic, itemize_list, write_list,
15};
16use crate::macros::{MacroPosition, rewrite_macro};
17use crate::overflow;
18use crate::pairs::{PairParts, rewrite_pair};
19use crate::patterns::rewrite_range_pat;
20use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
21use crate::shape::Shape;
22use crate::source_map::SpanUtils;
23use crate::spanned::Spanned;
24use crate::utils::{
25 colon_spaces, extra_offset, first_line_width, format_extern, format_mutability,
26 last_line_extendable, last_line_width, mk_sp, rewrite_ident,
27};
28
29#[derive(Copy, Clone, Debug, Eq, PartialEq)]
30pub(crate) enum PathContext {
31 Expr,
32 Type,
33 Import,
34}
35
36pub(crate) fn rewrite_path(
38 context: &RewriteContext<'_>,
39 path_context: PathContext,
40 qself: &Option<Box<ast::QSelf>>,
41 path: &ast::Path,
42 shape: Shape,
43) -> RewriteResult {
44 let skip_count = qself.as_ref().map_or(0, |x| x.position);
45
46 let mut result = String::with_capacity(32);
49
50 if path.is_global() && qself.is_none() && path_context != PathContext::Import {
51 result.push_str("::");
52 }
53
54 let mut span_lo = path.span.lo();
55
56 if let Some(qself) = qself {
57 result.push('<');
58
59 let fmt_ty = qself.ty.rewrite_result(context, shape)?;
60 result.push_str(&fmt_ty);
61
62 if skip_count > 0 {
63 result.push_str(" as ");
64 if path.is_global() && path_context != PathContext::Import {
65 result.push_str("::");
66 }
67
68 let shape = shape.sub_width(3).max_width_error(shape.width, path.span)?;
70
71 result = rewrite_path_segments(
72 PathContext::Type,
73 result,
74 path.segments.iter().take(skip_count),
75 span_lo,
76 path.span.hi(),
77 context,
78 shape,
79 )?;
80 }
81
82 result.push_str(">::");
83 span_lo = qself.ty.span.hi() + BytePos(1);
84 }
85
86 rewrite_path_segments(
87 path_context,
88 result,
89 path.segments.iter().skip(skip_count),
90 span_lo,
91 path.span.hi(),
92 context,
93 shape,
94 )
95}
96
97fn rewrite_path_segments<'a, I>(
98 path_context: PathContext,
99 mut buffer: String,
100 iter: I,
101 mut span_lo: BytePos,
102 span_hi: BytePos,
103 context: &RewriteContext<'_>,
104 shape: Shape,
105) -> RewriteResult
106where
107 I: Iterator<Item = &'a ast::PathSegment>,
108{
109 let mut first = true;
110 let shape = shape.visual_indent(0);
111
112 for segment in iter {
113 if segment.ident.name == kw::PathRoot {
115 continue;
116 }
117 if first {
118 first = false;
119 } else {
120 buffer.push_str("::");
121 }
122
123 let extra_offset = extra_offset(&buffer, shape);
124 let new_shape = shape
125 .shrink_left(extra_offset)
126 .max_width_error(shape.width, mk_sp(span_lo, span_hi))?;
127 let segment_string = rewrite_segment(
128 path_context,
129 segment,
130 &mut span_lo,
131 span_hi,
132 context,
133 new_shape,
134 )?;
135
136 buffer.push_str(&segment_string);
137 }
138
139 Ok(buffer)
140}
141
142#[derive(Debug)]
143pub(crate) enum SegmentParam<'a> {
144 Const(&'a ast::AnonConst),
145 LifeTime(&'a ast::Lifetime),
146 Type(&'a ast::Ty),
147 Binding(&'a ast::AssocItemConstraint),
148}
149
150impl<'a> SegmentParam<'a> {
151 fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam<'_> {
152 match arg {
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_),
156 }
157 }
158}
159
160impl<'a> Spanned for SegmentParam<'a> {
161 fn span(&self) -> Span {
162 match *self {
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,
167 }
168 }
169}
170
171impl<'a> Rewrite for SegmentParam<'a> {
172 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
173 self.rewrite_result(context, shape).ok()
174 }
175
176 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
177 match *self {
178 SegmentParam::Const(const_) => const_.rewrite_result(context, shape),
179 SegmentParam::LifeTime(lt) => lt.rewrite_result(context, shape),
180 SegmentParam::Type(ty) => ty.rewrite_result(context, shape),
181 SegmentParam::Binding(atc) => atc.rewrite_result(context, shape),
182 }
183 }
184}
185
186impl Rewrite for ast::PreciseCapturingArg {
187 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
188 self.rewrite_result(context, shape).ok()
189 }
190
191 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
192 match self {
193 ast::PreciseCapturingArg::Lifetime(lt) => lt.rewrite_result(context, shape),
194 ast::PreciseCapturingArg::Arg(p, _) => {
195 rewrite_path(context, PathContext::Type, &None, p, shape)
196 }
197 }
198 }
199}
200
201impl Rewrite for ast::AssocItemConstraint {
202 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
203 self.rewrite_result(context, shape).ok()
204 }
205
206 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
207 use ast::AssocItemConstraintKind::{Bound, Equality};
208
209 let mut result = String::with_capacity(128);
210 result.push_str(rewrite_ident(context, self.ident));
211
212 if let Some(ref gen_args) = self.gen_args {
213 let budget = shape
214 .width
215 .checked_sub(result.len())
216 .max_width_error(shape.width, self.span)?;
217 let shape = Shape::legacy(budget, shape.indent + result.len());
218 let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
219 result.push_str(&gen_str);
220 }
221
222 let infix = match (&self.kind, context.config.type_punctuation_density()) {
223 (Bound { .. }, _) => ": ",
224 (Equality { .. }, TypeDensity::Wide) => " = ",
225 (Equality { .. }, TypeDensity::Compressed) => "=",
226 };
227 result.push_str(infix);
228
229 let budget = shape
230 .width
231 .checked_sub(result.len())
232 .max_width_error(shape.width, self.span)?;
233 let shape = Shape::legacy(budget, shape.indent + result.len());
234 let rewrite = self.kind.rewrite_result(context, shape)?;
235 result.push_str(&rewrite);
236
237 Ok(result)
238 }
239}
240
241impl Rewrite for ast::AssocItemConstraintKind {
242 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
243 self.rewrite_result(context, shape).ok()
244 }
245
246 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
247 match self {
248 ast::AssocItemConstraintKind::Equality { term } => match term {
249 Term::Ty(ty) => ty.rewrite_result(context, shape),
250 Term::Const(c) => c.rewrite_result(context, shape),
251 },
252 ast::AssocItemConstraintKind::Bound { bounds } => bounds.rewrite_result(context, shape),
253 }
254 }
255}
256
257fn rewrite_segment(
268 path_context: PathContext,
269 segment: &ast::PathSegment,
270 span_lo: &mut BytePos,
271 span_hi: BytePos,
272 context: &RewriteContext<'_>,
273 shape: Shape,
274) -> RewriteResult {
275 let mut result = String::with_capacity(128);
276 result.push_str(rewrite_ident(context, segment.ident));
277
278 let ident_len = result.len();
279 let shape = if context.use_block_indent() {
280 shape.offset_left(ident_len)
281 } else {
282 shape.shrink_left(ident_len)
283 }
284 .max_width_error(shape.width, mk_sp(*span_lo, span_hi))?;
285
286 if let Some(ref args) = segment.args {
287 let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
288 match **args {
289 ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
290 let separator_snippet = context
295 .snippet(mk_sp(segment.ident.span.hi(), data.span.lo()))
296 .trim();
297 let force_separator = context.inside_macro() && separator_snippet.starts_with("::");
298 let separator = if path_context == PathContext::Expr || force_separator {
299 "::"
300 } else {
301 ""
302 };
303 result.push_str(separator);
304
305 *span_lo = context
307 .snippet_provider
308 .span_after(mk_sp(*span_lo, span_hi), "<");
309 }
310 _ => (),
311 }
312 result.push_str(&generics_str)
313 }
314
315 Ok(result)
316}
317
318fn format_function_type<'a, I>(
319 inputs: I,
320 output: &FnRetTy,
321 variadic: bool,
322 span: Span,
323 context: &RewriteContext<'_>,
324 shape: Shape,
325) -> RewriteResult
326where
327 I: ExactSizeIterator,
328 <I as Iterator>::Item: Deref,
329 <I::Item as Deref>::Target: Rewrite + Spanned + 'a,
330{
331 debug!("format_function_type {:#?}", shape);
332
333 let ty_shape = match context.config.indent_style() {
334 IndentStyle::Block => shape.offset_left(4).max_width_error(shape.width, span)?,
336 IndentStyle::Visual => shape.block_left(4).max_width_error(shape.width, span)?,
337 };
338 let output = match *output {
339 FnRetTy::Ty(ref ty) => {
340 let type_str = ty.rewrite_result(context, ty_shape)?;
341 format!(" -> {type_str}")
342 }
343 FnRetTy::Default(..) => String::new(),
344 };
345
346 let list_shape = if context.use_block_indent() {
347 Shape::indented(
348 shape.block().indent.block_indent(context.config),
349 context.config,
350 )
351 } else {
352 let budget = shape
354 .width
355 .checked_sub(2)
356 .max_width_error(shape.width, span)?;
357 let offset = shape.indent + 1;
359 Shape::legacy(budget, offset)
360 };
361
362 let is_inputs_empty = inputs.len() == 0;
363 let list_lo = context.snippet_provider.span_after(span, "(");
364 let (list_str, tactic) = if is_inputs_empty {
365 let tactic = get_tactics(&[], &output, shape);
366 let list_hi = context.snippet_provider.span_before(span, ")");
367 let comment = context
368 .snippet_provider
369 .span_to_snippet(mk_sp(list_lo, list_hi))
370 .unknown_error()?
371 .trim();
372 let comment = if comment.starts_with("//") {
373 format!(
374 "{}{}{}",
375 &list_shape.indent.to_string_with_newline(context.config),
376 comment,
377 &shape.block().indent.to_string_with_newline(context.config)
378 )
379 } else {
380 comment.to_string()
381 };
382 (comment, tactic)
383 } else {
384 let items = itemize_list(
385 context.snippet_provider,
386 inputs,
387 ")",
388 ",",
389 |arg| arg.span().lo(),
390 |arg| arg.span().hi(),
391 |arg| arg.rewrite_result(context, list_shape),
392 list_lo,
393 span.hi(),
394 false,
395 );
396
397 let item_vec: Vec<_> = items.collect();
398 let tactic = get_tactics(&item_vec, &output, shape);
399 let trailing_separator = if !context.use_block_indent() || variadic {
400 SeparatorTactic::Never
401 } else {
402 context.config.trailing_comma()
403 };
404
405 let fmt = ListFormatting::new(list_shape, context.config)
406 .tactic(tactic)
407 .trailing_separator(trailing_separator)
408 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
409 .preserve_newline(true);
410 (write_list(&item_vec, &fmt)?, tactic)
411 };
412
413 let args = if tactic == DefinitiveListTactic::Horizontal
414 || !context.use_block_indent()
415 || is_inputs_empty
416 {
417 format!("({list_str})")
418 } else {
419 format!(
420 "({}{}{})",
421 list_shape.indent.to_string_with_newline(context.config),
422 list_str,
423 shape.block().indent.to_string_with_newline(context.config),
424 )
425 };
426 if output.is_empty() || last_line_width(&args) + first_line_width(&output) <= shape.width {
427 Ok(format!("{args}{output}"))
428 } else {
429 Ok(format!(
430 "{}\n{}{}",
431 args,
432 list_shape.indent.to_string(context.config),
433 output.trim_start()
434 ))
435 }
436}
437
438fn type_bound_colon(context: &RewriteContext<'_>) -> &'static str {
439 colon_spaces(context.config)
440}
441
442fn get_tactics(item_vec: &[ListItem], output: &str, shape: Shape) -> DefinitiveListTactic {
445 if output.contains('\n') {
446 DefinitiveListTactic::Vertical
447 } else {
448 definitive_tactic(
449 item_vec,
450 ListTactic::HorizontalVertical,
451 Separator::Comma,
452 shape.width.saturating_sub(2 + output.len()),
454 )
455 }
456}
457
458impl Rewrite for ast::WherePredicate {
459 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
460 self.rewrite_result(context, shape).ok()
461 }
462
463 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
464 let attrs_str = self.attrs.rewrite_result(context, shape)?;
465 let pred_str = &match self.kind {
467 ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
468 ref bound_generic_params,
469 ref bounded_ty,
470 ref bounds,
471 ..
472 }) => {
473 let type_str = bounded_ty.rewrite_result(context, shape)?;
474 let colon = type_bound_colon(context).trim_end();
475 let lhs = if let Some(binder_str) =
476 rewrite_bound_params(context, shape, bound_generic_params)
477 {
478 format!("for<{binder_str}> {type_str}{colon}")
479 } else {
480 format!("{type_str}{colon}")
481 };
482
483 rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
484 }
485 ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
486 ref lifetime,
487 ref bounds,
488 }) => rewrite_bounded_lifetime(lifetime, bounds, self.span, context, shape)?,
489 ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate {
490 ref lhs_ty,
491 ref rhs_ty,
492 ..
493 }) => {
494 let lhs_ty_str = lhs_ty
495 .rewrite_result(context, shape)
496 .map(|lhs| lhs + " =")?;
497 rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
498 }
499 };
500
501 let mut result = String::with_capacity(attrs_str.len() + pred_str.len() + 1);
502 result.push_str(&attrs_str);
503 let pred_start = self.span.lo();
504 let line_len = last_line_width(&attrs_str) + 1 + first_line_width(&pred_str);
505 if let Some(last_attr) = self.attrs.last().filter(|last_attr| {
506 contains_comment(context.snippet(mk_sp(last_attr.span.hi(), pred_start)))
507 }) {
508 result = combine_strs_with_missing_comments(
509 context,
510 &result,
511 &pred_str,
512 mk_sp(last_attr.span.hi(), pred_start),
513 Shape {
514 width: shape.width.min(context.config.inline_attribute_width()),
515 ..shape
516 },
517 !last_attr.is_doc_comment(),
518 )?;
519 } else {
520 if !self.attrs.is_empty() {
521 if context.config.inline_attribute_width() < line_len
522 || self.attrs.len() > 1
523 || self.attrs.last().is_some_and(|a| a.is_doc_comment())
524 {
525 result.push_str(&shape.indent.to_string_with_newline(context.config));
526 } else {
527 result.push(' ');
528 }
529 }
530 result.push_str(&pred_str);
531 }
532
533 Ok(result)
534 }
535}
536
537impl Rewrite for ast::GenericArg {
538 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
539 self.rewrite_result(context, shape).ok()
540 }
541
542 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
543 match *self {
544 ast::GenericArg::Lifetime(ref lt) => lt.rewrite_result(context, shape),
545 ast::GenericArg::Type(ref ty) => ty.rewrite_result(context, shape),
546 ast::GenericArg::Const(ref const_) => const_.rewrite_result(context, shape),
547 }
548 }
549}
550
551fn rewrite_generic_args(
552 gen_args: &ast::GenericArgs,
553 context: &RewriteContext<'_>,
554 shape: Shape,
555 span: Span,
556) -> RewriteResult {
557 match gen_args {
558 ast::GenericArgs::AngleBracketed(ref data) => {
559 if data.args.is_empty() {
560 Ok("".to_owned())
561 } else {
562 let args = data
563 .args
564 .iter()
565 .map(|x| match x {
566 ast::AngleBracketedArg::Arg(generic_arg) => {
567 SegmentParam::from_generic_arg(generic_arg)
568 }
569 ast::AngleBracketedArg::Constraint(constraint) => {
570 SegmentParam::Binding(constraint)
571 }
572 })
573 .collect::<Vec<_>>();
574
575 overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
576 }
577 }
578 ast::GenericArgs::Parenthesized(ref data) => format_function_type(
579 data.inputs.iter().map(|x| &**x),
580 &data.output,
581 false,
582 data.span,
583 context,
584 shape,
585 ),
586 ast::GenericArgs::ParenthesizedElided(..) => Ok("(..)".to_owned()),
587 }
588}
589
590fn rewrite_bounded_lifetime(
591 lt: &ast::Lifetime,
592 bounds: &[ast::GenericBound],
593 span: Span,
594 context: &RewriteContext<'_>,
595 shape: Shape,
596) -> RewriteResult {
597 let result = lt.rewrite_result(context, shape)?;
598
599 if bounds.is_empty() {
600 Ok(result)
601 } else {
602 let colon = type_bound_colon(context);
603 let overhead = last_line_width(&result) + colon.len();
604 let shape = shape
605 .sub_width(overhead)
606 .max_width_error(shape.width, span)?;
607 let result = format!(
608 "{}{}{}",
609 result,
610 colon,
611 join_bounds(context, shape, bounds, true)?
612 );
613 Ok(result)
614 }
615}
616
617impl Rewrite for ast::AnonConst {
618 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
619 self.rewrite_result(context, shape).ok()
620 }
621
622 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
623 format_expr(&self.value, ExprType::SubExpression, context, shape)
624 }
625}
626
627impl Rewrite for ast::Lifetime {
628 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
629 self.rewrite_result(context, shape).ok()
630 }
631
632 fn rewrite_result(&self, context: &RewriteContext<'_>, _: Shape) -> RewriteResult {
633 Ok(context.snippet(self.ident.span).to_owned())
634 }
635}
636
637impl Rewrite for ast::GenericBound {
638 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
639 self.rewrite_result(context, shape).ok()
640 }
641
642 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
643 match *self {
644 ast::GenericBound::Trait(ref poly_trait_ref) => {
645 let snippet = context.snippet(self.span());
646 let has_paren = snippet.starts_with('(') && snippet.ends_with(')');
647 poly_trait_ref
648 .rewrite_result(context, shape)
649 .map(|s| if has_paren { format!("({})", s) } else { s })
650 }
651 ast::GenericBound::Use(ref args, span) => {
652 overflow::rewrite_with_angle_brackets(context, "use", args.iter(), shape, span)
653 }
654 ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite_result(context, shape),
655 }
656 }
657}
658
659impl Rewrite for ast::GenericBounds {
660 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
661 self.rewrite_result(context, shape).ok()
662 }
663
664 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
665 if self.is_empty() {
666 return Ok(String::new());
667 }
668
669 join_bounds(context, shape, self, true)
670 }
671}
672
673impl Rewrite for ast::GenericParam {
674 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
675 self.rewrite_result(context, shape).ok()
676 }
677
678 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
679 let mut result = self
681 .attrs
682 .rewrite_result(context, shape)
683 .unwrap_or(String::new());
684 let has_attrs = !result.is_empty();
685
686 let mut param = String::with_capacity(128);
687
688 let param_start = if let ast::GenericParamKind::Const {
689 ref ty,
690 span,
691 default,
692 } = &self.kind
693 {
694 param.push_str("const ");
695 param.push_str(rewrite_ident(context, self.ident));
696 param.push_str(": ");
697 param.push_str(&ty.rewrite_result(context, shape)?);
698 if let Some(default) = default {
699 let eq_str = match context.config.type_punctuation_density() {
700 TypeDensity::Compressed => "=",
701 TypeDensity::Wide => " = ",
702 };
703 param.push_str(eq_str);
704 let budget = shape
705 .width
706 .checked_sub(param.len())
707 .max_width_error(shape.width, self.span())?;
708 let rewrite =
709 default.rewrite_result(context, Shape::legacy(budget, shape.indent))?;
710 param.push_str(&rewrite);
711 }
712 span.lo()
713 } else {
714 param.push_str(rewrite_ident(context, self.ident));
715 self.ident.span.lo()
716 };
717
718 if !self.bounds.is_empty() {
719 param.push_str(type_bound_colon(context));
720 param.push_str(&self.bounds.rewrite_result(context, shape)?)
721 }
722 if let ast::GenericParamKind::Type {
723 default: Some(ref def),
724 } = self.kind
725 {
726 let eq_str = match context.config.type_punctuation_density() {
727 TypeDensity::Compressed => "=",
728 TypeDensity::Wide => " = ",
729 };
730 param.push_str(eq_str);
731 let budget = shape
732 .width
733 .checked_sub(param.len())
734 .max_width_error(shape.width, self.span())?;
735 let rewrite =
736 def.rewrite_result(context, Shape::legacy(budget, shape.indent + param.len()))?;
737 param.push_str(&rewrite);
738 }
739
740 if let Some(last_attr) = self.attrs.last().filter(|last_attr| {
741 contains_comment(context.snippet(mk_sp(last_attr.span.hi(), param_start)))
742 }) {
743 result = combine_strs_with_missing_comments(
744 context,
745 &result,
746 ¶m,
747 mk_sp(last_attr.span.hi(), param_start),
748 shape,
749 !last_attr.is_doc_comment(),
750 )?;
751 } else {
752 if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) {
755 result.push_str(&shape.indent.to_string_with_newline(context.config));
756 } else if has_attrs {
757 result.push(' ');
758 }
759 result.push_str(¶m);
760 }
761
762 Ok(result)
763 }
764}
765
766impl Rewrite for ast::PolyTraitRef {
767 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
768 self.rewrite_result(context, shape).ok()
769 }
770
771 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
772 let (binder, shape) = if let Some(lifetime_str) =
773 rewrite_bound_params(context, shape, &self.bound_generic_params)
774 {
775 let extra_offset = lifetime_str.len() + 6;
777 let shape = shape
778 .offset_left(extra_offset)
779 .max_width_error(shape.width, self.span)?;
780 (format!("for<{lifetime_str}> "), shape)
781 } else {
782 (String::new(), shape)
783 };
784
785 let ast::TraitBoundModifiers {
786 constness,
787 asyncness,
788 polarity,
789 } = self.modifiers;
790 let mut constness = constness.as_str().to_string();
791 if !constness.is_empty() {
792 constness.push(' ');
793 }
794 let mut asyncness = asyncness.as_str().to_string();
795 if !asyncness.is_empty() {
796 asyncness.push(' ');
797 }
798 let polarity = polarity.as_str();
799 let shape = shape
800 .offset_left(constness.len() + polarity.len())
801 .max_width_error(shape.width, self.span)?;
802
803 let path_str = self.trait_ref.rewrite_result(context, shape)?;
804 Ok(format!(
805 "{binder}{constness}{asyncness}{polarity}{path_str}"
806 ))
807 }
808}
809
810impl Rewrite for ast::TraitRef {
811 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
812 self.rewrite_result(context, shape).ok()
813 }
814
815 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
816 rewrite_path(context, PathContext::Type, &None, &self.path, shape)
817 }
818}
819
820impl Rewrite for ast::Ty {
821 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
822 self.rewrite_result(context, shape).ok()
823 }
824
825 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
826 match self.kind {
827 ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
828 let (shape, prefix) = match tobj_syntax {
830 ast::TraitObjectSyntax::Dyn => {
831 let shape = shape
832 .offset_left(4)
833 .max_width_error(shape.width, self.span())?;
834 (shape, "dyn ")
835 }
836 ast::TraitObjectSyntax::None => (shape, ""),
837 };
838 let mut res = bounds.rewrite_result(context, shape)?;
839 if context.inside_macro()
841 && bounds.len() == 1
842 && context.snippet(self.span).ends_with('+')
843 && !res.ends_with('+')
844 {
845 res.push('+');
846 }
847 Ok(format!("{prefix}{res}"))
848 }
849 ast::TyKind::Ptr(ref mt) => {
850 let prefix = match mt.mutbl {
851 Mutability::Mut => "*mut ",
852 Mutability::Not => "*const ",
853 };
854
855 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
856 }
857 ast::TyKind::Ref(ref lifetime, ref mt)
858 | ast::TyKind::PinnedRef(ref lifetime, ref mt) => {
859 let mut_str = format_mutability(mt.mutbl);
860 let mut_len = mut_str.len();
861 let mut result = String::with_capacity(128);
862 result.push('&');
863 let ref_hi = context.snippet_provider.span_after(self.span(), "&");
864 let mut cmnt_lo = ref_hi;
865
866 if let Some(ref lifetime) = *lifetime {
867 let lt_budget = shape
868 .width
869 .checked_sub(2 + mut_len)
870 .max_width_error(shape.width, self.span())?;
871 let lt_str = lifetime.rewrite_result(
872 context,
873 Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
874 )?;
875 let before_lt_span = mk_sp(cmnt_lo, lifetime.ident.span.lo());
876 if contains_comment(context.snippet(before_lt_span)) {
877 result = combine_strs_with_missing_comments(
878 context,
879 &result,
880 <_str,
881 before_lt_span,
882 shape,
883 true,
884 )?;
885 } else {
886 result.push_str(<_str);
887 }
888 result.push(' ');
889 cmnt_lo = lifetime.ident.span.hi();
890 }
891
892 if let ast::TyKind::PinnedRef(..) = self.kind {
893 result.push_str("pin ");
894 if ast::Mutability::Not == mt.mutbl {
895 result.push_str("const ");
896 }
897 }
898
899 if ast::Mutability::Mut == mt.mutbl {
900 let mut_hi = context.snippet_provider.span_after(self.span(), "mut");
901 let before_mut_span = mk_sp(cmnt_lo, mut_hi - BytePos::from_usize(3));
902 if contains_comment(context.snippet(before_mut_span)) {
903 result = combine_strs_with_missing_comments(
904 context,
905 result.trim_end(),
906 mut_str,
907 before_mut_span,
908 shape,
909 true,
910 )?;
911 } else {
912 result.push_str(mut_str);
913 }
914 cmnt_lo = mut_hi;
915 }
916
917 let before_ty_span = mk_sp(cmnt_lo, mt.ty.span.lo());
918 if contains_comment(context.snippet(before_ty_span)) {
919 result = combine_strs_with_missing_comments(
920 context,
921 result.trim_end(),
922 &mt.ty.rewrite_result(context, shape)?,
923 before_ty_span,
924 shape,
925 true,
926 )?;
927 } else {
928 let used_width = last_line_width(&result);
929 let budget = shape
930 .width
931 .checked_sub(used_width)
932 .max_width_error(shape.width, self.span())?;
933 let ty_str = mt.ty.rewrite_result(
934 context,
935 Shape::legacy(budget, shape.indent + used_width),
936 )?;
937 result.push_str(&ty_str);
938 }
939
940 Ok(result)
941 }
942 ast::TyKind::Paren(ref ty) => {
945 if context.config.style_edition() <= StyleEdition::Edition2021
946 || context.config.indent_style() == IndentStyle::Visual
947 {
948 let budget = shape
949 .width
950 .checked_sub(2)
951 .max_width_error(shape.width, self.span())?;
952 return ty
953 .rewrite_result(context, Shape::legacy(budget, shape.indent + 1))
954 .map(|ty_str| format!("({})", ty_str));
955 }
956
957 if let Some(sh) = shape.sub_width(2) {
959 if let Ok(ref s) = ty.rewrite_result(context, sh) {
960 if !s.contains('\n') {
961 return Ok(format!("({s})"));
962 }
963 }
964 }
965
966 let indent_str = shape.indent.to_string_with_newline(context.config);
967 let shape = shape
968 .block_indent(context.config.tab_spaces())
969 .with_max_width(context.config);
970 let rw = ty.rewrite_result(context, shape)?;
971 Ok(format!(
972 "({}{}{})",
973 shape.to_string_with_newline(context.config),
974 rw,
975 indent_str
976 ))
977 }
978 ast::TyKind::Slice(ref ty) => {
979 let budget = shape
980 .width
981 .checked_sub(4)
982 .max_width_error(shape.width, self.span())?;
983 ty.rewrite_result(context, Shape::legacy(budget, shape.indent + 1))
984 .map(|ty_str| format!("[{}]", ty_str))
985 }
986 ast::TyKind::Tup(ref items) => {
987 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
988 }
989 ast::TyKind::Path(ref q_self, ref path) => {
990 rewrite_path(context, PathContext::Type, q_self, path, shape)
991 }
992 ast::TyKind::Array(ref ty, ref repeats) => rewrite_pair(
993 &**ty,
994 &*repeats.value,
995 PairParts::new("[", "; ", "]"),
996 context,
997 shape,
998 SeparatorPlace::Back,
999 ),
1000 ast::TyKind::Infer => {
1001 if shape.width >= 1 {
1002 Ok("_".to_owned())
1003 } else {
1004 Err(RewriteError::ExceedsMaxWidth {
1005 configured_width: shape.width,
1006 span: self.span(),
1007 })
1008 }
1009 }
1010 ast::TyKind::FnPtr(ref fn_ptr) => rewrite_fn_ptr(fn_ptr, self.span, context, shape),
1011 ast::TyKind::Never => Ok(String::from("!")),
1012 ast::TyKind::MacCall(ref mac) => {
1013 rewrite_macro(mac, context, shape, MacroPosition::Expression)
1014 }
1015 ast::TyKind::ImplicitSelf => Ok(String::from("")),
1016 ast::TyKind::ImplTrait(_, ref it) => {
1017 if it.is_empty() {
1019 return Ok("impl".to_owned());
1020 }
1021 let rw = if context.config.style_edition() <= StyleEdition::Edition2021 {
1022 it.rewrite_result(context, shape)
1023 } else {
1024 join_bounds(context, shape, it, false)
1025 };
1026 rw.map(|it_str| {
1027 let space = if it_str.is_empty() { "" } else { " " };
1028 format!("impl{}{}", space, it_str)
1029 })
1030 }
1031 ast::TyKind::CVarArgs => Ok("...".to_owned()),
1032 ast::TyKind::Dummy | ast::TyKind::Err(_) => Ok(context.snippet(self.span).to_owned()),
1033 ast::TyKind::Pat(ref ty, ref pat) => {
1034 let ty = ty.rewrite_result(context, shape)?;
1035 let pat = pat.rewrite_result(context, shape)?;
1036 Ok(format!("{ty} is {pat}"))
1037 }
1038 ast::TyKind::UnsafeBinder(ref binder) => {
1039 let mut result = String::new();
1040 if binder.generic_params.is_empty() {
1041 result.push_str("unsafe<> ")
1044 } else if let Some(ref lifetime_str) =
1045 rewrite_bound_params(context, shape, &binder.generic_params)
1046 {
1047 result.push_str("unsafe<");
1048 result.push_str(lifetime_str);
1049 result.push_str("> ");
1050 }
1051
1052 let inner_ty_shape = if context.use_block_indent() {
1053 shape
1054 .offset_left(result.len())
1055 .max_width_error(shape.width, self.span())?
1056 } else {
1057 shape
1058 .visual_indent(result.len())
1059 .sub_width(result.len())
1060 .max_width_error(shape.width, self.span())?
1061 };
1062
1063 let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?;
1064 result.push_str(&rewrite);
1065 Ok(result)
1066 }
1067 }
1068 }
1069}
1070
1071impl Rewrite for ast::TyPat {
1072 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1073 self.rewrite_result(context, shape).ok()
1074 }
1075
1076 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1077 match self.kind {
1078 ast::TyPatKind::Range(ref lhs, ref rhs, ref end_kind) => {
1079 rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span)
1080 }
1081 ast::TyPatKind::Or(ref variants) => {
1082 let mut first = true;
1083 let mut s = String::new();
1084 for variant in variants {
1085 if first {
1086 first = false
1087 } else {
1088 s.push_str(" | ");
1089 }
1090 s.push_str(&variant.rewrite_result(context, shape)?);
1091 }
1092 Ok(s)
1093 }
1094 ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
1095 }
1096 }
1097}
1098
1099fn rewrite_fn_ptr(
1100 fn_ptr: &ast::FnPtrTy,
1101 span: Span,
1102 context: &RewriteContext<'_>,
1103 shape: Shape,
1104) -> RewriteResult {
1105 debug!("rewrite_bare_fn {:#?}", shape);
1106
1107 let mut result = String::with_capacity(128);
1108
1109 if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &fn_ptr.generic_params) {
1110 result.push_str("for<");
1111 result.push_str(lifetime_str);
1115 result.push_str("> ");
1116 }
1117
1118 result.push_str(crate::utils::format_safety(fn_ptr.safety));
1119
1120 result.push_str(&format_extern(
1121 fn_ptr.ext,
1122 context.config.force_explicit_abi(),
1123 ));
1124
1125 result.push_str("fn");
1126
1127 let func_ty_shape = if context.use_block_indent() {
1128 shape
1129 .offset_left(result.len())
1130 .max_width_error(shape.width, span)?
1131 } else {
1132 shape
1133 .visual_indent(result.len())
1134 .sub_width(result.len())
1135 .max_width_error(shape.width, span)?
1136 };
1137
1138 let rewrite = format_function_type(
1139 fn_ptr.decl.inputs.iter(),
1140 &fn_ptr.decl.output,
1141 fn_ptr.decl.c_variadic(),
1142 span,
1143 context,
1144 func_ty_shape,
1145 )?;
1146
1147 result.push_str(&rewrite);
1148
1149 Ok(result)
1150}
1151
1152fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
1153 let is_trait = |b: &ast::GenericBound| match b {
1154 ast::GenericBound::Outlives(..) => false,
1155 ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => true,
1156 };
1157 let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
1158 let last_trait_index = generic_bounds.iter().rposition(is_trait);
1159 let first_lifetime_index = generic_bounds.iter().position(is_lifetime);
1160 match (last_trait_index, first_lifetime_index) {
1161 (Some(last_trait_index), Some(first_lifetime_index)) => {
1162 last_trait_index < first_lifetime_index
1163 }
1164 _ => true,
1165 }
1166}
1167
1168fn join_bounds(
1169 context: &RewriteContext<'_>,
1170 shape: Shape,
1171 items: &[ast::GenericBound],
1172 need_indent: bool,
1173) -> RewriteResult {
1174 join_bounds_inner(context, shape, items, need_indent, false)
1175}
1176
1177fn join_bounds_inner(
1178 context: &RewriteContext<'_>,
1179 shape: Shape,
1180 items: &[ast::GenericBound],
1181 need_indent: bool,
1182 force_newline: bool,
1183) -> RewriteResult {
1184 debug_assert!(!items.is_empty());
1185
1186 let generic_bounds_in_order = is_generic_bounds_in_order(items);
1187 let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
1188 ast::GenericBound::Outlives(..) => true,
1189 ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => last_line_extendable(s),
1191 };
1192
1193 let is_item_with_multi_items_array = |item: &ast::GenericBound| match item {
1196 ast::GenericBound::Trait(ref poly_trait_ref, ..) => {
1197 let segments = &poly_trait_ref.trait_ref.path.segments;
1198 if segments.len() > 1 {
1199 true
1200 } else {
1201 if let Some(args_in) = &segments[0].args {
1202 matches!(
1203 args_in.deref(),
1204 ast::GenericArgs::AngleBracketed(bracket_args)
1205 if bracket_args.args.len() > 1
1206 )
1207 } else {
1208 false
1209 }
1210 }
1211 }
1212 ast::GenericBound::Use(args, _) => args.len() > 1,
1213 _ => false,
1214 };
1215
1216 let result = items.iter().enumerate().try_fold(
1217 (String::new(), None, false),
1218 |(strs, prev_trailing_span, prev_extendable), (i, item)| {
1219 let trailing_span = if i < items.len() - 1 {
1220 let hi = context
1221 .snippet_provider
1222 .span_before(mk_sp(items[i + 1].span().lo(), item.span().hi()), "+");
1223
1224 Some(mk_sp(item.span().hi(), hi))
1225 } else {
1226 None
1227 };
1228 let (leading_span, has_leading_comment) = if i > 0 {
1229 let lo = context
1230 .snippet_provider
1231 .span_after(mk_sp(items[i - 1].span().hi(), item.span().lo()), "+");
1232
1233 let span = mk_sp(lo, item.span().lo());
1234
1235 let has_comments = contains_comment(context.snippet(span));
1236
1237 (Some(mk_sp(lo, item.span().lo())), has_comments)
1238 } else {
1239 (None, false)
1240 };
1241 let prev_has_trailing_comment = match prev_trailing_span {
1242 Some(ts) => contains_comment(context.snippet(ts)),
1243 _ => false,
1244 };
1245
1246 let shape = if need_indent && force_newline {
1247 shape
1248 .block_indent(context.config.tab_spaces())
1249 .with_max_width(context.config)
1250 } else {
1251 shape
1252 };
1253 let whitespace = if force_newline && (!prev_extendable || !generic_bounds_in_order) {
1254 shape
1255 .indent
1256 .to_string_with_newline(context.config)
1257 .to_string()
1258 } else {
1259 String::from(" ")
1260 };
1261
1262 let joiner = match context.config.type_punctuation_density() {
1263 TypeDensity::Compressed => String::from("+"),
1264 TypeDensity::Wide => whitespace + "+ ",
1265 };
1266 let joiner = if has_leading_comment {
1267 joiner.trim_end()
1268 } else {
1269 &joiner
1270 };
1271 let joiner = if prev_has_trailing_comment {
1272 joiner.trim_start()
1273 } else {
1274 joiner
1275 };
1276
1277 let (extendable, trailing_str) = if i == 0 {
1278 let bound_str = item.rewrite_result(context, shape)?;
1279 (is_bound_extendable(&bound_str, item), bound_str)
1280 } else {
1281 let bound_str = &item.rewrite_result(context, shape)?;
1282 match leading_span {
1283 Some(ls) if has_leading_comment => (
1284 is_bound_extendable(bound_str, item),
1285 combine_strs_with_missing_comments(
1286 context, joiner, bound_str, ls, shape, true,
1287 )?,
1288 ),
1289 _ => (
1290 is_bound_extendable(bound_str, item),
1291 String::from(joiner) + bound_str,
1292 ),
1293 }
1294 };
1295 match prev_trailing_span {
1296 Some(ts) if prev_has_trailing_comment => combine_strs_with_missing_comments(
1297 context,
1298 &strs,
1299 &trailing_str,
1300 ts,
1301 shape,
1302 true,
1303 )
1304 .map(|v| (v, trailing_span, extendable)),
1305 _ => Ok((strs + &trailing_str, trailing_span, extendable)),
1306 }
1307 },
1308 )?;
1309
1310 let retry_with_force_newline = match context.config.style_edition() {
1316 style_edition @ _ if style_edition <= StyleEdition::Edition2021 => {
1317 !force_newline
1318 && items.len() > 1
1319 && (result.0.contains('\n') || result.0.len() > shape.width)
1320 }
1321 _ if force_newline => false,
1322 _ if (!result.0.contains('\n') && result.0.len() <= shape.width) => false,
1323 _ if items.len() > 1 => true,
1324 _ => is_item_with_multi_items_array(&items[0]),
1325 };
1326
1327 if retry_with_force_newline {
1328 join_bounds_inner(context, shape, items, need_indent, true)
1329 } else {
1330 Ok(result.0)
1331 }
1332}
1333
1334pub(crate) fn opaque_ty(ty: &Option<Box<ast::Ty>>) -> Option<&ast::GenericBounds> {
1335 ty.as_ref().and_then(|t| match &t.kind {
1336 ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
1337 _ => None,
1338 })
1339}
1340
1341pub(crate) fn can_be_overflowed_type(
1342 context: &RewriteContext<'_>,
1343 ty: &ast::Ty,
1344 len: usize,
1345) -> bool {
1346 match ty.kind {
1347 ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
1348 ast::TyKind::Ref(_, ref mutty)
1349 | ast::TyKind::PinnedRef(_, ref mutty)
1350 | ast::TyKind::Ptr(ref mutty) => can_be_overflowed_type(context, &*mutty.ty, len),
1351 _ => false,
1352 }
1353}
1354
1355pub(crate) fn rewrite_bound_params(
1357 context: &RewriteContext<'_>,
1358 shape: Shape,
1359 generic_params: &[ast::GenericParam],
1360) -> Option<String> {
1361 let result = generic_params
1362 .iter()
1363 .map(|param| param.rewrite(context, shape))
1364 .collect::<Option<Vec<_>>>()?
1365 .join(", ");
1366 if result.is_empty() {
1367 None
1368 } else {
1369 Some(result)
1370 }
1371}