Skip to main content

rustc_hir_pretty/
lib.rs

1//! HIR pretty-printing is layered on top of AST pretty-printing. A number of
2//! the definitions in this file have equivalents in `rustc_ast_pretty`.
3
4// tidy-alphabetical-start
5#![recursion_limit = "256"]
6// tidy-alphabetical-end
7
8use std::cell::Cell;
9use std::vec;
10
11use rustc_abi::ExternAbi;
12use rustc_ast as ast;
13use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
14use rustc_ast::{DUMMY_NODE_ID, DelimArgs};
15use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
16use rustc_ast_pretty::pp::{self, BoxMarker, Breaks};
17use rustc_ast_pretty::pprust::state::MacHeader;
18use rustc_ast_pretty::pprust::{Comments, PrintState};
19use rustc_hir as hir;
20use rustc_hir::attrs::{AttributeKind, PrintAttribute};
21use rustc_hir::{
22    BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound,
23    GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind,
24    PreciseCapturingArg, RangeEnd, Term, TyFieldPath, TyPatKind,
25};
26use rustc_span::source_map::SourceMap;
27use rustc_span::{DUMMY_SP, FileName, Ident, Span, Spanned, Symbol, kw, sym};
28
29pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String {
30    to_string(&cx, |s| s.print_node(cx.hir_node(hir_id)))
31}
32
33pub enum AnnNode<'a> {
34    Name(&'a Symbol),
35    Block(&'a hir::Block<'a>),
36    Item(&'a hir::Item<'a>),
37    SubItem(HirId),
38    Expr(&'a hir::Expr<'a>),
39    Pat(&'a hir::Pat<'a>),
40    TyPat(&'a hir::TyPat<'a>),
41    Arm(&'a hir::Arm<'a>),
42}
43
44pub enum Nested {
45    Item(hir::ItemId),
46    TraitItem(hir::TraitItemId),
47    ImplItem(hir::ImplItemId),
48    ForeignItem(hir::ForeignItemId),
49    Body(hir::BodyId),
50    BodyParamPat(hir::BodyId, usize),
51}
52
53pub trait PpAnn {
54    fn nested(&self, _state: &mut State<'_>, _nested: Nested) {}
55    fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
56    fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
57}
58
59impl PpAnn for &dyn rustc_hir::intravisit::HirTyCtxt<'_> {
60    fn nested(&self, state: &mut State<'_>, nested: Nested) {
61        match nested {
62            Nested::Item(id) => state.print_item(self.hir_item(id)),
63            Nested::TraitItem(id) => state.print_trait_item(self.hir_trait_item(id)),
64            Nested::ImplItem(id) => state.print_impl_item(self.hir_impl_item(id)),
65            Nested::ForeignItem(id) => state.print_foreign_item(self.hir_foreign_item(id)),
66            Nested::Body(id) => state.print_expr(self.hir_body(id).value),
67            Nested::BodyParamPat(id, i) => state.print_pat(self.hir_body(id).params[i].pat),
68        }
69    }
70}
71
72pub struct State<'a> {
73    pub s: pp::Printer,
74    comments: Option<Comments<'a>>,
75    attrs: &'a dyn Fn(HirId) -> &'a [hir::Attribute],
76    ann: &'a (dyn PpAnn + 'a),
77}
78
79impl<'a> State<'a> {
80    fn attrs(&self, id: HirId) -> &'a [hir::Attribute] {
81        (self.attrs)(id)
82    }
83
84    fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
85        let has_attr = |id: HirId| !self.attrs(id).is_empty();
86        expr.precedence(&has_attr)
87    }
88
89    fn print_attrs(&mut self, attrs: &[hir::Attribute]) {
90        if attrs.is_empty() {
91            return;
92        }
93
94        for attr in attrs {
95            self.print_attribute_as_style(attr, ast::AttrStyle::Outer);
96        }
97        self.hardbreak_if_not_bol();
98    }
99
100    /// Print a single attribute as if it has style `style`, disregarding the
101    /// actual style of the attribute.
102    fn print_attribute_as_style(&mut self, attr: &hir::Attribute, style: ast::AttrStyle) {
103        match &attr {
104            hir::Attribute::Unparsed(unparsed) => {
105                self.maybe_print_comment(unparsed.span.lo());
106                match style {
107                    ast::AttrStyle::Inner => self.word("#!["),
108                    ast::AttrStyle::Outer => self.word("#["),
109                }
110                self.print_attr_item(&unparsed, unparsed.span);
111                self.word("]");
112                self.hardbreak()
113            }
114            hir::Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
115                self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string(
116                    *kind, style, *comment,
117                ));
118                self.hardbreak()
119            }
120            hir::Attribute::Parsed(pa) => {
121                match style {
122                    ast::AttrStyle::Inner => self.word("#![attr = "),
123                    ast::AttrStyle::Outer => self.word("#[attr = "),
124                }
125                pa.print_attribute(self);
126                self.word("]");
127                self.hardbreak()
128            }
129        }
130    }
131
132    fn print_attr_item(&mut self, item: &hir::AttrItem, span: Span) {
133        let ib = self.ibox(0);
134        let path = ast::Path {
135            span,
136            segments: item
137                .path
138                .segments
139                .iter()
140                .map(|i| ast::PathSegment {
141                    ident: Ident { name: *i, span: DUMMY_SP },
142                    args: None,
143                    id: DUMMY_NODE_ID,
144                })
145                .collect(),
146        };
147
148        match &item.args {
149            hir::AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self
150                .print_mac_common(
151                    Some(MacHeader::Path(&path)),
152                    false,
153                    None,
154                    *delim,
155                    None,
156                    &tokens,
157                    true,
158                    span,
159                ),
160            hir::AttrArgs::Empty => {
161                PrintState::print_path(self, &path, false, 0);
162            }
163            hir::AttrArgs::Eq { eq_span: _, expr } => {
164                PrintState::print_path(self, &path, false, 0);
165                self.space();
166                self.word_space("=");
167                let token_str = self.meta_item_lit_to_string(expr);
168                self.word(token_str);
169            }
170        }
171        self.end(ib);
172    }
173
174    fn print_node(&mut self, node: Node<'_>) {
175        match node {
176            Node::Param(a) => self.print_param(a),
177            Node::Item(a) => self.print_item(a),
178            Node::ForeignItem(a) => self.print_foreign_item(a),
179            Node::TraitItem(a) => self.print_trait_item(a),
180            Node::ImplItem(a) => self.print_impl_item(a),
181            Node::Variant(a) => self.print_variant(a),
182            Node::AnonConst(a) => self.print_anon_const(a),
183            Node::ConstBlock(a) => self.print_inline_const(a),
184            Node::ConstArg(a) => self.print_const_arg(a),
185            Node::Expr(a) => self.print_expr(a),
186            Node::ExprField(a) => self.print_expr_field(a),
187            // FIXME(mgca): proper printing for struct exprs
188            Node::ConstArgExprField(_) => self.word("/* STRUCT EXPR */"),
189            Node::Stmt(a) => self.print_stmt(a),
190            Node::PathSegment(a) => self.print_path_segment(a),
191            Node::Ty(a) => self.print_type(a),
192            Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a),
193            Node::TraitRef(a) => self.print_trait_ref(a),
194            Node::OpaqueTy(_) => { ::core::panicking::panic_fmt(format_args!("cannot print Node::OpaqueTy")); }panic!("cannot print Node::OpaqueTy"),
195            Node::Pat(a) => self.print_pat(a),
196            Node::TyPat(a) => self.print_ty_pat(a),
197            Node::PatField(a) => self.print_patfield(a),
198            Node::PatExpr(a) => self.print_pat_expr(a),
199            Node::Arm(a) => self.print_arm(a),
200            Node::Infer(_) => self.word("_"),
201            Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
202            Node::Block(a) => {
203                // Containing cbox, will be closed by print-block at `}`.
204                let cb = self.cbox(INDENT_UNIT);
205                // Head-ibox, will be closed by print-block after `{`.
206                let ib = self.ibox(0);
207                self.print_block(a, cb, ib);
208            }
209            Node::Lifetime(a) => self.print_lifetime(a),
210            Node::GenericParam(_) => {
    ::core::panicking::panic_fmt(format_args!("cannot print Node::GenericParam"));
}panic!("cannot print Node::GenericParam"),
211            Node::Field(_) => { ::core::panicking::panic_fmt(format_args!("cannot print Node::Field")); }panic!("cannot print Node::Field"),
212            // These cases do not carry enough information in the
213            // `hir_map` to reconstruct their full structure for pretty
214            // printing.
215            Node::Ctor(..) => { ::core::panicking::panic_fmt(format_args!("cannot print isolated Ctor")); }panic!("cannot print isolated Ctor"),
216            Node::LetStmt(a) => self.print_local_decl(a),
217            Node::Crate(..) => { ::core::panicking::panic_fmt(format_args!("cannot print Crate")); }panic!("cannot print Crate"),
218            Node::WherePredicate(pred) => self.print_where_predicate(pred),
219            Node::Synthetic => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
220            Node::Err(_) => self.word("/*ERROR*/"),
221        }
222    }
223
224    fn print_generic_arg(&mut self, generic_arg: &GenericArg<'_>, elide_lifetimes: bool) {
225        match generic_arg {
226            GenericArg::Lifetime(lt) if !elide_lifetimes => self.print_lifetime(lt),
227            GenericArg::Lifetime(_) => {}
228            GenericArg::Type(ty) => self.print_type(ty.as_unambig_ty()),
229            GenericArg::Const(ct) => self.print_const_arg(ct.as_unambig_ct()),
230            GenericArg::Infer(_inf) => self.word("_"),
231        }
232    }
233}
234
235impl std::ops::Deref for State<'_> {
236    type Target = pp::Printer;
237    fn deref(&self) -> &Self::Target {
238        &self.s
239    }
240}
241
242impl std::ops::DerefMut for State<'_> {
243    fn deref_mut(&mut self) -> &mut Self::Target {
244        &mut self.s
245    }
246}
247
248impl<'a> PrintState<'a> for State<'a> {
249    fn comments(&self) -> Option<&Comments<'a>> {
250        self.comments.as_ref()
251    }
252
253    fn comments_mut(&mut self) -> Option<&mut Comments<'a>> {
254        self.comments.as_mut()
255    }
256
257    fn ann_post(&mut self, ident: Ident) {
258        self.ann.post(self, AnnNode::Name(&ident.name));
259    }
260
261    fn print_generic_args(&mut self, _: &ast::GenericArgs, _colons_before_params: bool) {
262        {
    ::core::panicking::panic_fmt(format_args!("AST generic args printed by HIR pretty-printer"));
};panic!("AST generic args printed by HIR pretty-printer");
263    }
264}
265
266const INDENT_UNIT: isize = 4;
267
268/// Requires you to pass an input filename and reader so that
269/// it can scan the input text for comments to copy forward.
270pub fn print_crate<'a>(
271    sm: &'a SourceMap,
272    krate: &hir::Mod<'_>,
273    filename: FileName,
274    input: String,
275    attrs: &'a dyn Fn(HirId) -> &'a [hir::Attribute],
276    ann: &'a dyn PpAnn,
277) -> String {
278    let mut s = State {
279        s: pp::Printer::new(),
280        comments: Some(Comments::new(sm, filename, input)),
281        attrs,
282        ann,
283    };
284
285    // Print all attributes, regardless of actual style, as inner attributes
286    // since this is the crate root with nothing above it to print outer
287    // attributes.
288    for attr in s.attrs(hir::CRATE_HIR_ID) {
289        s.print_attribute_as_style(attr, ast::AttrStyle::Inner);
290    }
291
292    // When printing the AST, we sometimes need to inject `#[no_std]` here.
293    // Since you can't compile the HIR, it's not necessary.
294
295    s.print_mod(krate);
296    s.print_remaining_comments();
297    s.s.eof()
298}
299
300fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
301where
302    F: FnOnce(&mut State<'_>),
303{
304    let mut printer = State { s: pp::Printer::new(), comments: None, attrs: &|_| &[], ann };
305    f(&mut printer);
306    printer.s.eof()
307}
308
309pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String {
310    to_string(ann, |s| s.print_attribute_as_style(attr, ast::AttrStyle::Outer))
311}
312
313pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String {
314    to_string(ann, |s| s.print_type(ty))
315}
316
317pub fn qpath_to_string(ann: &dyn PpAnn, segment: &hir::QPath<'_>) -> String {
318    to_string(ann, |s| s.print_qpath(segment, false))
319}
320
321pub fn pat_to_string(ann: &dyn PpAnn, pat: &hir::Pat<'_>) -> String {
322    to_string(ann, |s| s.print_pat(pat))
323}
324
325pub fn expr_to_string(ann: &dyn PpAnn, pat: &hir::Expr<'_>) -> String {
326    to_string(ann, |s| s.print_expr(pat))
327}
328
329pub fn item_to_string(ann: &dyn PpAnn, pat: &hir::Item<'_>) -> String {
330    to_string(ann, |s| s.print_item(pat))
331}
332
333impl<'a> State<'a> {
334    fn bclose_maybe_open(&mut self, span: rustc_span::Span, cb: Option<BoxMarker>) {
335        self.maybe_print_comment(span.hi());
336        self.break_offset_if_not_bol(1, -INDENT_UNIT);
337        self.word("}");
338        if let Some(cb) = cb {
339            self.end(cb);
340        }
341    }
342
343    fn bclose(&mut self, span: rustc_span::Span, cb: BoxMarker) {
344        self.bclose_maybe_open(span, Some(cb))
345    }
346
347    fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
348    where
349        F: FnMut(&mut State<'_>, &T),
350        G: FnMut(&T) -> rustc_span::Span,
351    {
352        let rb = self.rbox(0, b);
353        let len = elts.len();
354        let mut i = 0;
355        for elt in elts {
356            self.maybe_print_comment(get_span(elt).hi());
357            op(self, elt);
358            i += 1;
359            if i < len {
360                self.word(",");
361                self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
362                self.space_if_not_bol();
363            }
364        }
365        self.end(rb);
366    }
367
368    fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
369        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
370    }
371
372    fn print_mod(&mut self, _mod: &hir::Mod<'_>) {
373        for &item_id in _mod.item_ids {
374            self.ann.nested(self, Nested::Item(item_id));
375        }
376    }
377
378    fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
379        if !lifetime.is_elided() {
380            self.print_lifetime(lifetime);
381            self.nbsp();
382        }
383    }
384
385    fn print_type(&mut self, ty: &hir::Ty<'_>) {
386        self.maybe_print_comment(ty.span.lo());
387        let ib = self.ibox(0);
388        match ty.kind {
389            hir::TyKind::Slice(ty) => {
390                self.word("[");
391                self.print_type(ty);
392                self.word("]");
393            }
394            hir::TyKind::Ptr(ref mt) => {
395                self.word("*");
396                self.print_mt(mt, true);
397            }
398            hir::TyKind::Ref(lifetime, ref mt) => {
399                self.word("&");
400                self.print_opt_lifetime(lifetime);
401                self.print_mt(mt, false);
402            }
403            hir::TyKind::Never => {
404                self.word("!");
405            }
406            hir::TyKind::Tup(elts) => {
407                self.popen();
408                self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty));
409                if elts.len() == 1 {
410                    self.word(",");
411                }
412                self.pclose();
413            }
414            hir::TyKind::FnPtr(f) => {
415                self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_idents);
416            }
417            hir::TyKind::UnsafeBinder(unsafe_binder) => {
418                self.print_unsafe_binder(unsafe_binder);
419            }
420            hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
421            hir::TyKind::TraitAscription(bounds) => {
422                self.print_bounds("impl", bounds);
423            }
424            hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
425            hir::TyKind::TraitObject(bounds, lifetime) => {
426                let syntax = lifetime.tag();
427                match syntax {
428                    ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
429                    ast::TraitObjectSyntax::None => {}
430                }
431                let mut first = true;
432                for bound in bounds {
433                    if first {
434                        first = false;
435                    } else {
436                        self.nbsp();
437                        self.word_space("+");
438                    }
439                    self.print_poly_trait_ref(bound);
440                }
441                if !lifetime.is_elided() {
442                    self.nbsp();
443                    self.word_space("+");
444                    self.print_lifetime(lifetime.pointer());
445                }
446            }
447            hir::TyKind::Array(ty, ref length) => {
448                self.word("[");
449                self.print_type(ty);
450                self.word("; ");
451                self.print_const_arg(length);
452                self.word("]");
453            }
454            hir::TyKind::Err(_) => {
455                self.popen();
456                self.word("/*ERROR*/");
457                self.pclose();
458            }
459            hir::TyKind::Infer(()) | hir::TyKind::InferDelegation(..) => {
460                self.word("_");
461            }
462            hir::TyKind::Pat(ty, pat) => {
463                self.print_type(ty);
464                self.word(" is ");
465                self.print_ty_pat(pat);
466            }
467            hir::TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
468                self.word("field_of!(");
469                self.print_type(ty);
470                self.word(", ");
471                if let Some(variant) = *variant {
472                    self.print_ident(variant);
473                    self.word(".");
474                }
475                self.print_ident(*field);
476                self.word(")");
477            }
478            hir::TyKind::View(ty, fields) => {
479                self.word("view_type!(");
480                self.print_type(ty);
481                self.word(".{");
482                if !fields.is_empty() {
483                    self.space();
484                    self.commasep(Breaks::Inconsistent, fields, |s, f| s.print_ident(*f));
485                    self.space();
486                }
487                self.word("})");
488            }
489        }
490        self.end(ib)
491    }
492
493    fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
494        let ib = self.ibox(INDENT_UNIT);
495        self.word("unsafe");
496        self.print_generic_params(unsafe_binder.generic_params);
497        self.nbsp();
498        self.print_type(unsafe_binder.inner_ty);
499        self.end(ib);
500    }
501
502    fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
503        self.hardbreak_if_not_bol();
504        self.maybe_print_comment(item.span.lo());
505        self.print_attrs(self.attrs(item.hir_id()));
506        match item.kind {
507            hir::ForeignItemKind::Fn(sig, arg_idents, generics) => {
508                let (cb, ib) = self.head("");
509                self.print_fn(
510                    sig.header,
511                    Some(item.ident.name),
512                    generics,
513                    sig.decl,
514                    arg_idents,
515                    None,
516                );
517                self.end(ib);
518                self.word(";");
519                self.end(cb)
520            }
521            hir::ForeignItemKind::Static(t, m, safety) => {
522                self.print_safety(safety);
523                let (cb, ib) = self.head("static");
524                if m.is_mut() {
525                    self.word_space("mut");
526                }
527                self.print_ident(item.ident);
528                self.word_space(":");
529                self.print_type(t);
530                self.word(";");
531                self.end(ib);
532                self.end(cb)
533            }
534            hir::ForeignItemKind::Type => {
535                let (cb, ib) = self.head("type");
536                self.print_ident(item.ident);
537                self.word(";");
538                self.end(ib);
539                self.end(cb)
540            }
541        }
542    }
543
544    fn print_associated_const(
545        &mut self,
546        ident: Ident,
547        generics: &hir::Generics<'_>,
548        ty: &hir::Ty<'_>,
549        default: Option<hir::ConstItemRhs<'_>>,
550    ) {
551        self.word_space("const");
552        self.print_ident(ident);
553        self.print_generic_params(generics.params);
554        self.word_space(":");
555        self.print_type(ty);
556        if let Some(ct_rhs) = default {
557            self.space();
558            self.word_space("=");
559            self.print_const_item_rhs(ct_rhs);
560        }
561        self.print_where_clause(generics);
562        self.word(";")
563    }
564
565    fn print_associated_type(
566        &mut self,
567        ident: Ident,
568        generics: &hir::Generics<'_>,
569        bounds: Option<hir::GenericBounds<'_>>,
570        ty: Option<&hir::Ty<'_>>,
571    ) {
572        self.word_space("type");
573        self.print_ident(ident);
574        self.print_generic_params(generics.params);
575        if let Some(bounds) = bounds {
576            self.print_bounds(":", bounds);
577        }
578        self.print_where_clause(generics);
579        if let Some(ty) = ty {
580            self.space();
581            self.word_space("=");
582            self.print_type(ty);
583        }
584        self.word(";")
585    }
586
587    fn print_item(&mut self, item: &hir::Item<'_>) {
588        self.hardbreak_if_not_bol();
589        self.maybe_print_comment(item.span.lo());
590        let attrs = self.attrs(item.hir_id());
591        self.print_attrs(attrs);
592        self.ann.pre(self, AnnNode::Item(item));
593        match item.kind {
594            hir::ItemKind::ExternCrate(orig_name, ident) => {
595                let (cb, ib) = self.head("extern crate");
596                if let Some(orig_name) = orig_name {
597                    self.print_name(orig_name);
598                    self.space();
599                    self.word("as");
600                    self.space();
601                }
602                self.print_ident(ident);
603                self.word(";");
604                self.end(ib);
605                self.end(cb);
606            }
607            hir::ItemKind::Use(path, kind) => {
608                let (cb, ib) = self.head("use");
609                self.print_path(path, false);
610
611                match kind {
612                    hir::UseKind::Single(ident) => {
613                        if path.segments.last().unwrap().ident != ident {
614                            self.space();
615                            self.word_space("as");
616                            self.print_ident(ident);
617                        }
618                        self.word(";");
619                    }
620                    hir::UseKind::Glob => self.word("::*;"),
621                    hir::UseKind::ListStem => self.word("::{};"),
622                }
623                self.end(ib);
624                self.end(cb);
625            }
626            hir::ItemKind::Static(m, ident, ty, expr) => {
627                let (cb, ib) = self.head("static");
628                if m.is_mut() {
629                    self.word_space("mut");
630                }
631                self.print_ident(ident);
632                self.word_space(":");
633                self.print_type(ty);
634                self.space();
635                self.end(ib);
636
637                self.word_space("=");
638                self.ann.nested(self, Nested::Body(expr));
639                self.word(";");
640                self.end(cb);
641            }
642            hir::ItemKind::Const(ident, generics, ty, rhs) => {
643                let (cb, ib) = self.head("const");
644                self.print_ident(ident);
645                self.print_generic_params(generics.params);
646                self.word_space(":");
647                self.print_type(ty);
648                self.space();
649                self.end(ib);
650
651                self.word_space("=");
652                self.print_const_item_rhs(rhs);
653                self.print_where_clause(generics);
654                self.word(";");
655                self.end(cb);
656            }
657            hir::ItemKind::Fn { ident, sig, generics, body, .. } => {
658                let (cb, ib) = self.head("");
659                self.print_fn(sig.header, Some(ident.name), generics, sig.decl, &[], Some(body));
660                self.word(" ");
661                self.end(ib);
662                self.end(cb);
663                self.ann.nested(self, Nested::Body(body));
664            }
665            hir::ItemKind::Macro(ident, macro_def, _) => {
666                self.print_mac_def(macro_def, &ident, item.span, |_| {});
667            }
668            hir::ItemKind::Mod(ident, mod_) => {
669                let (cb, ib) = self.head("mod");
670                self.print_ident(ident);
671                self.nbsp();
672                self.bopen(ib);
673                self.print_mod(mod_);
674                self.bclose(item.span, cb);
675            }
676            hir::ItemKind::ForeignMod { abi, items } => {
677                let (cb, ib) = self.head("extern");
678                self.word_nbsp(abi.to_string());
679                self.bopen(ib);
680                for &foreign_item in items {
681                    self.ann.nested(self, Nested::ForeignItem(foreign_item));
682                }
683                self.bclose(item.span, cb);
684            }
685            hir::ItemKind::GlobalAsm { asm, .. } => {
686                let (cb, ib) = self.head("global_asm!");
687                self.print_inline_asm(asm);
688                self.word(";");
689                self.end(cb);
690                self.end(ib);
691            }
692            hir::ItemKind::TyAlias(ident, generics, ty) => {
693                let (cb, ib) = self.head("type");
694                self.print_ident(ident);
695                self.print_generic_params(generics.params);
696                self.end(ib);
697
698                self.print_where_clause(generics);
699                self.space();
700                self.word_space("=");
701                self.print_type(ty);
702                self.word(";");
703                self.end(cb);
704            }
705            hir::ItemKind::Enum(ident, generics, ref enum_def) => {
706                self.print_enum_def(ident.name, generics, enum_def, item.span);
707            }
708            hir::ItemKind::Struct(ident, generics, ref struct_def) => {
709                let (cb, ib) = self.head("struct");
710                self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
711            }
712            hir::ItemKind::Union(ident, generics, ref struct_def) => {
713                let (cb, ib) = self.head("union");
714                self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
715            }
716            hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items, constness }) => {
717                let (cb, ib) = self.head("");
718
719                let impl_generics = |this: &mut Self| {
720                    this.word_nbsp("impl");
721                    if !generics.params.is_empty() {
722                        this.print_generic_params(generics.params);
723                        this.space();
724                    }
725                };
726
727                match of_trait {
728                    None => {
729                        if let hir::Constness::Const { always: false } = constness {
730                            self.word_nbsp("const");
731                        }
732                        impl_generics(self)
733                    }
734                    Some(&hir::TraitImplHeader {
735                        safety,
736                        polarity,
737                        defaultness,
738                        defaultness_span: _,
739                        ref trait_ref,
740                    }) => {
741                        self.print_defaultness(defaultness);
742                        self.print_safety(safety);
743
744                        impl_generics(self);
745
746                        if let hir::Constness::Const { always: false } = constness {
747                            self.word_nbsp("const");
748                        }
749
750                        if let hir::ImplPolarity::Negative(_) = polarity {
751                            self.word("!");
752                        }
753
754                        self.print_trait_ref(trait_ref);
755                        self.space();
756                        self.word_space("for");
757                    }
758                }
759
760                self.print_type(self_ty);
761                self.print_where_clause(generics);
762
763                self.space();
764                self.bopen(ib);
765                for &impl_item in items {
766                    self.ann.nested(self, Nested::ImplItem(impl_item));
767                }
768                self.bclose(item.span, cb);
769            }
770            hir::ItemKind::Trait {
771                impl_restriction,
772                constness,
773                is_auto,
774                safety,
775                ident,
776                generics,
777                bounds,
778                items: trait_items,
779            } => {
780                let (cb, ib) = self.head("");
781                self.print_impl_restriction(impl_restriction);
782                self.print_constness(constness);
783                self.print_is_auto(is_auto);
784                self.print_safety(safety);
785                self.word_nbsp("trait");
786                self.print_ident(ident);
787                self.print_generic_params(generics.params);
788                self.print_bounds(":", bounds);
789                self.print_where_clause(generics);
790                self.word(" ");
791                self.bopen(ib);
792                for &trait_item in trait_items {
793                    self.ann.nested(self, Nested::TraitItem(trait_item));
794                }
795                self.bclose(item.span, cb);
796            }
797            hir::ItemKind::TraitAlias(constness, ident, generics, bounds) => {
798                let (cb, ib) = self.head("");
799                self.print_constness(constness);
800                self.word_nbsp("trait");
801                self.print_ident(ident);
802                self.print_generic_params(generics.params);
803                self.nbsp();
804                self.print_bounds("=", bounds);
805                self.print_where_clause(generics);
806                self.word(";");
807                self.end(ib);
808                self.end(cb);
809            }
810        }
811        self.ann.post(self, AnnNode::Item(item))
812    }
813
814    fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
815        self.print_path(t.path, false);
816    }
817
818    fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
819        if !generic_params.is_empty() {
820            self.word("for");
821            self.print_generic_params(generic_params);
822            self.nbsp();
823        }
824    }
825
826    fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
827        let hir::TraitBoundModifiers { constness, polarity } = t.modifiers;
828        match constness {
829            hir::BoundConstness::Never => {}
830            hir::BoundConstness::Always(_) => self.word("const"),
831            hir::BoundConstness::Maybe(_) => self.word("[const]"),
832        }
833        match polarity {
834            hir::BoundPolarity::Positive => {}
835            hir::BoundPolarity::Negative(_) => self.word("!"),
836            hir::BoundPolarity::Maybe(_) => self.word("?"),
837        }
838        self.print_formal_generic_params(t.bound_generic_params);
839        self.print_trait_ref(&t.trait_ref);
840    }
841
842    fn print_enum_def(
843        &mut self,
844        name: Symbol,
845        generics: &hir::Generics<'_>,
846        enum_def: &hir::EnumDef<'_>,
847        span: rustc_span::Span,
848    ) {
849        let (cb, ib) = self.head("enum");
850        self.print_name(name);
851        self.print_generic_params(generics.params);
852        self.print_where_clause(generics);
853        self.space();
854        self.print_variants(enum_def.variants, span, cb, ib);
855    }
856
857    fn print_variants(
858        &mut self,
859        variants: &[hir::Variant<'_>],
860        span: rustc_span::Span,
861        cb: BoxMarker,
862        ib: BoxMarker,
863    ) {
864        self.bopen(ib);
865        for v in variants {
866            self.space_if_not_bol();
867            self.maybe_print_comment(v.span.lo());
868            self.print_attrs(self.attrs(v.hir_id));
869            let ib = self.ibox(INDENT_UNIT);
870            self.print_variant(v);
871            self.word(",");
872            self.end(ib);
873            self.maybe_print_trailing_comment(v.span, None);
874        }
875        self.bclose(span, cb)
876    }
877
878    fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
879        match defaultness {
880            hir::Defaultness::Default { .. } => self.word_nbsp("default"),
881            hir::Defaultness::Final => (),
882        }
883    }
884
885    fn print_struct(
886        &mut self,
887        name: Symbol,
888        generics: &hir::Generics<'_>,
889        struct_def: &hir::VariantData<'_>,
890        span: rustc_span::Span,
891        print_finalizer: bool,
892        cb: BoxMarker,
893        ib: BoxMarker,
894    ) {
895        self.print_name(name);
896        self.print_generic_params(generics.params);
897        match struct_def {
898            hir::VariantData::Tuple(..) | hir::VariantData::Unit(..) => {
899                if let hir::VariantData::Tuple(..) = struct_def {
900                    self.popen();
901                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
902                        s.maybe_print_comment(field.span.lo());
903                        s.print_attrs(s.attrs(field.hir_id));
904                        s.print_mut_restriction(field.mut_restriction);
905                        s.print_type(field.ty);
906                    });
907                    self.pclose();
908                }
909                self.print_where_clause(generics);
910                if print_finalizer {
911                    self.word(";");
912                }
913                self.end(ib);
914                self.end(cb);
915            }
916            hir::VariantData::Struct { .. } => {
917                self.print_where_clause(generics);
918                self.nbsp();
919                self.bopen(ib);
920                self.hardbreak_if_not_bol();
921
922                for field in struct_def.fields() {
923                    self.hardbreak_if_not_bol();
924                    self.maybe_print_comment(field.span.lo());
925                    self.print_attrs(self.attrs(field.hir_id));
926                    self.print_mut_restriction(field.mut_restriction);
927                    self.print_ident(field.ident);
928                    self.word_nbsp(":");
929                    self.print_type(field.ty);
930                    self.word(",");
931                }
932
933                self.bclose(span, cb)
934            }
935        }
936    }
937
938    pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
939        let (cb, ib) = self.head("");
940        let generics = hir::Generics::empty();
941        self.print_struct(v.ident.name, generics, &v.data, v.span, false, cb, ib);
942        if let Some(ref d) = v.disr_expr {
943            self.space();
944            self.word_space("=");
945            self.print_anon_const(d);
946        }
947    }
948
949    fn print_method_sig(
950        &mut self,
951        ident: Ident,
952        m: &hir::FnSig<'_>,
953        generics: &hir::Generics<'_>,
954        arg_idents: &[Option<Ident>],
955        body_id: Option<hir::BodyId>,
956    ) {
957        self.print_fn(m.header, Some(ident.name), generics, m.decl, arg_idents, body_id);
958    }
959
960    fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
961        self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
962        self.hardbreak_if_not_bol();
963        self.maybe_print_comment(ti.span.lo());
964        self.print_attrs(self.attrs(ti.hir_id()));
965        match ti.kind {
966            hir::TraitItemKind::Const(ty, default) => {
967                self.print_associated_const(ti.ident, ti.generics, ty, default);
968            }
969            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_idents)) => {
970                self.print_method_sig(ti.ident, sig, ti.generics, arg_idents, None);
971                self.word(";");
972            }
973            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
974                let (cb, ib) = self.head("");
975                self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(body));
976                self.nbsp();
977                self.end(ib);
978                self.end(cb);
979                self.ann.nested(self, Nested::Body(body));
980            }
981            hir::TraitItemKind::Type(bounds, default) => {
982                self.print_associated_type(ti.ident, ti.generics, Some(bounds), default);
983            }
984        }
985        self.ann.post(self, AnnNode::SubItem(ti.hir_id()))
986    }
987
988    fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
989        self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
990        self.hardbreak_if_not_bol();
991        self.maybe_print_comment(ii.span.lo());
992        self.print_attrs(self.attrs(ii.hir_id()));
993
994        match ii.kind {
995            hir::ImplItemKind::Const(ty, expr) => {
996                self.print_associated_const(ii.ident, ii.generics, ty, Some(expr));
997            }
998            hir::ImplItemKind::Fn(ref sig, body) => {
999                let (cb, ib) = self.head("");
1000                self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(body));
1001                self.nbsp();
1002                self.end(ib);
1003                self.end(cb);
1004                self.ann.nested(self, Nested::Body(body));
1005            }
1006            hir::ImplItemKind::Type(ty) => {
1007                self.print_associated_type(ii.ident, ii.generics, None, Some(ty));
1008            }
1009        }
1010        self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
1011    }
1012
1013    fn print_local(
1014        &mut self,
1015        super_: bool,
1016        init: Option<&hir::Expr<'_>>,
1017        els: Option<&hir::Block<'_>>,
1018        decl: impl Fn(&mut Self),
1019    ) {
1020        self.space_if_not_bol();
1021        let ibm1 = self.ibox(INDENT_UNIT);
1022        if super_ {
1023            self.word_nbsp("super");
1024        }
1025        self.word_nbsp("let");
1026
1027        let ibm2 = self.ibox(INDENT_UNIT);
1028        decl(self);
1029        self.end(ibm2);
1030
1031        if let Some(init) = init {
1032            self.nbsp();
1033            self.word_space("=");
1034            self.print_expr(init);
1035        }
1036
1037        if let Some(els) = els {
1038            self.nbsp();
1039            self.word_space("else");
1040            // containing cbox, will be closed by print-block at `}`
1041            let cb = self.cbox(0);
1042            // head-box, will be closed by print-block after `{`
1043            let ib = self.ibox(0);
1044            self.print_block(els, cb, ib);
1045        }
1046
1047        self.end(ibm1)
1048    }
1049
1050    fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
1051        self.maybe_print_comment(st.span.lo());
1052        match st.kind {
1053            hir::StmtKind::Let(loc) => {
1054                self.print_local(loc.super_.is_some(), loc.init, loc.els, |this| {
1055                    this.print_local_decl(loc)
1056                });
1057            }
1058            hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
1059            hir::StmtKind::Expr(expr) => {
1060                self.space_if_not_bol();
1061                self.print_expr(expr);
1062            }
1063            hir::StmtKind::Semi(expr) => {
1064                self.space_if_not_bol();
1065                self.print_expr(expr);
1066                self.word(";");
1067            }
1068        }
1069        if stmt_ends_with_semi(&st.kind) {
1070            self.word(";");
1071        }
1072        self.maybe_print_trailing_comment(st.span, None)
1073    }
1074
1075    fn print_block(&mut self, blk: &hir::Block<'_>, cb: BoxMarker, ib: BoxMarker) {
1076        self.print_block_maybe_unclosed(blk, Some(cb), ib)
1077    }
1078
1079    fn print_block_unclosed(&mut self, blk: &hir::Block<'_>, ib: BoxMarker) {
1080        self.print_block_maybe_unclosed(blk, None, ib)
1081    }
1082
1083    fn print_block_maybe_unclosed(
1084        &mut self,
1085        blk: &hir::Block<'_>,
1086        cb: Option<BoxMarker>,
1087        ib: BoxMarker,
1088    ) {
1089        match blk.rules {
1090            hir::BlockCheckMode::UnsafeBlock(..) => self.word_space("unsafe"),
1091            hir::BlockCheckMode::DefaultBlock => (),
1092        }
1093        self.maybe_print_comment(blk.span.lo());
1094        self.ann.pre(self, AnnNode::Block(blk));
1095        self.bopen(ib);
1096
1097        for st in blk.stmts {
1098            self.print_stmt(st);
1099        }
1100        if let Some(expr) = blk.expr {
1101            self.space_if_not_bol();
1102            self.print_expr(expr);
1103            self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
1104        }
1105        self.bclose_maybe_open(blk.span, cb);
1106        self.ann.post(self, AnnNode::Block(blk))
1107    }
1108
1109    fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
1110        if let Some(els_inner) = els {
1111            match els_inner.kind {
1112                // Another `else if` block.
1113                hir::ExprKind::If(i, hir::Expr { kind: hir::ExprKind::Block(t, None), .. }, e) => {
1114                    let cb = self.cbox(0);
1115                    let ib = self.ibox(0);
1116                    self.word(" else if ");
1117                    self.print_expr_as_cond(i);
1118                    self.space();
1119                    self.print_block(t, cb, ib);
1120                    self.print_else(e);
1121                }
1122                // Final `else` block.
1123                hir::ExprKind::Block(b, None) => {
1124                    let cb = self.cbox(0);
1125                    let ib = self.ibox(0);
1126                    self.word(" else ");
1127                    self.print_block(b, cb, ib);
1128                }
1129                // Constraints would be great here!
1130                _ => {
1131                    {
    ::core::panicking::panic_fmt(format_args!("print_if saw if with weird alternative"));
};panic!("print_if saw if with weird alternative");
1132                }
1133            }
1134        }
1135    }
1136
1137    fn print_if(
1138        &mut self,
1139        test: &hir::Expr<'_>,
1140        blk: &hir::Expr<'_>,
1141        elseopt: Option<&hir::Expr<'_>>,
1142    ) {
1143        match blk.kind {
1144            hir::ExprKind::Block(blk, None) => {
1145                let cb = self.cbox(0);
1146                let ib = self.ibox(0);
1147                self.word_nbsp("if");
1148                self.print_expr_as_cond(test);
1149                self.space();
1150                self.print_block(blk, cb, ib);
1151                self.print_else(elseopt)
1152            }
1153            _ => { ::core::panicking::panic_fmt(format_args!("non-block then expr")); }panic!("non-block then expr"),
1154        }
1155    }
1156
1157    fn print_anon_const(&mut self, constant: &hir::AnonConst) {
1158        self.ann.nested(self, Nested::Body(constant.body))
1159    }
1160
1161    fn print_const_item_rhs(&mut self, ct_rhs: hir::ConstItemRhs<'_>) {
1162        match ct_rhs {
1163            hir::ConstItemRhs::Body(body_id) => self.ann.nested(self, Nested::Body(body_id)),
1164            hir::ConstItemRhs::TypeConst(const_arg) => self.print_const_arg(const_arg),
1165        }
1166    }
1167
1168    fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
1169        match &const_arg.kind {
1170            ConstArgKind::Tup(exprs) => {
1171                self.popen();
1172                self.commasep_cmnt(
1173                    Inconsistent,
1174                    exprs,
1175                    |s, arg| s.print_const_arg(arg),
1176                    |arg| arg.span,
1177                );
1178                self.pclose();
1179            }
1180            ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields),
1181            ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args),
1182            ConstArgKind::Array(..) => self.word("/* ARRAY EXPR */"),
1183            ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
1184            ConstArgKind::Anon(anon) => self.print_anon_const(anon),
1185            ConstArgKind::Error(_) => self.word("/*ERROR*/"),
1186            ConstArgKind::Infer(..) => self.word("_"),
1187            ConstArgKind::Literal { lit, negated } => {
1188                if *negated {
1189                    self.word("-");
1190                }
1191                let span = const_arg.span;
1192                self.print_literal(&Spanned { span, node: *lit })
1193            }
1194        }
1195    }
1196
1197    fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) {
1198        self.print_qpath(qpath, true);
1199        self.word(" ");
1200        self.word("{");
1201        if !fields.is_empty() {
1202            self.nbsp();
1203        }
1204        self.commasep(Inconsistent, *fields, |s, field| {
1205            s.word(field.field.as_str().to_string());
1206            s.word(":");
1207            s.nbsp();
1208            s.print_const_arg(field.expr);
1209        });
1210        self.word("}");
1211    }
1212
1213    fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) {
1214        self.print_qpath(qpath, true);
1215        self.word("(");
1216        self.commasep(Inconsistent, *args, |s, arg| {
1217            s.print_const_arg(arg);
1218        });
1219        self.word(")");
1220    }
1221
1222    fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
1223        self.popen();
1224        self.commasep_exprs(Inconsistent, args);
1225        self.pclose()
1226    }
1227
1228    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
1229    /// `if cond { ... }`.
1230    fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
1231        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
1232    }
1233
1234    /// Prints `expr` or `(expr)` when `needs_par` holds.
1235    fn print_expr_cond_paren(&mut self, expr: &hir::Expr<'_>, needs_par: bool) {
1236        if needs_par {
1237            self.popen();
1238        }
1239        if let hir::ExprKind::DropTemps(actual_expr) = expr.kind {
1240            self.print_expr(actual_expr);
1241        } else {
1242            self.print_expr(expr);
1243        }
1244        if needs_par {
1245            self.pclose();
1246        }
1247    }
1248
1249    /// Print a `let pat = expr` expression.
1250    fn print_let(&mut self, pat: &hir::Pat<'_>, ty: Option<&hir::Ty<'_>>, init: &hir::Expr<'_>) {
1251        self.word_space("let");
1252        self.print_pat(pat);
1253        if let Some(ty) = ty {
1254            self.word_space(":");
1255            self.print_type(ty);
1256        }
1257        self.space();
1258        self.word_space("=");
1259        let npals = || parser::needs_par_as_let_scrutinee(self.precedence(init));
1260        self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
1261    }
1262
1263    // Does `expr` need parentheses when printed in a condition position?
1264    //
1265    // These cases need parens due to the parse error observed in #26461: `if return {}`
1266    // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
1267    fn cond_needs_par(expr: &hir::Expr<'_>) -> bool {
1268        match expr.kind {
1269            hir::ExprKind::Break(..) | hir::ExprKind::Closure { .. } | hir::ExprKind::Ret(..) => {
1270                true
1271            }
1272            _ => contains_exterior_struct_lit(expr),
1273        }
1274    }
1275
1276    fn print_expr_vec(&mut self, exprs: &[hir::Expr<'_>]) {
1277        let ib = self.ibox(INDENT_UNIT);
1278        self.word("[");
1279        self.commasep_exprs(Inconsistent, exprs);
1280        self.word("]");
1281        self.end(ib)
1282    }
1283
1284    fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
1285        let ib = self.ibox(INDENT_UNIT);
1286        self.word_space("const");
1287        self.ann.nested(self, Nested::Body(constant.body));
1288        self.end(ib)
1289    }
1290
1291    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ConstArg<'_>) {
1292        let ib = self.ibox(INDENT_UNIT);
1293        self.word("[");
1294        self.print_expr(element);
1295        self.word_space(";");
1296        self.print_const_arg(count);
1297        self.word("]");
1298        self.end(ib)
1299    }
1300
1301    fn print_expr_struct(
1302        &mut self,
1303        qpath: &hir::QPath<'_>,
1304        fields: &[hir::ExprField<'_>],
1305        wth: hir::StructTailExpr<'_>,
1306    ) {
1307        self.print_qpath(qpath, true);
1308        self.nbsp();
1309        self.word_space("{");
1310        self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span);
1311        match wth {
1312            hir::StructTailExpr::Base(expr) => {
1313                let ib = self.ibox(INDENT_UNIT);
1314                if !fields.is_empty() {
1315                    self.word(",");
1316                    self.space();
1317                }
1318                self.word("..");
1319                self.print_expr(expr);
1320                self.end(ib);
1321            }
1322            hir::StructTailExpr::DefaultFields(_) => {
1323                let ib = self.ibox(INDENT_UNIT);
1324                if !fields.is_empty() {
1325                    self.word(",");
1326                    self.space();
1327                }
1328                self.word("..");
1329                self.end(ib);
1330            }
1331            hir::StructTailExpr::None => {}
1332            hir::StructTailExpr::NoneWithError(_) => {}
1333        }
1334        self.space();
1335        self.word("}");
1336    }
1337
1338    fn print_expr_field(&mut self, field: &hir::ExprField<'_>) {
1339        let cb = self.cbox(INDENT_UNIT);
1340        self.print_attrs(self.attrs(field.hir_id));
1341        if !field.is_shorthand {
1342            self.print_ident(field.ident);
1343            self.word_space(":");
1344        }
1345        self.print_expr(field.expr);
1346        self.end(cb)
1347    }
1348
1349    fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) {
1350        self.popen();
1351        self.commasep_exprs(Inconsistent, exprs);
1352        if exprs.len() == 1 {
1353            self.word(",");
1354        }
1355        self.pclose()
1356    }
1357
1358    fn print_expr_call(&mut self, func: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
1359        let needs_paren = match func.kind {
1360            hir::ExprKind::Field(..) => true,
1361            _ => self.precedence(func) < ExprPrecedence::Unambiguous,
1362        };
1363
1364        self.print_expr_cond_paren(func, needs_paren);
1365        self.print_call_post(args)
1366    }
1367
1368    fn print_expr_method_call(
1369        &mut self,
1370        segment: &hir::PathSegment<'_>,
1371        receiver: &hir::Expr<'_>,
1372        args: &[hir::Expr<'_>],
1373    ) {
1374        let base_args = args;
1375        self.print_expr_cond_paren(
1376            receiver,
1377            self.precedence(receiver) < ExprPrecedence::Unambiguous,
1378        );
1379        self.word(".");
1380        self.print_ident(segment.ident);
1381
1382        let generic_args = segment.args();
1383        if !generic_args.args.is_empty() || !generic_args.constraints.is_empty() {
1384            self.print_generic_args(generic_args, true);
1385        }
1386
1387        self.print_call_post(base_args)
1388    }
1389
1390    fn print_expr_binary(&mut self, op: hir::BinOpKind, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
1391        let binop_prec = op.precedence();
1392        let left_prec = self.precedence(lhs);
1393        let right_prec = self.precedence(rhs);
1394
1395        let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
1396            Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
1397            Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
1398            Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
1399        };
1400
1401        match (&lhs.kind, op) {
1402            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
1403            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
1404            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
1405            (&hir::ExprKind::Cast { .. }, hir::BinOpKind::Lt | hir::BinOpKind::Shl) => {
1406                left_needs_paren = true;
1407            }
1408            (&hir::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(binop_prec) => {
1409                left_needs_paren = true;
1410            }
1411            _ => {}
1412        }
1413
1414        self.print_expr_cond_paren(lhs, left_needs_paren);
1415        self.space();
1416        self.word_space(op.as_str());
1417        self.print_expr_cond_paren(rhs, right_needs_paren);
1418    }
1419
1420    fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr<'_>) {
1421        self.word(op.as_str());
1422        self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
1423    }
1424
1425    fn print_expr_addr_of(
1426        &mut self,
1427        kind: hir::BorrowKind,
1428        mutability: hir::Mutability,
1429        expr: &hir::Expr<'_>,
1430    ) {
1431        self.word("&");
1432        match kind {
1433            hir::BorrowKind::Ref => self.print_mutability(mutability, false),
1434            hir::BorrowKind::Raw => {
1435                self.word_nbsp("raw");
1436                self.print_mutability(mutability, true);
1437            }
1438            hir::BorrowKind::Pin => {
1439                self.word_nbsp("pin");
1440                self.print_mutability(mutability, true);
1441            }
1442        }
1443        self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
1444    }
1445
1446    fn print_literal(&mut self, lit: &hir::Lit) {
1447        self.maybe_print_comment(lit.span.lo());
1448        self.word(lit.node.to_string())
1449    }
1450
1451    fn print_inline_asm(&mut self, asm: &hir::InlineAsm<'_>) {
1452        enum AsmArg<'a> {
1453            Template(String),
1454            Operand(&'a hir::InlineAsmOperand<'a>),
1455            Options(ast::InlineAsmOptions),
1456        }
1457
1458        let mut args = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(asm.template))]))vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(asm.template))];
1459        args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
1460        if !asm.options.is_empty() {
1461            args.push(AsmArg::Options(asm.options));
1462        }
1463
1464        self.popen();
1465        self.commasep(Consistent, &args, |s, arg| match *arg {
1466            AsmArg::Template(ref template) => s.print_string(template, ast::StrStyle::Cooked),
1467            AsmArg::Operand(op) => match *op {
1468                hir::InlineAsmOperand::In { reg, expr } => {
1469                    s.word("in");
1470                    s.popen();
1471                    s.word(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", reg))
    })format!("{reg}"));
1472                    s.pclose();
1473                    s.space();
1474                    s.print_expr(expr);
1475                }
1476                hir::InlineAsmOperand::Out { reg, late, ref expr } => {
1477                    s.word(if late { "lateout" } else { "out" });
1478                    s.popen();
1479                    s.word(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", reg))
    })format!("{reg}"));
