1 use crate::pp
::Breaks
::Inconsistent
;
2 use crate::pprust
::state
::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT}
;
6 use rustc_ast
::util
::literal
::escape_byte_str_symbol
;
7 use rustc_ast
::util
::parser
::{self, AssocOp, Fixity}
;
8 use rustc_ast
::{self as ast, BlockCheckMode}
;
10 FormatAlignment
, FormatArgPosition
, FormatArgsPiece
, FormatCount
, FormatDebugHex
, FormatSign
,
16 fn print_else(&mut self, els
: Option
<&ast
::Expr
>) {
17 if let Some(_else
) = els
{
19 // Another `else if` block.
20 ast
::ExprKind
::If(i
, then
, e
) => {
21 self.cbox(INDENT_UNIT
- 1);
23 self.word(" else if ");
24 self.print_expr_as_cond(i
);
26 self.print_block(then
);
27 self.print_else(e
.as_deref())
29 // Final `else` block.
30 ast
::ExprKind
::Block(b
, _
) => {
31 self.cbox(INDENT_UNIT
- 1);
36 // Constraints would be great here!
38 panic
!("print_if saw if with weird alternative");
44 fn print_if(&mut self, test
: &ast
::Expr
, blk
: &ast
::Block
, elseopt
: Option
<&ast
::Expr
>) {
46 self.print_expr_as_cond(test
);
48 self.print_block(blk
);
49 self.print_else(elseopt
)
52 fn print_call_post(&mut self, args
: &[P
<ast
::Expr
>]) {
54 self.commasep_exprs(Inconsistent
, args
);
58 fn print_expr_maybe_paren(&mut self, expr
: &ast
::Expr
, prec
: i8) {
59 self.print_expr_cond_paren(expr
, expr
.precedence().order() < prec
)
62 /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
63 /// `if cond { ... }`.
64 fn print_expr_as_cond(&mut self, expr
: &ast
::Expr
) {
65 self.print_expr_cond_paren(expr
, Self::cond_needs_par(expr
))
68 /// Does `expr` need parentheses when printed in a condition position?
70 /// These cases need parens due to the parse error observed in #26461: `if return {}`
71 /// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
72 pub(super) fn cond_needs_par(expr
: &ast
::Expr
) -> bool
{
74 ast
::ExprKind
::Break(..)
75 | ast
::ExprKind
::Closure(..)
76 | ast
::ExprKind
::Ret(..)
77 | ast
::ExprKind
::Yeet(..) => true,
78 _
=> parser
::contains_exterior_struct_lit(expr
),
82 /// Prints `expr` or `(expr)` when `needs_par` holds.
83 pub(super) fn print_expr_cond_paren(&mut self, expr
: &ast
::Expr
, needs_par
: bool
) {
87 self.print_expr(expr
);
93 fn print_expr_vec(&mut self, exprs
: &[P
<ast
::Expr
>]) {
94 self.ibox(INDENT_UNIT
);
96 self.commasep_exprs(Inconsistent
, exprs
);
101 pub(super) fn print_expr_anon_const(
103 expr
: &ast
::AnonConst
,
104 attrs
: &[ast
::Attribute
],
106 self.ibox(INDENT_UNIT
);
109 if let ast
::ExprKind
::Block(block
, None
) = &expr
.value
.kind
{
112 self.print_block_with_attrs(block
, attrs
);
114 self.print_expr(&expr
.value
);
119 fn print_expr_repeat(&mut self, element
: &ast
::Expr
, count
: &ast
::AnonConst
) {
120 self.ibox(INDENT_UNIT
);
122 self.print_expr(element
);
123 self.word_space(";");
124 self.print_expr(&count
.value
);
129 fn print_expr_struct(
131 qself
: &Option
<P
<ast
::QSelf
>>,
133 fields
: &[ast
::ExprField
],
134 rest
: &ast
::StructRest
,
136 if let Some(qself
) = qself
{
137 self.print_qpath(path
, qself
, true);
139 self.print_path(path
, true, 0);
143 let has_rest
= match rest
{
144 ast
::StructRest
::Base(_
) | ast
::StructRest
::Rest(_
) => true,
145 ast
::StructRest
::None
=> false,
147 if fields
.is_empty() && !has_rest
{
152 for field
in fields
.iter().delimited() {
153 self.maybe_print_comment(field
.span
.hi());
154 self.print_outer_attributes(&field
.attrs
);
156 self.space_if_not_bol();
158 if !field
.is_shorthand
{
159 self.print_ident(field
.ident
);
162 self.print_expr(&field
.expr
);
163 if !field
.is_last
|| has_rest
{
164 self.word_space(",");
166 self.trailing_comma_or_space();
170 if fields
.is_empty() {
174 if let ast
::StructRest
::Base(expr
) = rest
{
175 self.print_expr(expr
);
179 self.offset(-INDENT_UNIT
);
184 fn print_expr_tup(&mut self, exprs
: &[P
<ast
::Expr
>]) {
186 self.commasep_exprs(Inconsistent
, exprs
);
187 if exprs
.len() == 1 {
193 fn print_expr_call(&mut self, func
: &ast
::Expr
, args
: &[P
<ast
::Expr
>]) {
194 let prec
= match func
.kind
{
195 ast
::ExprKind
::Field(..) => parser
::PREC_FORCE_PAREN
,
196 _
=> parser
::PREC_POSTFIX
,
199 self.print_expr_maybe_paren(func
, prec
);
200 self.print_call_post(args
)
203 fn print_expr_method_call(
205 segment
: &ast
::PathSegment
,
206 receiver
: &ast
::Expr
,
207 base_args
: &[P
<ast
::Expr
>],
209 self.print_expr_maybe_paren(receiver
, parser
::PREC_POSTFIX
);
211 self.print_ident(segment
.ident
);
212 if let Some(args
) = &segment
.args
{
213 self.print_generic_args(args
, true);
215 self.print_call_post(base_args
)
218 fn print_expr_binary(&mut self, op
: ast
::BinOp
, lhs
: &ast
::Expr
, rhs
: &ast
::Expr
) {
219 let assoc_op
= AssocOp
::from_ast_binop(op
.node
);
220 let prec
= assoc_op
.precedence() as i8;
221 let fixity
= assoc_op
.fixity();
223 let (left_prec
, right_prec
) = match fixity
{
224 Fixity
::Left
=> (prec
, prec
+ 1),
225 Fixity
::Right
=> (prec
+ 1, prec
),
226 Fixity
::None
=> (prec
+ 1, prec
+ 1),
229 let left_prec
= match (&lhs
.kind
, op
.node
) {
230 // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
231 // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
232 // of `(x as i32) < ...`. We need to convince it _not_ to do that.
233 (&ast
::ExprKind
::Cast { .. }
, ast
::BinOpKind
::Lt
| ast
::BinOpKind
::Shl
) => {
234 parser
::PREC_FORCE_PAREN
236 // We are given `(let _ = a) OP b`.
238 // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
239 // as the parser will interpret this as `(let _ = a) OP b`.
241 // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
242 // parens are required since the parser would interpret `let a = b < c` as
243 // `let a = (b < c)`. To achieve this, we force parens.
244 (&ast
::ExprKind
::Let { .. }
, _
) if !parser
::needs_par_as_let_scrutinee(prec
) => {
245 parser
::PREC_FORCE_PAREN
250 self.print_expr_maybe_paren(lhs
, left_prec
);
252 self.word_space(op
.node
.to_string());
253 self.print_expr_maybe_paren(rhs
, right_prec
)
256 fn print_expr_unary(&mut self, op
: ast
::UnOp
, expr
: &ast
::Expr
) {
257 self.word(ast
::UnOp
::to_string(op
));
258 self.print_expr_maybe_paren(expr
, parser
::PREC_PREFIX
)
261 fn print_expr_addr_of(
263 kind
: ast
::BorrowKind
,
264 mutability
: ast
::Mutability
,
269 ast
::BorrowKind
::Ref
=> self.print_mutability(mutability
, false),
270 ast
::BorrowKind
::Raw
=> {
271 self.word_nbsp("raw");
272 self.print_mutability(mutability
, true);
275 self.print_expr_maybe_paren(expr
, parser
::PREC_PREFIX
)
278 pub fn print_expr(&mut self, expr
: &ast
::Expr
) {
279 self.print_expr_outer_attr_style(expr
, true)
282 pub(super) fn print_expr_outer_attr_style(&mut self, expr
: &ast
::Expr
, is_inline
: bool
) {
283 self.maybe_print_comment(expr
.span
.lo());
285 let attrs
= &expr
.attrs
;
287 self.print_outer_attributes_inline(attrs
);
289 self.print_outer_attributes(attrs
);
292 self.ibox(INDENT_UNIT
);
293 self.ann
.pre(self, AnnNode
::Expr(expr
));
295 ast
::ExprKind
::Box(expr
) => {
296 self.word_space("box");
297 self.print_expr_maybe_paren(expr
, parser
::PREC_PREFIX
);
299 ast
::ExprKind
::Array(exprs
) => {
300 self.print_expr_vec(exprs
);
302 ast
::ExprKind
::ConstBlock(anon_const
) => {
303 self.print_expr_anon_const(anon_const
, attrs
);
305 ast
::ExprKind
::Repeat(element
, count
) => {
306 self.print_expr_repeat(element
, count
);
308 ast
::ExprKind
::Struct(se
) => {
309 self.print_expr_struct(&se
.qself
, &se
.path
, &se
.fields
, &se
.rest
);
311 ast
::ExprKind
::Tup(exprs
) => {
312 self.print_expr_tup(exprs
);
314 ast
::ExprKind
::Call(func
, args
) => {
315 self.print_expr_call(func
, args
);
317 ast
::ExprKind
::MethodCall(box ast
::MethodCall { seg, receiver, args, .. }
) => {
318 self.print_expr_method_call(seg
, receiver
, args
);
320 ast
::ExprKind
::Binary(op
, lhs
, rhs
) => {
321 self.print_expr_binary(*op
, lhs
, rhs
);
323 ast
::ExprKind
::Unary(op
, expr
) => {
324 self.print_expr_unary(*op
, expr
);
326 ast
::ExprKind
::AddrOf(k
, m
, expr
) => {
327 self.print_expr_addr_of(*k
, *m
, expr
);
329 ast
::ExprKind
::Lit(token_lit
) => {
330 self.print_token_literal(*token_lit
, expr
.span
);
332 ast
::ExprKind
::IncludedBytes(bytes
) => {
333 let lit
= token
::Lit
::new(token
::ByteStr
, escape_byte_str_symbol(bytes
), None
);
334 self.print_token_literal(lit
, expr
.span
)
336 ast
::ExprKind
::Cast(expr
, ty
) => {
337 let prec
= AssocOp
::As
.precedence() as i8;
338 self.print_expr_maybe_paren(expr
, prec
);
340 self.word_space("as");
343 ast
::ExprKind
::Type(expr
, ty
) => {
344 let prec
= AssocOp
::Colon
.precedence() as i8;
345 self.print_expr_maybe_paren(expr
, prec
);
346 self.word_space(":");
349 ast
::ExprKind
::Let(pat
, scrutinee
, _
) => {
350 self.print_let(pat
, scrutinee
);
352 ast
::ExprKind
::If(test
, blk
, elseopt
) => self.print_if(test
, blk
, elseopt
.as_deref()),
353 ast
::ExprKind
::While(test
, blk
, opt_label
) => {
354 if let Some(label
) = opt_label
{
355 self.print_ident(label
.ident
);
356 self.word_space(":");
360 self.word_nbsp("while");
361 self.print_expr_as_cond(test
);
363 self.print_block_with_attrs(blk
, attrs
);
365 ast
::ExprKind
::ForLoop(pat
, iter
, blk
, opt_label
) => {
366 if let Some(label
) = opt_label
{
367 self.print_ident(label
.ident
);
368 self.word_space(":");
372 self.word_nbsp("for");
375 self.word_space("in");
376 self.print_expr_as_cond(iter
);
378 self.print_block_with_attrs(blk
, attrs
);
380 ast
::ExprKind
::Loop(blk
, opt_label
, _
) => {
381 if let Some(label
) = opt_label
{
382 self.print_ident(label
.ident
);
383 self.word_space(":");
387 self.word_nbsp("loop");
388 self.print_block_with_attrs(blk
, attrs
);
390 ast
::ExprKind
::Match(expr
, arms
) => {
393 self.word_nbsp("match");
394 self.print_expr_as_cond(expr
);
397 self.print_inner_attributes_no_trailing_hardbreak(attrs
);
401 let empty
= attrs
.is_empty() && arms
.is_empty();
402 self.bclose(expr
.span
, empty
);
404 ast
::ExprKind
::Closure(box ast
::Closure
{
415 self.print_closure_binder(binder
);
416 self.print_constness(*constness
);
417 self.print_movability(*movability
);
418 self.print_asyncness(*asyncness
);
419 self.print_capture_clause(*capture_clause
);
421 self.print_fn_params_and_ret(fn_decl
, true);
423 self.print_expr(body
);
424 self.end(); // need to close a box
426 // a box will be closed by print_expr, but we didn't want an overall
427 // wrapper so we closed the corresponding opening. so create an
428 // empty box to satisfy the close.
431 ast
::ExprKind
::Block(blk
, opt_label
) => {
432 if let Some(label
) = opt_label
{
433 self.print_ident(label
.ident
);
434 self.word_space(":");
436 // containing cbox, will be closed by print-block at }
438 // head-box, will be closed by print-block after {
440 self.print_block_with_attrs(blk
, attrs
);
442 ast
::ExprKind
::Async(capture_clause
, _
, blk
) => {
443 self.word_nbsp("async");
444 self.print_capture_clause(*capture_clause
);
445 // cbox/ibox in analogy to the `ExprKind::Block` arm above
448 self.print_block_with_attrs(blk
, attrs
);
450 ast
::ExprKind
::Await(expr
) => {
451 self.print_expr_maybe_paren(expr
, parser
::PREC_POSTFIX
);
454 ast
::ExprKind
::Assign(lhs
, rhs
, _
) => {
455 let prec
= AssocOp
::Assign
.precedence() as i8;
456 self.print_expr_maybe_paren(lhs
, prec
+ 1);
458 self.word_space("=");
459 self.print_expr_maybe_paren(rhs
, prec
);
461 ast
::ExprKind
::AssignOp(op
, lhs
, rhs
) => {
462 let prec
= AssocOp
::Assign
.precedence() as i8;
463 self.print_expr_maybe_paren(lhs
, prec
+ 1);
465 self.word(op
.node
.to_string());
466 self.word_space("=");
467 self.print_expr_maybe_paren(rhs
, prec
);
469 ast
::ExprKind
::Field(expr
, ident
) => {
470 self.print_expr_maybe_paren(expr
, parser
::PREC_POSTFIX
);
472 self.print_ident(*ident
);
474 ast
::ExprKind
::Index(expr
, index
) => {
475 self.print_expr_maybe_paren(expr
, parser
::PREC_POSTFIX
);
477 self.print_expr(index
);
480 ast
::ExprKind
::Range(start
, end
, limits
) => {
481 // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
482 // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
483 // Here we use a fake precedence value so that any child with lower precedence than
484 // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
485 let fake_prec
= AssocOp
::LOr
.precedence() as i8;
486 if let Some(e
) = start
{
487 self.print_expr_maybe_paren(e
, fake_prec
);
490 ast
::RangeLimits
::HalfOpen
=> self.word(".."),
491 ast
::RangeLimits
::Closed
=> self.word("..="),
493 if let Some(e
) = end
{
494 self.print_expr_maybe_paren(e
, fake_prec
);
497 ast
::ExprKind
::Underscore
=> self.word("_"),
498 ast
::ExprKind
::Path(None
, path
) => self.print_path(path
, true, 0),
499 ast
::ExprKind
::Path(Some(qself
), path
) => self.print_qpath(path
, qself
, true),
500 ast
::ExprKind
::Break(opt_label
, opt_expr
) => {
502 if let Some(label
) = opt_label
{
504 self.print_ident(label
.ident
);
506 if let Some(expr
) = opt_expr
{
508 self.print_expr_maybe_paren(expr
, parser
::PREC_JUMP
);
511 ast
::ExprKind
::Continue(opt_label
) => {
512 self.word("continue");
513 if let Some(label
) = opt_label
{
515 self.print_ident(label
.ident
);
518 ast
::ExprKind
::Ret(result
) => {
520 if let Some(expr
) = result
{
522 self.print_expr_maybe_paren(expr
, parser
::PREC_JUMP
);
525 ast
::ExprKind
::Yeet(result
) => {
529 if let Some(expr
) = result
{
531 self.print_expr_maybe_paren(expr
, parser
::PREC_JUMP
);
534 ast
::ExprKind
::InlineAsm(a
) => {
535 // FIXME: This should have its own syntax, distinct from a macro invocation.
537 self.print_inline_asm(a
);
539 ast
::ExprKind
::FormatArgs(fmt
) => {
540 // FIXME: This should have its own syntax, distinct from a macro invocation.
541 self.word("format_args!");
543 self.rbox(0, Inconsistent
);
544 self.word(reconstruct_format_args_template_string(&fmt
.template
));
545 for arg
in fmt
.arguments
.all_args() {
546 self.word_space(",");
547 self.print_expr(&arg
.expr
);
552 ast
::ExprKind
::MacCall(m
) => self.print_mac(m
),
553 ast
::ExprKind
::Paren(e
) => {
558 ast
::ExprKind
::Yield(e
) => {
561 if let Some(expr
) = e
{
563 self.print_expr_maybe_paren(expr
, parser
::PREC_JUMP
);
566 ast
::ExprKind
::Try(e
) => {
567 self.print_expr_maybe_paren(e
, parser
::PREC_POSTFIX
);
570 ast
::ExprKind
::TryBlock(blk
) => {
573 self.word_nbsp("try");
574 self.print_block_with_attrs(blk
, attrs
)
576 ast
::ExprKind
::Err
=> {
578 self.word("/*ERROR*/");
582 self.ann
.post(self, AnnNode
::Expr(expr
));
586 fn print_arm(&mut self, arm
: &ast
::Arm
) {
587 // Note, I have no idea why this check is necessary, but here it is.
588 if arm
.attrs
.is_empty() {
591 self.cbox(INDENT_UNIT
);
593 self.maybe_print_comment(arm
.pat
.span
.lo());
594 self.print_outer_attributes(&arm
.attrs
);
595 self.print_pat(&arm
.pat
);
597 if let Some(e
) = &arm
.guard
{
598 self.word_space("if");
602 self.word_space("=>");
604 match &arm
.body
.kind
{
605 ast
::ExprKind
::Block(blk
, opt_label
) => {
606 if let Some(label
) = opt_label
{
607 self.print_ident(label
.ident
);
608 self.word_space(":");
611 // The block will close the pattern's ibox.
612 self.print_block_unclosed_indent(blk
);
614 // If it is a user-provided unsafe block, print a comma after it.
615 if let BlockCheckMode
::Unsafe(ast
::UserProvided
) = blk
.rules
{
620 self.end(); // Close the ibox for the pattern.
621 self.print_expr(&arm
.body
);
625 self.end(); // Close enclosing cbox.
628 fn print_closure_binder(&mut self, binder
: &ast
::ClosureBinder
) {
630 ast
::ClosureBinder
::NotPresent
=> {}
631 ast
::ClosureBinder
::For { generic_params, .. }
=> {
632 self.print_formal_generic_params(generic_params
)
637 fn print_movability(&mut self, movability
: ast
::Movability
) {
639 ast
::Movability
::Static
=> self.word_space("static"),
640 ast
::Movability
::Movable
=> {}
644 fn print_capture_clause(&mut self, capture_clause
: ast
::CaptureBy
) {
645 match capture_clause
{
646 ast
::CaptureBy
::Value
=> self.word_space("move"),
647 ast
::CaptureBy
::Ref
=> {}
652 pub fn reconstruct_format_args_template_string(pieces
: &[FormatArgsPiece
]) -> String
{
653 let mut template
= "\"".to_string();
654 for piece
in pieces
{
656 FormatArgsPiece
::Literal(s
) => {
657 for c
in s
.as_str().escape_debug() {
659 if let '{' | '}'
= c
{
664 FormatArgsPiece
::Placeholder(p
) => {
666 let (Ok(n
) | Err(n
)) = p
.argument
.index
;
667 write
!(template
, "{n}").unwrap();
668 if p
.format_options
!= Default
::default() || p
.format_trait
!= FormatTrait
::Display
670 template
.push_str(":");
672 if let Some(fill
) = p
.format_options
.fill
{
675 match p
.format_options
.alignment
{
676 Some(FormatAlignment
::Left
) => template
.push_str("<"),
677 Some(FormatAlignment
::Right
) => template
.push_str(">"),
678 Some(FormatAlignment
::Center
) => template
.push_str("^"),
681 match p
.format_options
.sign
{
682 Some(FormatSign
::Plus
) => template
.push('
+'
),
683 Some(FormatSign
::Minus
) => template
.push('
-'
),
686 if p
.format_options
.alternate
{
689 if p
.format_options
.zero_pad
{
692 if let Some(width
) = &p
.format_options
.width
{
694 FormatCount
::Literal(n
) => write
!(template
, "{n}").unwrap(),
695 FormatCount
::Argument(FormatArgPosition
{
696 index
: Ok(n
) | Err(n
), ..
698 write
!(template
, "{n}$").unwrap();
702 if let Some(precision
) = &p
.format_options
.precision
{
705 FormatCount
::Literal(n
) => write
!(template
, "{n}").unwrap(),
706 FormatCount
::Argument(FormatArgPosition
{
707 index
: Ok(n
) | Err(n
), ..
709 write
!(template
, "{n}$").unwrap();
713 match p
.format_options
.debug_hex
{
714 Some(FormatDebugHex
::Lower
) => template
.push('x'
),
715 Some(FormatDebugHex
::Upper
) => template
.push('X'
),
718 template
.push_str(match p
.format_trait
{
719 FormatTrait
::Display
=> "",
720 FormatTrait
::Debug
=> "?",
721 FormatTrait
::LowerExp
=> "e",
722 FormatTrait
::UpperExp
=> "E",
723 FormatTrait
::Octal
=> "o",
724 FormatTrait
::Pointer
=> "p",
725 FormatTrait
::Binary
=> "b",
726 FormatTrait
::LowerHex
=> "x",
727 FormatTrait
::UpperHex
=> "X",