1480                    s.pclose();
1481                    s.space();
1482                    match expr {
1483                        Some(expr) => s.print_expr(expr),
1484                        None => s.word("_"),
1485                    }
1486                }
1487                hir::InlineAsmOperand::InOut { reg, late, expr } => {
1488                    s.word(if late { "inlateout" } else { "inout" });
1489                    s.popen();
1490                    s.word(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", reg))
    })format!("{reg}"));
1491                    s.pclose();
1492                    s.space();
1493                    s.print_expr(expr);
1494                }
1495                hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, ref out_expr } => {
1496                    s.word(if late { "inlateout" } else { "inout" });
1497                    s.popen();
1498                    s.word(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", reg))
    })format!("{reg}"));
1499                    s.pclose();
1500                    s.space();
1501                    s.print_expr(in_expr);
1502                    s.space();
1503                    s.word_space("=>");
1504                    match out_expr {
1505                        Some(out_expr) => s.print_expr(out_expr),
1506                        None => s.word("_"),
1507                    }
1508                }
1509                hir::InlineAsmOperand::Const { ref anon_const } => {
1510                    s.word("const");
1511                    s.space();
1512                    // Not using `print_inline_const` to avoid additional `const { ... }`
1513                    s.ann.nested(s, Nested::Body(anon_const.body))
1514                }
1515                hir::InlineAsmOperand::SymFn { ref expr } => {
1516                    s.word("sym_fn");
1517                    s.space();
1518                    s.print_expr(expr);
1519                }
1520                hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
1521                    s.word("sym_static");
1522                    s.space();
1523                    s.print_qpath(path, true);
1524                }
1525                hir::InlineAsmOperand::Label { block } => {
1526                    let (cb, ib) = s.head("label");
1527                    s.print_block(block, cb, ib);
1528                }
1529            },
1530            AsmArg::Options(opts) => {
1531                s.word("options");
1532                s.popen();
1533                s.commasep(Inconsistent, &opts.human_readable_names(), |s, &opt| {
1534                    s.word(opt);
1535                });
1536                s.pclose();
1537            }
1538        });
1539        self.pclose();
1540    }
1541
1542    fn print_expr(&mut self, expr: &hir::Expr<'_>) {
1543        self.maybe_print_comment(expr.span.lo());
1544        self.print_attrs(self.attrs(expr.hir_id));
1545        let ib = self.ibox(INDENT_UNIT);
1546        self.ann.pre(self, AnnNode::Expr(expr));
1547        match expr.kind {
1548            hir::ExprKind::Array(exprs) => {
1549                self.print_expr_vec(exprs);
1550            }
1551            hir::ExprKind::ConstBlock(ref anon_const) => {
1552                self.print_inline_const(anon_const);
1553            }
1554            hir::ExprKind::Repeat(element, ref count) => {
1555                self.print_expr_repeat(element, count);
1556            }
1557            hir::ExprKind::Struct(qpath, fields, wth) => {
1558                self.print_expr_struct(qpath, fields, wth);
1559            }
1560            hir::ExprKind::Tup(exprs) => {
1561                self.print_expr_tup(exprs);
1562            }
1563            hir::ExprKind::Call(func, args) => {
1564                self.print_expr_call(func, args);
1565            }
1566            hir::ExprKind::MethodCall(segment, receiver, args, _) => {
1567                self.print_expr_method_call(segment, receiver, args);
1568            }
1569            hir::ExprKind::Use(expr, _) => {
1570                self.print_expr(expr);
1571                self.word(".use");
1572            }
1573            hir::ExprKind::Binary(op, lhs, rhs) => {
1574                self.print_expr_binary(op.node, lhs, rhs);
1575            }
1576            hir::ExprKind::Unary(op, expr) => {
1577                self.print_expr_unary(op, expr);
1578            }
1579            hir::ExprKind::AddrOf(k, m, expr) => {
1580                self.print_expr_addr_of(k, m, expr);
1581            }
1582            hir::ExprKind::Lit(lit) => {
1583                self.print_literal(&lit);
1584            }
1585            hir::ExprKind::Cast(expr, ty) => {
1586                self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Cast);
1587                self.space();
1588                self.word_space("as");
1589                self.print_type(ty);
1590            }
1591            hir::ExprKind::Type(expr, ty) => {
1592                self.word("type_ascribe!(");
1593                let ib = self.ibox(0);
1594                self.print_expr(expr);
1595
1596                self.word(",");
1597                self.space_if_not_bol();
1598                self.print_type(ty);
1599
1600                self.end(ib);
1601                self.word(")");
1602            }
1603            hir::ExprKind::DropTemps(init) => {
1604                // Print `{`:
1605                let cb = self.cbox(0);
1606                let ib = self.ibox(0);
1607                self.bopen(ib);
1608
1609                // Print `let _t = $init;`:
1610                let temp = Ident::with_dummy_span(sym::_t);
1611                self.print_local(false, Some(init), None, |this| this.print_ident(temp));
1612                self.word(";");
1613
1614                // Print `_t`:
1615                self.space_if_not_bol();
1616                self.print_ident(temp);
1617
1618                // Print `}`:
1619                self.bclose_maybe_open(expr.span, Some(cb));
1620            }
1621            hir::ExprKind::Let(&hir::LetExpr { pat, ty, init, .. }) => {
1622                self.print_let(pat, ty, init);
1623            }
1624            hir::ExprKind::If(test, blk, elseopt) => {
1625                self.print_if(test, blk, elseopt);
1626            }
1627            hir::ExprKind::Loop(blk, opt_label, _, _) => {
1628                let cb = self.cbox(0);
1629                let ib = self.ibox(0);
1630                if let Some(label) = opt_label {
1631                    self.print_ident(label.ident);
1632                    self.word_space(":");
1633                }
1634                self.word_nbsp("loop");
1635                self.print_block(blk, cb, ib);
1636            }
1637            hir::ExprKind::Match(expr, arms, _) => {
1638                let cb = self.cbox(0);
1639                let ib = self.ibox(0);
1640                self.word_nbsp("match");
1641                self.print_expr_as_cond(expr);
1642                self.space();
1643                self.bopen(ib);
1644                for arm in arms {
1645                    self.print_arm(arm);
1646                }
1647                self.bclose(expr.span, cb);
1648            }
1649            hir::ExprKind::Closure(&hir::Closure {
1650                binder,
1651                constness,
1652                capture_clause,
1653                bound_generic_params,
1654                fn_decl,
1655                body,
1656                fn_decl_span: _,
1657                fn_arg_span: _,
1658                kind: _,
1659                def_id: _,
1660                explicit_captures: _,
1661            }) => {
1662                self.print_closure_binder(binder, bound_generic_params);
1663                self.print_constness(constness);
1664                self.print_capture_clause(capture_clause);
1665
1666                self.print_closure_params(fn_decl, body);
1667                self.space();
1668
1669                // This is a bare expression.
1670                self.ann.nested(self, Nested::Body(body));
1671            }
1672            hir::ExprKind::Block(blk, opt_label) => {
1673                if let Some(label) = opt_label {
1674                    self.print_ident(label.ident);
1675                    self.word_space(":");
1676                }
1677                // containing cbox, will be closed by print-block at `}`
1678                let cb = self.cbox(0);
1679                // head-box, will be closed by print-block after `{`
1680                let ib = self.ibox(0);
1681                self.print_block(blk, cb, ib);
1682            }
1683            hir::ExprKind::Assign(lhs, rhs, _) => {
1684                self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign);
1685                self.space();
1686                self.word_space("=");
1687                self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign);
1688            }
1689            hir::ExprKind::AssignOp(op, lhs, rhs) => {
1690                self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign);
1691                self.space();
1692                self.word_space(op.node.as_str());
1693                self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign);
1694            }
1695            hir::ExprKind::Field(expr, ident) => {
1696                self.print_expr_cond_paren(
1697                    expr,
1698                    self.precedence(expr) < ExprPrecedence::Unambiguous,
1699                );
1700                self.word(".");
1701                self.print_ident(ident);
1702            }
1703            hir::ExprKind::Index(expr, index, _) => {
1704                self.print_expr_cond_paren(
1705                    expr,
1706                    self.precedence(expr) < ExprPrecedence::Unambiguous,
1707                );
1708                self.word("[");
1709                self.print_expr(index);
1710                self.word("]");
1711            }
1712            hir::ExprKind::Path(ref qpath) => self.print_qpath(qpath, true),
1713            hir::ExprKind::Break(destination, opt_expr) => {
1714                self.word("break");
1715                if let Some(label) = destination.label {
1716                    self.space();
1717                    self.print_ident(label.ident);
1718                }
1719                if let Some(expr) = opt_expr {
1720                    self.space();
1721                    self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
1722                }
1723            }
1724            hir::ExprKind::Continue(destination) => {
1725                self.word("continue");
1726                if let Some(label) = destination.label {
1727                    self.space();
1728                    self.print_ident(label.ident);
1729                }
1730            }
1731            hir::ExprKind::Ret(result) => {
1732                self.word("return");
1733                if let Some(expr) = result {
1734                    self.word(" ");
1735                    self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
1736                }
1737            }
1738            hir::ExprKind::Become(result) => {
1739                self.word("become");
1740                self.word(" ");
1741                self.print_expr_cond_paren(result, self.precedence(result) < ExprPrecedence::Jump);
1742            }
1743            hir::ExprKind::InlineAsm(asm) => {
1744                self.word(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}!", asm.asm_macro.macro_name()))
    })format!("{}!", asm.asm_macro.macro_name()));
1745                self.print_inline_asm(asm);
1746            }
1747            hir::ExprKind::OffsetOf(container, fields) => {
1748                self.word("offset_of!(");
1749                self.print_type(container);
1750                self.word(",");
1751                self.space();
1752
1753                if let Some((&first, rest)) = fields.split_first() {
1754                    self.print_ident(first);
1755
1756                    for &field in rest {
1757                        self.word(".");
1758                        self.print_ident(field);
1759                    }
1760                }
1761
1762                self.word(")");
1763            }
1764            hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
1765                match kind {
1766                    ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
1767                    ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
1768                }
1769                self.print_expr(expr);
1770                if let Some(ty) = ty {
1771                    self.word(",");
1772                    self.space();
1773                    self.print_type(ty);
1774                }
1775                self.word(")");
1776            }
1777            hir::ExprKind::Yield(expr, _) => {
1778                self.word_space("yield");
1779                self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
1780            }
1781            hir::ExprKind::Err(_) => {
1782                self.popen();
1783                self.word("/*ERROR*/");
1784                self.pclose();
1785            }
1786        }
1787        self.ann.post(self, AnnNode::Expr(expr));
1788        self.end(ib)
1789    }
1790
1791    fn print_local_decl(&mut self, loc: &hir::LetStmt<'_>) {
1792        self.print_pat(loc.pat);
1793        if let Some(ty) = loc.ty {
1794            self.word_space(":");
1795            self.print_type(ty);
1796        }
1797    }
1798
1799    fn print_name(&mut self, name: Symbol) {
1800        self.print_ident(Ident::with_dummy_span(name))
1801    }
1802
1803    fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
1804        self.maybe_print_comment(path.span.lo());
1805
1806        for (i, segment) in path.segments.iter().enumerate() {
1807            if i > 0 {
1808                self.word("::")
1809            }
1810            if segment.ident.name != kw::PathRoot {
1811                self.print_ident(segment.ident);
1812                self.print_generic_args(segment.args(), colons_before_params);
1813            }
1814        }
1815    }
1816
1817    fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
1818        if segment.ident.name != kw::PathRoot {
1819            self.print_ident(segment.ident);
1820            self.print_generic_args(segment.args(), false);
1821        }
1822    }
1823
1824    fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
1825        match *qpath {
1826            hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params),
1827            hir::QPath::Resolved(Some(qself), path) => {
1828                self.word("<");
1829                self.print_type(qself);
1830                self.space();
1831                self.word_space("as");
1832
1833                for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() {
1834                    if i > 0 {
1835                        self.word("::")
1836                    }
1837                    if segment.ident.name != kw::PathRoot {
1838                        self.print_ident(segment.ident);
1839                        self.print_generic_args(segment.args(), colons_before_params);
1840                    }
1841                }
1842
1843                self.word(">");
1844                self.word("::");
1845                let item_segment = path.segments.last().unwrap();
1846                self.print_ident(item_segment.ident);
1847                self.print_generic_args(item_segment.args(), colons_before_params)
1848            }
1849            hir::QPath::TypeRelative(qself, item_segment) => {
1850                // If we've got a compound-qualified-path, let's push an additional pair of angle
1851                // brackets, so that we pretty-print `<<A::B>::C>` as `<A::B>::C`, instead of just
1852                // `A::B::C` (since the latter could be ambiguous to the user)
1853                if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = qself.kind {
1854                    self.print_type(qself);
1855                } else {
1856                    self.word("<");
1857                    self.print_type(qself);
1858                    self.word(">");
1859                }
1860
1861                self.word("::");
1862                self.print_ident(item_segment.ident);
1863                self.print_generic_args(item_segment.args(), colons_before_params)
1864            }
1865        }
1866    }
1867
1868    fn print_generic_args(
1869        &mut self,
1870        generic_args: &hir::GenericArgs<'_>,
1871        colons_before_params: bool,
1872    ) {
1873        match generic_args.parenthesized {
1874            hir::GenericArgsParentheses::No => {
1875                let start = if colons_before_params { "::<" } else { "<" };
1876                let empty = Cell::new(true);
1877                let start_or_comma = |this: &mut Self| {
1878                    if empty.get() {
1879                        empty.set(false);
1880                        this.word(start)
1881                    } else {
1882                        this.word_space(",")
1883                    }
1884                };
1885
1886                let mut nonelided_generic_args: bool = false;
1887                let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
1888                    GenericArg::Lifetime(lt) if lt.is_elided() => true,
1889                    GenericArg::Lifetime(_) => {
1890                        nonelided_generic_args = true;
1891                        false
1892                    }
1893                    _ => {
1894                        nonelided_generic_args = true;
1895                        true
1896                    }
1897                });
1898
1899                if nonelided_generic_args {
1900                    start_or_comma(self);
1901                    self.commasep(Inconsistent, generic_args.args, |s, generic_arg| {
1902                        s.print_generic_arg(generic_arg, elide_lifetimes)
1903                    });
1904                }
1905
1906                for constraint in generic_args.constraints {
1907                    start_or_comma(self);
1908                    self.print_assoc_item_constraint(constraint);
1909                }
1910
1911                if !empty.get() {
1912                    self.word(">")
1913                }
1914            }
1915            hir::GenericArgsParentheses::ParenSugar => {
1916                let (inputs, output) = generic_args.paren_sugar_inputs_output().unwrap();
1917
1918                self.word("(");
1919                self.commasep(Inconsistent, inputs, |s, ty| s.print_type(ty));
1920                self.word(")");
1921
1922                self.space_if_not_bol();
1923                self.word_space("->");
1924                self.print_type(output);
1925            }
1926            hir::GenericArgsParentheses::ReturnTypeNotation => {
1927                self.word("(..)");
1928            }
1929        }
1930    }
1931
1932    fn print_assoc_item_constraint(&mut self, constraint: &hir::AssocItemConstraint<'_>) {
1933        self.print_ident(constraint.ident);
1934        self.print_generic_args(constraint.gen_args, false);
1935        self.space();
1936        match constraint.kind {
1937            hir::AssocItemConstraintKind::Equality { ref term } => {
1938                self.word_space("=");
1939                match term {
1940                    Term::Ty(ty) => self.print_type(ty),
1941                    Term::Const(c) => self.print_const_arg(c),
1942                }
1943            }
1944            hir::AssocItemConstraintKind::Bound { bounds } => {
1945                self.print_bounds(":", bounds);
1946            }
1947        }
1948    }
1949
1950    fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) {
1951        match &expr.kind {
1952            hir::PatExprKind::Lit { lit, negated } => {
1953                if *negated {
1954                    self.word("-");
1955                }
1956                self.print_literal(lit);
1957            }
1958            hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true),
1959        }
1960    }
1961
1962    fn print_ty_pat(&mut self, pat: &hir::TyPat<'_>) {
1963        self.maybe_print_comment(pat.span.lo());
1964        self.ann.pre(self, AnnNode::TyPat(pat));
1965        // Pat isn't normalized, but the beauty of it
1966        // is that it doesn't matter
1967        match pat.kind {
1968            TyPatKind::Range(begin, end) => {
1969                self.print_const_arg(begin);
1970                self.word("..=");
1971                self.print_const_arg(end);
1972            }
1973            TyPatKind::NotNull => {
1974                self.word_space("not");
1975                self.word("null");
1976            }
1977            TyPatKind::Or(patterns) => {
1978                self.popen();
1979                let mut first = true;
1980                for pat in patterns {
1981                    if first {
1982                        first = false;
1983                    } else {
1984                        self.word(" | ");
1985                    }
1986                    self.print_ty_pat(pat);
1987                }
1988                self.pclose();
1989            }
1990            TyPatKind::Err(_) => {
1991                self.popen();
1992                self.word("/*ERROR*/");
1993                self.pclose();
1994            }
1995        }
1996        self.ann.post(self, AnnNode::TyPat(pat))
1997    }
1998
1999    fn print_pat(&mut self, pat: &hir::Pat<'_>) {
2000        self.maybe_print_comment(pat.span.lo());
2001        self.ann.pre(self, AnnNode::Pat(pat));
2002        // Pat isn't normalized, but the beauty of it is that it doesn't matter.
2003        match pat.kind {
2004            // Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
2005            // E.g. `fn(u32)` gets printed as `fn(_: u32)`.
2006            PatKind::Missing => self.word("_"),
2007            PatKind::Wild => self.word("_"),
2008            PatKind::Never => self.word("!"),
2009            PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
2010                if mutbl.is_mut() {
2011                    self.word_nbsp("mut");
2012                }
2013                if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
2014                    self.word_nbsp("ref");
2015                    if pinnedness.is_pinned() {
2016                        self.word_nbsp("pin");
2017                    }
2018                    if rmutbl.is_mut() {
2019                        self.word_nbsp("mut");
2020                    } else if pinnedness.is_pinned() {
2021                        self.word_nbsp("const");
2022                    }
2023                }
2024                self.print_ident(ident);
2025                if let Some(p) = sub {
2026                    self.word("@");
2027                    self.print_pat(p);
2028                }
2029            }
2030            PatKind::TupleStruct(ref qpath, elts, ddpos) => {
2031                self.print_qpath(qpath, true);
2032                self.popen();
2033                if let Some(ddpos) = ddpos.as_opt_usize() {
2034                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
2035                    if ddpos != 0 {
2036                        self.word_space(",");
2037                    }
2038                    self.word("..");
2039                    if ddpos != elts.len() {
2040                        self.word(",");
2041                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
2042                    }
2043                } else {
2044                    self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
2045                }
2046                self.pclose();
2047            }
2048            PatKind::Struct(ref qpath, fields, etc) => {
2049                self.print_qpath(qpath, true);
2050                self.nbsp();
2051                self.word("{");
2052                let empty = fields.is_empty() && etc.is_none();
2053                if !empty {
2054                    self.space();
2055                }
2056                self.commasep_cmnt(Consistent, fields, |s, f| s.print_patfield(f), |f| f.pat.span);
2057                if etc.is_some() {
2058                    if !fields.is_empty() {
2059                        self.word_space(",");
2060                    }
2061                    self.word("..");
2062                }
2063                if !empty {
2064                    self.space();
2065                }
2066                self.word("}");
2067            }
2068            PatKind::Or(pats) => {
2069                self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
2070            }
2071            PatKind::Tuple(elts, ddpos) => {
2072                self.popen();
2073                if let Some(ddpos) = ddpos.as_opt_usize() {
2074                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
2075                    if ddpos != 0 {
2076                        self.word_space(",");
2077                    }
2078                    self.word("..");
2079                    if ddpos != elts.len() {
2080                        self.word(",");
2081                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
2082                    }
2083                } else {
2084                    self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
2085                    if elts.len() == 1 {
2086                        self.word(",");
2087                    }
2088                }
2089                self.pclose();
2090            }
2091            PatKind::Box(inner) => {
2092                let is_range_inner = #[allow(non_exhaustive_omitted_patterns)] match inner.kind {
    PatKind::Range(..) => true,
    _ => false,
}matches!(inner.kind, PatKind::Range(..));
2093                self.word("box ");
2094                if is_range_inner {
2095                    self.popen();
2096                }
2097                self.print_pat(inner);
2098                if is_range_inner {
2099                    self.pclose();
2100                }
2101            }
2102            PatKind::Deref(inner) => {
2103                self.word("deref!");
2104                self.popen();
2105                self.print_pat(inner);
2106                self.pclose();
2107            }
2108            PatKind::Ref(inner, pinned, mutbl) => {
2109                let is_range_inner = #[allow(non_exhaustive_omitted_patterns)] match inner.kind {
    PatKind::Range(..) => true,
    _ => false,
}matches!(inner.kind, PatKind::Range(..));
2110                self.word("&");
2111                if pinned.is_pinned() {
2112                    self.word("pin ");
2113                    if mutbl.is_not() {
2114                        self.word("const ");
2115                    }
2116                }
2117                self.word(mutbl.prefix_str());
2118                if is_range_inner {
2119                    self.popen();
2120                }
2121                self.print_pat(inner);
2122                if is_range_inner {
2123                    self.pclose();
2124                }
2125            }
2126            PatKind::Expr(e) => self.print_pat_expr(e),
2127            PatKind::Range(begin, end, end_kind) => {
2128                if let Some(expr) = begin {
2129                    self.print_pat_expr(expr);
2130                }
2131                match end_kind {
2132                    RangeEnd::Included => self.word("..."),
2133                    RangeEnd::Excluded => self.word(".."),
2134                }
2135                if let Some(expr) = end {
2136                    self.print_pat_expr(expr);
2137                }
2138            }
2139            PatKind::Slice(before, slice, after) => {
2140                self.word("[");
2141                self.commasep(Inconsistent, before, |s, p| s.print_pat(p));
2142                if let Some(p) = slice {
2143                    if !before.is_empty() {
2144                        self.word_space(",");
2145                    }
2146                    if let PatKind::Wild = p.kind {
2147                        // Print nothing.
2148                    } else {
2149                        self.print_pat(p);
2150                    }
2151                    self.word("..");
2152                    if !after.is_empty() {
2153                        self.word_space(",");
2154                    }
2155                }
2156                self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
2157                self.word("]");
2158            }
2159            PatKind::Guard(inner, cond) => {
2160                self.print_pat(inner);
2161                self.space();
2162                self.word_space("if");
2163                self.print_expr(cond);
2164            }
2165            PatKind::Err(_) => {
2166                self.popen();
2167                self.word("/*ERROR*/");
2168                self.pclose();
2169            }
2170        }
2171        self.ann.post(self, AnnNode::Pat(pat))
2172    }
2173
2174    fn print_patfield(&mut self, field: &hir::PatField<'_>) {
2175        if self.attrs(field.hir_id).is_empty() {
2176            self.space();
2177        }
2178        let cb = self.cbox(INDENT_UNIT);
2179        self.print_attrs(self.attrs(field.hir_id));
2180        if !field.is_shorthand {
2181            self.print_ident(field.ident);
2182            self.word_nbsp(":");
2183        }
2184        self.print_pat(field.pat);
2185        self.end(cb);
2186    }
2187
2188    fn print_param(&mut self, arg: &hir::Param<'_>) {
2189        self.print_attrs(self.attrs(arg.hir_id));
2190        self.print_pat(arg.pat);
2191    }
2192
2193    fn print_implicit_self(&mut self, implicit_self_kind: &hir::ImplicitSelfKind) {
2194        match implicit_self_kind {
2195            ImplicitSelfKind::Imm => {
2196                self.word("self");
2197            }
2198            ImplicitSelfKind::Mut => {
2199                self.print_mutability(hir::Mutability::Mut, false);
2200                self.word("self");
2201            }
2202            ImplicitSelfKind::RefImm => {
2203                self.word("&");
2204                self.word("self");
2205            }
2206            ImplicitSelfKind::RefMut => {
2207                self.word("&");
2208                self.print_mutability(hir::Mutability::Mut, false);
2209                self.word("self");
2210            }
2211            ImplicitSelfKind::None => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
2212        }
2213    }
2214
2215    fn print_arm(&mut self, arm: &hir::Arm<'_>) {
2216        // I have no idea why this check is necessary, but here it
2217        // is :(
2218        if self.attrs(arm.hir_id).is_empty() {
2219            self.space();
2220        }
2221        let cb = self.cbox(INDENT_UNIT);
2222        self.ann.pre(self, AnnNode::Arm(arm));
2223        let ib = self.ibox(0);
2224        self.print_attrs(self.attrs(arm.hir_id));
2225        self.print_pat(arm.pat);
2226        self.space();
2227        if let Some(ref g) = arm.guard {
2228            self.word_space("if");
2229            self.print_expr(g);
2230            self.space();
2231        }
2232        self.word_space("=>");
2233
2234        match arm.body.kind {
2235            hir::ExprKind::Block(blk, opt_label) => {
2236                if let Some(label) = opt_label {
2237                    self.print_ident(label.ident);
2238                    self.word_space(":");
2239                }
2240                self.print_block_unclosed(blk, ib);
2241
2242                // If it is a user-provided unsafe block, print a comma after it
2243                if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules
2244                {
2245                    self.word(",");
2246                }
2247            }
2248            _ => {
2249                self.end(ib);
2250                self.print_expr(arm.body);
2251                self.word(",");
2252            }
2253        }
2254        self.ann.post(self, AnnNode::Arm(arm));
2255        self.end(cb)
2256    }
2257
2258    fn print_fn(
2259        &mut self,
2260        header: hir::FnHeader,
2261        name: Option<Symbol>,
2262        generics: &hir::Generics<'_>,
2263        decl: &hir::FnDecl<'_>,
2264        arg_idents: &[Option<Ident>],
2265        body_id: Option<hir::BodyId>,
2266    ) {
2267        self.print_fn_header_info(header);
2268
2269        if let Some(name) = name {
2270            self.nbsp();
2271            self.print_name(name);
2272        }
2273        self.print_generic_params(generics.params);
2274
2275        self.popen();
2276        // Make sure we aren't supplied *both* `arg_idents` and `body_id`.
2277        if !(arg_idents.is_empty() || body_id.is_none()) {
    ::core::panicking::panic("assertion failed: arg_idents.is_empty() || body_id.is_none()")
};assert!(arg_idents.is_empty() || body_id.is_none());
2278        let mut i = 0;
2279        let mut print_arg = |s: &mut Self, ty: Option<&hir::Ty<'_>>| {
2280            if Some(i) == decl.splatted().map(usize::from) {
2281                s.word("#[rustc_splat]");
2282            }
2283            if i == 0 && decl.implicit_self().has_implicit_self() {
2284                s.print_implicit_self(&decl.implicit_self());
2285            } else {
2286                if let Some(arg_ident) = arg_idents.get(i) {
2287                    if let Some(arg_ident) = arg_ident {
2288                        s.word(arg_ident.to_string());
2289                        s.word(":");
2290                        s.space();
2291                    }
2292                } else if let Some(body_id) = body_id {
2293                    s.ann.nested(s, Nested::BodyParamPat(body_id, i));
2294                    s.word(":");
2295                    s.space();
2296                }
2297                if let Some(ty) = ty {
2298                    s.print_type(ty);
2299                }
2300            }
2301            i += 1;
2302        };
2303        self.commasep(Inconsistent, decl.inputs, |s, ty| {
2304            let ib = s.ibox(INDENT_UNIT);
2305            print_arg(s, Some(ty));
2306            s.end(ib);
2307        });
2308        if decl.c_variadic() {
2309            if !decl.inputs.is_empty() {
2310                self.word(", ");
2311            }
2312            print_arg(self, None);
2313            self.word("...");
2314        }
2315        self.pclose();
2316
2317        self.print_fn_output(decl);
2318        self.print_where_clause(generics)
2319    }
2320
2321    fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) {
2322        self.word("|");
2323        let mut i = 0;
2324        self.commasep(Inconsistent, decl.inputs, |s, ty| {
2325            let ib = s.ibox(INDENT_UNIT);
2326
2327            s.ann.nested(s, Nested::BodyParamPat(body_id, i));
2328            i += 1;
2329
2330            if let hir::TyKind::Infer(()) = ty.kind {
2331                // Print nothing.
2332            } else {
2333                s.word(":");
2334                s.space();
2335                s.print_type(ty);
2336            }
2337            s.end(ib);
2338        });
2339        self.word("|");
2340
2341        match decl.output {
2342            hir::FnRetTy::Return(ty) => {
2343                self.space_if_not_bol();
2344                self.word_space("->");
2345                self.print_type(ty);
2346                self.maybe_print_comment(ty.span.lo());
2347            }
2348            hir::FnRetTy::DefaultReturn(..) => {}
2349        }
2350    }
2351
2352    fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
2353        match capture_clause {
2354            hir::CaptureBy::Value { .. } => self.word_space("move"),
2355            hir::CaptureBy::Use { .. } => self.word_space("use"),
2356            hir::CaptureBy::Ref => {}
2357        }
2358    }
2359
2360    fn print_closure_binder(
2361        &mut self,
2362        binder: hir::ClosureBinder,
2363        generic_params: &[GenericParam<'_>],
2364    ) {
2365        let generic_params = generic_params
2366            .iter()
2367            .filter(|p| {
2368                #[allow(non_exhaustive_omitted_patterns)] match p {
    GenericParam {
        kind: GenericParamKind::Lifetime {
            kind: LifetimeParamKind::Explicit
            }, .. } => true,
    _ => false,
}matches!(
2369                    p,
2370                    GenericParam {
2371                        kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit },
2372                        ..
2373                    }
2374                )
2375            })
2376            .collect::<Vec<_>>();
2377
2378        match binder {
2379            hir::ClosureBinder::Default => {}
2380            // We need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional
2381            // restrictions.
2382            hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
2383            hir::ClosureBinder::For { .. } => {
2384                self.word("for");
2385                self.word("<");
2386
2387                self.commasep(Inconsistent, &generic_params, |s, param| {
2388                    s.print_generic_param(param)
2389                });
2390
2391                self.word(">");
2392                self.nbsp();
2393            }
2394        }
2395    }
2396
2397    fn print_bounds<'b>(
2398        &mut self,
2399        prefix: &'static str,
2400        bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>,
2401    ) {
2402        let mut first = true;
2403        for bound in bounds {
2404            if first {
2405                self.word(prefix);
2406            }
2407            if !(first && prefix.is_empty()) {
2408                self.nbsp();
2409            }
2410            if first {
2411                first = false;
2412            } else {
2413                self.word_space("+");
2414            }
2415
2416            match bound {
2417                GenericBound::Trait(tref) => {
2418                    self.print_poly_trait_ref(tref);
2419                }
2420                GenericBound::Outlives(lt) => {
2421                    self.print_lifetime(lt);
2422                }
2423                GenericBound::Use(args, _) => {
2424                    self.word("use <");
2425
2426                    self.commasep(Inconsistent, *args, |s, arg| {
2427                        s.print_precise_capturing_arg(*arg)
2428                    });
2429
2430                    self.word(">");
2431                }
2432            }
2433        }
2434    }
2435
2436    fn print_precise_capturing_arg(&mut self, arg: PreciseCapturingArg<'_>) {
2437        match arg {
2438            PreciseCapturingArg::Lifetime(lt) => self.print_lifetime(lt),
2439            PreciseCapturingArg::Param(arg) => self.print_ident(arg.ident),
2440        }
2441    }
2442
2443    fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
2444        let is_lifetime_elided = |generic_param: &GenericParam<'_>| {
2445            #[allow(non_exhaustive_omitted_patterns)] match generic_param.kind {
    GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) } => true,
    _ => false,
}matches!(
2446                generic_param.kind,
2447                GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) }
2448            )
2449        };
2450
2451        // We don't want to show elided lifetimes as they are compiler-inserted and not
2452        // expressible in surface level Rust.
2453        if !generic_params.is_empty() && !generic_params.iter().all(is_lifetime_elided) {
2454            self.word("<");
2455
2456            self.commasep(
2457                Inconsistent,
2458                generic_params.iter().filter(|gp| !is_lifetime_elided(gp)),
2459                |s, param| s.print_generic_param(param),
2460            );
2461
2462            self.word(">");
2463        }
2464    }
2465
2466    fn print_generic_param(&mut self, param: &GenericParam<'_>) {
2467        if let GenericParamKind::Const { .. } = param.kind {
2468            self.word_space("const");
2469        }
2470
2471        self.print_ident(param.name.ident());
2472
2473        match param.kind {
2474            GenericParamKind::Lifetime { .. } => {}
2475            GenericParamKind::Type { default, .. } => {
2476                if let Some(default) = default {
2477                    self.space();
2478                    self.word_space("=");
2479                    self.print_type(default);
2480                }
2481            }
2482            GenericParamKind::Const { ty, ref default } => {
2483                self.word_space(":");
2484                self.print_type(ty);
2485                if let Some(default) = default {
2486                    self.space();
2487                    self.word_space("=");
2488                    self.print_const_arg(default);
2489                }
2490            }
2491        }
2492    }
2493
2494    fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
2495        self.print_ident(lifetime.ident)
2496    }
2497
2498    fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
2499        if generics.predicates.is_empty() {
2500            return;
2501        }
2502
2503        self.space();
2504        self.word_space("where");
2505
2506        for (i, predicate) in generics.predicates.iter().enumerate() {
2507            if i != 0 {
2508                self.word_space(",");
2509            }
2510            self.print_where_predicate(predicate);
2511        }
2512    }
2513
2514    fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) {
2515        self.print_attrs(self.attrs(predicate.hir_id));
2516        match *predicate.kind {
2517            hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
2518                bound_generic_params,
2519                bounded_ty,
2520                bounds,
2521                ..
2522            }) => {
2523                self.print_formal_generic_params(bound_generic_params);
2524                self.print_type(bounded_ty);
2525                self.print_bounds(":", bounds);
2526            }
2527            hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
2528                lifetime,
2529                bounds,
2530                ..
2531            }) => {
2532                self.print_lifetime(lifetime);
2533                self.word(":");
2534
2535                for (i, bound) in bounds.iter().enumerate() {
2536                    match bound {
2537                        GenericBound::Outlives(lt) => {
2538                            self.print_lifetime(lt);
2539                        }
2540                        _ => {
    ::core::panicking::panic_fmt(format_args!("unexpected bound on lifetime param: {0:?}",
            bound));
}panic!("unexpected bound on lifetime param: {bound:?}"),
2541                    }
2542
2543                    if i != 0 {
2544                        self.word(":");
2545                    }
2546                }
2547            }
2548        }
2549    }
2550
2551    fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
2552        match mutbl {
2553            hir::Mutability::Mut => self.word_nbsp("mut"),
2554            hir::Mutability::Not => {
2555                if print_const {
2556                    self.word_nbsp("const")
2557                }
2558            }
2559        }
2560    }
2561
2562    fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
2563        self.print_mutability(mt.mutbl, print_const);
2564        self.print_type(mt.ty);
2565    }
2566
2567    fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
2568        match decl.output {
2569            hir::FnRetTy::Return(ty) => {
2570                self.space_if_not_bol();
2571                let ib = self.ibox(INDENT_UNIT);
2572                self.word_space("->");
2573                self.print_type(ty);
2574                self.end(ib);
2575
2576                if let hir::FnRetTy::Return(output) = decl.output {
2577                    self.maybe_print_comment(output.span.lo());
2578                }
2579            }
2580            hir::FnRetTy::DefaultReturn(..) => {}
2581        }
2582    }
2583
2584    fn print_ty_fn(
2585        &mut self,
2586        abi: ExternAbi,
2587        safety: hir::Safety,
2588        decl: &hir::FnDecl<'_>,
2589        name: Option<Symbol>,
2590        generic_params: &[hir::GenericParam<'_>],
2591        arg_idents: &[Option<Ident>],
2592    ) {
2593        let ib = self.ibox(INDENT_UNIT);
2594        self.print_formal_generic_params(generic_params);
2595        let generics = hir::Generics::empty();
2596        self.print_fn(
2597            hir::FnHeader {
2598                safety: safety.into(),
2599                abi,
2600                constness: hir::Constness::NotConst,
2601                asyncness: hir::IsAsync::NotAsync,
2602            },
2603            name,
2604            generics,
2605            decl,
2606            arg_idents,
2607            None,
2608        );
2609        self.end(ib);
2610    }
2611
2612    fn print_fn_header_info(&mut self, header: hir::FnHeader) {
2613        self.print_constness(header.constness);
2614
2615        let safety = match header.safety {
2616            hir::HeaderSafety::SafeTargetFeatures => {
2617                self.word_nbsp("#[target_feature]");
2618                hir::Safety::Safe
2619            }
2620            hir::HeaderSafety::Normal(safety) => safety,
2621        };
2622
2623        match header.asyncness {
2624            hir::IsAsync::NotAsync => {}
2625            hir::IsAsync::Async(_) => self.word_nbsp("async"),
2626        }
2627
2628        self.print_safety(safety);
2629
2630        if header.abi != ExternAbi::Rust {
2631            self.word_nbsp("extern");
2632            self.word_nbsp(header.abi.to_string());
2633        }
2634
2635        self.word("fn")
2636    }
2637
2638    fn print_constness(&mut self, s: hir::Constness) {
2639        match s {
2640            hir::Constness::NotConst => {}
2641            hir::Constness::Const { always: false } => self.word_nbsp("const"),
2642            hir::Constness::Const { always: true } => { /* printed as an attribute */ }
2643        }
2644    }
2645
2646    fn print_safety(&mut self, s: hir::Safety) {
2647        match s {
2648            hir::Safety::Safe => {}
2649            hir::Safety::Unsafe => self.word_nbsp("unsafe"),
2650        }
2651    }
2652
2653    fn print_is_auto(&mut self, s: hir::IsAuto) {
2654        match s {
2655            hir::IsAuto::Yes => self.word_nbsp("auto"),
2656            hir::IsAuto::No => {}
2657        }
2658    }
2659
2660    fn print_restriction<S: Into<std::borrow::Cow<'static, str>>>(
2661        &mut self,
2662        k: &hir::RestrictionKind<'_>,
2663        prefix: S,
2664    ) {
2665        match k {
2666            hir::RestrictionKind::Unrestricted => {}
2667            hir::RestrictionKind::Restricted(path) => {
2668                self.word(prefix.into());
2669                self.word_nbsp("(in");
2670                self.print_path(path, false);
2671                self.word_nbsp(")");
2672            }
2673        }
2674    }
2675
2676    fn print_mut_restriction(&mut self, r: &hir::MutRestriction<'_>) {
2677        self.print_restriction(&r.kind, "mut");
2678    }
2679
2680    fn print_impl_restriction(&mut self, r: &hir::ImplRestriction<'_>) {
2681        self.print_restriction(&r.kind, "impl");
2682    }
2683}
2684
2685/// Does this expression require a semicolon to be treated
2686/// as a statement? The negation of this: 'can this expression
2687/// be used as a statement without a semicolon' -- is used
2688/// as an early-bail-out in the parser so that, for instance,
2689///     if true {...} else {...}
2690///      |x| 5
2691/// isn't parsed as (if true {...} else {...} | x) | 5
2692//
2693// Duplicated from `parse::classify`, but adapted for the HIR.
2694fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
2695    !#[allow(non_exhaustive_omitted_patterns)] match e.kind {
    hir::ExprKind::If(..) | hir::ExprKind::Match(..) |
        hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) => true,
    _ => false,
}matches!(
2696        e.kind,
2697        hir::ExprKind::If(..)
2698            | hir::ExprKind::Match(..)
2699            | hir::ExprKind::Block(..)
2700            | hir::ExprKind::Loop(..)
2701    )
2702}
2703
2704/// This statement requires a semicolon after it.
2705/// note that in one case (stmt_semi), we've already
2706/// seen the semicolon, and thus don't need another.
2707fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
2708    match *stmt {
2709        hir::StmtKind::Let(_) => true,
2710        hir::StmtKind::Item(_) => false,
2711        hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
2712        hir::StmtKind::Semi(..) => false,
2713    }
2714}
2715
2716/// Expressions that syntactically contain an "exterior" struct literal, i.e., not surrounded by any
2717/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
2718/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
2719fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
2720    match value.kind {
2721        hir::ExprKind::Struct(..) => true,
2722
2723        hir::ExprKind::Assign(lhs, rhs, _)
2724        | hir::ExprKind::AssignOp(_, lhs, rhs)
2725        | hir::ExprKind::Binary(_, lhs, rhs) => {
2726            // `X { y: 1 } + X { y: 2 }`
2727            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
2728        }
2729        hir::ExprKind::Unary(_, x)
2730        | hir::ExprKind::Cast(x, _)
2731        | hir::ExprKind::Type(x, _)
2732        | hir::ExprKind::Field(x, _)
2733        | hir::ExprKind::Index(x, _, _) => {
2734            // `&X { y: 1 }, X { y: 1 }.y`
2735            contains_exterior_struct_lit(x)
2736        }
2737
2738        hir::ExprKind::MethodCall(_, receiver, ..) => {
2739            // `X { y: 1 }.bar(...)`
2740            contains_exterior_struct_lit(receiver)
2741        }
2742
2743        _ => false,
2744    }
2745}