Skip to main content

hir_def/expr_store/
pretty.rs

1//! A pretty-printer for HIR.
2#![allow(dead_code)]
3
4use std::{
5    fmt::{self, Write},
6    mem,
7};
8
9use hir_expand::{Lookup, mod_path::PathKind};
10use itertools::Itertools;
11use rustc_abi::ExternAbi;
12use span::Edition;
13use stdx::never;
14use syntax::ast::{HasName, RangeOp};
15
16use crate::{
17    AdtId, DefWithBodyId, FunctionId, GenericDefId, MacroId, StructId, TypeParamId, VariantId,
18    attrs::AttrFlags,
19    expr_store::path::{GenericArg, GenericArgs},
20    hir::{
21        Array, BindingAnnotation, CaptureBy, ClosureKind, CoroutineKind, Literal, Movability,
22        RecordSpread, Statement, Unsafe,
23        generics::{GenericParams, WherePredicate},
24    },
25    lang_item::LangItemTarget,
26    signatures::{FnFlags, FunctionSignature, StructSignature},
27    src::HasSource,
28    type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
29};
30use crate::{LifetimeParamId, signatures::StructFlags};
31use crate::{item_tree::FieldsShape, signatures::FieldData};
32
33use super::*;
34
35macro_rules! w {
36    ($dst:expr, $($arg:tt)*) => {
37        { let _ = write!($dst, $($arg)*); }
38    };
39}
40
41macro_rules! wln {
42    ($dst:expr) => {
43        { $dst.newline(); }
44    };
45    ($dst:expr, $($arg:tt)*) => {
46        { let _ = w!($dst, $($arg)*); $dst.newline(); }
47    };
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum LineFormat {
52    Oneline,
53    Newline,
54    Indentation,
55}
56
57fn item_name<Id, Loc>(db: &dyn SourceDatabase, id: Id, default: &str) -> String
58where
59    Id: Lookup<Data = Loc>,
60    Loc: HasSource,
61    Loc::Value: ast::HasName,
62{
63    let loc = id.lookup(db);
64    let source = loc.source(db);
65    source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string())
66}
67
68pub fn print_body_hir(
69    db: &dyn SourceDatabase,
70    body: &Body,
71    owner: DefWithBodyId,
72    edition: Edition,
73) -> String {
74    let header = match owner {
75        DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")),
76        DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")),
77        DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")),
78        DefWithBodyId::VariantId(it) => format!(
79            "enum {}::{}",
80            item_name(db, it.lookup(db).parent, "<missing>"),
81            item_name(db, it, "<missing>")
82        ),
83    };
84
85    let mut p = Printer {
86        db,
87        store: body,
88        buf: header,
89        indent_level: 0,
90        line_format: LineFormat::Newline,
91        edition,
92    };
93    if let DefWithBodyId::FunctionId(_) = owner {
94        p.buf.push('(');
95        if let Some(self_param) = body.self_param {
96            p.print_binding(self_param.formal);
97            p.buf.push_str(", ");
98        }
99        body.params.iter().for_each(|param| {
100            p.print_pat(param.formal);
101            p.buf.push_str(", ");
102        });
103        // remove the last ", " in param list
104        if !body.params.is_empty() {
105            p.buf.truncate(p.buf.len() - 2);
106        }
107        p.buf.push(')');
108        p.buf.push(' ');
109    }
110    p.print_expr(body.root_expr());
111    if matches!(owner, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_)) {
112        p.buf.push(';');
113    }
114    p.buf
115}
116
117pub fn print_variant_body_hir(
118    db: &dyn SourceDatabase,
119    owner: VariantId,
120    edition: Edition,
121) -> String {
122    let header = match owner {
123        VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")),
124        VariantId::EnumVariantId(it) => format!(
125            "enum {}::{}",
126            item_name(db, it.lookup(db).parent, "<missing>"),
127            item_name(db, it, "<missing>")
128        ),
129        VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
130    };
131
132    let fields = owner.fields(db);
133
134    let mut p = Printer {
135        db,
136        store: &fields.store,
137        buf: header,
138        indent_level: 0,
139        line_format: LineFormat::Newline,
140        edition,
141    };
142    match fields.shape {
143        FieldsShape::Record => wln!(p, " {{"),
144        FieldsShape::Tuple => wln!(p, "("),
145        FieldsShape::Unit => (),
146    }
147
148    for (_, data) in fields.fields().iter() {
149        let FieldData { name, type_ref, visibility, is_unsafe, default_value: _ } = data;
150        match visibility {
151            crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => {
152                w!(p, "pub(in {})", interned.display(db, p.edition))
153            }
154            crate::item_tree::RawVisibility::Public => w!(p, "pub "),
155            crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "),
156            crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "),
157        }
158        if *is_unsafe {
159            w!(p, "unsafe ");
160        }
161        w!(p, "{}: ", name.display(db, p.edition));
162        p.print_type_ref(*type_ref);
163    }
164
165    match fields.shape {
166        FieldsShape::Record => wln!(p, "}}"),
167        FieldsShape::Tuple => wln!(p, ");"),
168        FieldsShape::Unit => wln!(p, ";"),
169    }
170    p.buf
171}
172
173pub fn print_signature(db: &dyn SourceDatabase, owner: GenericDefId, edition: Edition) -> String {
174    match owner {
175        GenericDefId::AdtId(id) => match id {
176            AdtId::StructId(id) => {
177                let signature = StructSignature::of(db, id);
178                print_struct(db, id, signature, edition)
179            }
180            AdtId::UnionId(id) => {
181                format!("unimplemented {id:?}")
182            }
183            AdtId::EnumId(id) => {
184                format!("unimplemented {id:?}")
185            }
186        },
187        GenericDefId::ConstId(id) => format!("unimplemented {id:?}"),
188        GenericDefId::FunctionId(id) => {
189            let signature = FunctionSignature::of(db, id);
190            print_function(db, id, signature, edition)
191        }
192        GenericDefId::ImplId(id) => format!("unimplemented {id:?}"),
193        GenericDefId::StaticId(id) => format!("unimplemented {id:?}"),
194        GenericDefId::TraitId(id) => format!("unimplemented {id:?}"),
195        GenericDefId::TypeAliasId(id) => format!("unimplemented {id:?}"),
196    }
197}
198
199pub fn print_path(
200    db: &dyn SourceDatabase,
201    store: &ExpressionStore,
202    path: &Path,
203    edition: Edition,
204) -> String {
205    let mut p = Printer {
206        db,
207        store,
208        buf: String::new(),
209        indent_level: 0,
210        line_format: LineFormat::Newline,
211        edition,
212    };
213    p.print_path(path);
214    p.buf
215}
216
217pub fn print_struct(
218    db: &dyn SourceDatabase,
219    id: StructId,
220    StructSignature { name, generic_params, store, flags, shape }: &StructSignature,
221    edition: Edition,
222) -> String {
223    let mut p = Printer {
224        db,
225        store,
226        buf: String::new(),
227        indent_level: 0,
228        line_format: LineFormat::Newline,
229        edition,
230    };
231    if let Some(repr) = AttrFlags::repr(db, id.into()) {
232        if repr.c() {
233            wln!(p, "#[repr(C)]");
234        }
235        if let Some(align) = repr.align {
236            wln!(p, "#[repr(align({}))]", align.bytes());
237        }
238        if let Some(pack) = repr.pack {
239            wln!(p, "#[repr(pack({}))]", pack.bytes());
240        }
241    }
242    if flags.contains(StructFlags::FUNDAMENTAL) {
243        wln!(p, "#[fundamental]");
244    }
245    w!(p, "struct ");
246    w!(p, "{}", name.display(db, edition));
247    print_generic_params(db, generic_params, &mut p);
248    match shape {
249        FieldsShape::Record => wln!(p, " {{...}}"),
250        FieldsShape::Tuple => wln!(p, "(...)"),
251        FieldsShape::Unit => (),
252    }
253
254    print_where_clauses(db, generic_params, &mut p);
255
256    match shape {
257        FieldsShape::Record => wln!(p),
258        FieldsShape::Tuple => wln!(p, ";"),
259        FieldsShape::Unit => wln!(p, ";"),
260    }
261
262    p.buf
263}
264
265pub fn print_function(
266    db: &dyn SourceDatabase,
267    id: FunctionId,
268    signature @ FunctionSignature {
269        name,
270        generic_params,
271        store,
272        params,
273        ret_type,
274        abi,
275        flags,
276    }: &FunctionSignature,
277    edition: Edition,
278) -> String {
279    let legacy_const_generics_indices = signature.legacy_const_generics_indices(db, id);
280    let mut p = Printer {
281        db,
282        store,
283        buf: String::new(),
284        indent_level: 0,
285        line_format: LineFormat::Newline,
286        edition,
287    };
288    if flags.contains(FnFlags::CONST) {
289        w!(p, "const ");
290    }
291    if flags.contains(FnFlags::ASYNC) {
292        w!(p, "async ");
293    }
294    if flags.contains(FnFlags::UNSAFE) {
295        w!(p, "unsafe ");
296    }
297    if flags.contains(FnFlags::EXPLICIT_SAFE) {
298        w!(p, "safe ");
299    }
300    if *abi != ExternAbi::Rust {
301        w!(p, "extern \"{}\" ", abi.as_str());
302    }
303    w!(p, "fn ");
304    w!(p, "{}", name.display(db, edition));
305    print_generic_params(db, generic_params, &mut p);
306    w!(p, "(");
307    for (i, param) in params.iter().enumerate() {
308        if i != 0 {
309            w!(p, ", ");
310        }
311        if legacy_const_generics_indices.is_some_and(|idx| idx.contains(&(i as u32))) {
312            w!(p, "const: ");
313        }
314        p.print_type_ref(*param);
315    }
316    w!(p, ")");
317    if let Some(ret_type) = ret_type {
318        w!(p, " -> ");
319        p.print_type_ref(*ret_type);
320    }
321
322    print_where_clauses(db, generic_params, &mut p);
323    wln!(p, " {{...}}");
324
325    p.buf
326}
327
328fn print_where_clauses(
329    db: &dyn SourceDatabase,
330    generic_params: &GenericParams,
331    p: &mut Printer<'_>,
332) {
333    if !generic_params.where_predicates.is_empty() {
334        w!(p, "\nwhere\n");
335        p.indented(|p| {
336            for (i, pred) in generic_params.where_predicates.iter().enumerate() {
337                if i != 0 {
338                    w!(p, ",\n");
339                }
340                match pred {
341                    WherePredicate::TypeBound { lifetimes, target, bound } => {
342                        if let Some(lifetimes) = lifetimes {
343                            w!(p, "for<");
344                            for (i, lifetime) in lifetimes.iter().enumerate() {
345                                if i != 0 {
346                                    w!(p, ", ");
347                                }
348                                w!(p, "{}", lifetime.display(db, p.edition));
349                            }
350                            w!(p, "> ");
351                        }
352                        p.print_type_ref(*target);
353                        w!(p, ": ");
354                        p.print_type_bounds(std::slice::from_ref(bound));
355                    }
356                    WherePredicate::Lifetime { target, bound } => {
357                        p.print_lifetime_ref(*target);
358                        w!(p, ": ");
359                        p.print_lifetime_ref(*bound);
360                    }
361                }
362            }
363        });
364        wln!(p);
365    }
366}
367
368fn print_generic_params(
369    db: &dyn SourceDatabase,
370    generic_params: &GenericParams,
371    p: &mut Printer<'_>,
372) {
373    if !generic_params.is_empty() {
374        w!(p, "<");
375        let mut first = true;
376        for (_i, param) in generic_params.iter_lt() {
377            if !first {
378                w!(p, ", ");
379            }
380            first = false;
381            w!(p, "{}", param.name.display(db, p.edition));
382        }
383        for (i, param) in generic_params.iter_type_or_consts() {
384            if !first {
385                w!(p, ", ");
386            }
387            first = false;
388            if let Some(const_param) = param.const_param() {
389                w!(p, "const {}: ", const_param.name.display(db, p.edition));
390                p.print_type_ref(const_param.ty);
391                if let Some(default) = const_param.default {
392                    w!(p, " = ");
393                    p.print_expr(default.expr);
394                }
395            }
396            if let Some(type_param) = param.type_param() {
397                match &type_param.name {
398                    Some(name) => w!(p, "{}", name.display(db, p.edition)),
399                    None => w!(p, "Param[{}]", i.into_raw()),
400                }
401                if let Some(default) = type_param.default {
402                    w!(p, " = ");
403                    p.print_type_ref(default);
404                }
405            }
406        }
407        w!(p, ">");
408    }
409}
410
411pub fn print_expr_hir(
412    db: &dyn SourceDatabase,
413    store: &ExpressionStore,
414    _owner: ExpressionStoreOwnerId,
415    expr: ExprId,
416    edition: Edition,
417) -> String {
418    let mut p = Printer {
419        db,
420        store,
421        buf: String::new(),
422        indent_level: 0,
423        line_format: LineFormat::Newline,
424        edition,
425    };
426    p.print_expr(expr);
427    p.buf
428}
429
430pub fn print_pat_hir(
431    db: &dyn SourceDatabase,
432    store: &ExpressionStore,
433    _owner: ExpressionStoreOwnerId,
434    pat: PatId,
435    oneline: bool,
436    edition: Edition,
437) -> String {
438    let mut p = Printer {
439        db,
440        store,
441        buf: String::new(),
442        indent_level: 0,
443        line_format: if oneline { LineFormat::Oneline } else { LineFormat::Newline },
444        edition,
445    };
446    p.print_pat(pat);
447    p.buf
448}
449
450struct Printer<'a> {
451    db: &'a dyn SourceDatabase,
452    store: &'a ExpressionStore,
453    buf: String,
454    indent_level: usize,
455    line_format: LineFormat,
456    edition: Edition,
457}
458
459impl Write for Printer<'_> {
460    fn write_str(&mut self, s: &str) -> fmt::Result {
461        for line in s.split_inclusive('\n') {
462            if matches!(self.line_format, LineFormat::Indentation) {
463                match self.buf.chars().rev().find(|ch| *ch != ' ') {
464                    Some('\n') | None => {}
465                    _ => self.buf.push('\n'),
466                }
467                self.buf.push_str(&"    ".repeat(self.indent_level));
468            }
469
470            self.buf.push_str(line);
471
472            if matches!(self.line_format, LineFormat::Newline | LineFormat::Indentation) {
473                self.line_format = if line.ends_with('\n') {
474                    LineFormat::Indentation
475                } else {
476                    LineFormat::Newline
477                };
478            }
479        }
480
481        Ok(())
482    }
483}
484
485impl Printer<'_> {
486    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
487        self.indent_level += 1;
488        wln!(self);
489        f(self);
490        self.indent_level -= 1;
491        self.buf = self.buf.trim_end_matches('\n').to_owned();
492    }
493
494    fn whitespace(&mut self) {
495        match self.buf.chars().next_back() {
496            None | Some('\n' | ' ') => {}
497            _ => self.buf.push(' '),
498        }
499    }
500
501    // Add a newline if the current line is not empty.
502    // If the current line is empty, add a space instead.
503    //
504    // Do not use [`writeln!()`] or [`wln!()`] here, which will result in
505    // infinite recursive calls to this function.
506    fn newline(&mut self) {
507        if matches!(self.line_format, LineFormat::Oneline) {
508            match self.buf.chars().last() {
509                Some(' ') | None => {}
510                Some(_) => {
511                    w!(self, " ");
512                }
513            }
514        } else {
515            match self.buf.chars().rev().find_position(|ch| *ch != ' ') {
516                Some((_, '\n')) | None => {}
517                Some((idx, _)) => {
518                    if idx != 0 {
519                        self.buf.drain(self.buf.len() - idx..);
520                    }
521                    w!(self, "\n");
522                }
523            }
524        }
525    }
526
527    fn print_expr(&mut self, expr: ExprId) {
528        self.print_expr_in(None, expr);
529    }
530
531    fn print_expr_in(&mut self, prec: Option<ast::prec::ExprPrecedence>, expr: ExprId) {
532        let expr = &self.store[expr];
533        let needs_parens = match (prec, expr.precedence()) {
534            (Some(ast::prec::ExprPrecedence::LOr), ast::prec::ExprPrecedence::LOr) => false,
535            (Some(ast::prec::ExprPrecedence::LAnd), ast::prec::ExprPrecedence::LAnd) => false,
536            (Some(parent), prec) => prec.needs_parentheses_in(parent),
537            (None, _) => false,
538        };
539        let prec = Some(expr.precedence());
540
541        if needs_parens {
542            w!(self, "(");
543        }
544
545        match expr {
546            Expr::Missing => w!(self, "�"),
547            Expr::Underscore => w!(self, "_"),
548            Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
549            Expr::IncludeBytes => w!(self, "include_bytes!(_)"),
550            Expr::OffsetOf(offset_of) => {
551                w!(self, "builtin#offset_of(");
552                self.print_type_ref(offset_of.container);
553                let edition = self.edition;
554                w!(
555                    self,
556                    ", {})",
557                    offset_of
558                        .fields
559                        .iter()
560                        .format_with(".", |field, f| f(&field.display(self.db, edition)))
561                );
562            }
563            Expr::Path(path) => self.print_path(path),
564            Expr::If { condition, then_branch, else_branch } => {
565                w!(self, "if ");
566                self.print_expr(*condition);
567                w!(self, " ");
568                self.print_expr(*then_branch);
569                if let Some(els) = *else_branch {
570                    w!(self, " else ");
571                    self.print_expr(els);
572                }
573            }
574            Expr::Let { pat, expr } => {
575                w!(self, "let ");
576                self.print_pat(*pat);
577                w!(self, " = ");
578                self.print_expr_in(prec, *expr);
579            }
580            Expr::Loop { body, label, source: _ } => {
581                if let Some(lbl) = label {
582                    w!(self, "{}: ", self.store[*lbl].name.display(self.db, self.edition));
583                }
584                w!(self, "loop ");
585                self.print_expr(*body);
586            }
587            Expr::Call { callee, args } => {
588                self.print_expr_in(prec, *callee);
589                w!(self, "(");
590                if !args.is_empty() {
591                    self.indented(|p| {
592                        for arg in &**args {
593                            p.print_expr(*arg);
594                            wln!(p, ",");
595                        }
596                    });
597                }
598                w!(self, ")");
599            }
600            Expr::MethodCall { receiver, method_name, args, generic_args } => {
601                self.print_expr_in(prec, *receiver);
602                w!(self, ".{}", method_name.display(self.db, self.edition));
603                if let Some(args) = generic_args {
604                    w!(self, "::<");
605                    self.print_generic_args(args);
606                    w!(self, ">");
607                }
608                w!(self, "(");
609                if !args.is_empty() {
610                    self.indented(|p| {
611                        for arg in &**args {
612                            p.print_expr(*arg);
613                            wln!(p, ",");
614                        }
615                    });
616                }
617                w!(self, ")");
618            }
619            Expr::Match { expr, arms } => {
620                w!(self, "match ");
621                self.print_expr(*expr);
622                w!(self, " {{");
623                self.indented(|p| {
624                    for arm in &**arms {
625                        p.print_pat(arm.pat);
626                        if let Some(guard) = arm.guard {
627                            w!(p, " if ");
628                            p.print_expr(guard);
629                        }
630                        w!(p, " => ");
631                        p.print_expr(arm.expr);
632                        wln!(p, ",");
633                    }
634                });
635                wln!(self, "}}");
636            }
637            Expr::Continue { label } => {
638                w!(self, "continue");
639                if let Some(lbl) = label {
640                    w!(self, " {}", self.store[*lbl].name.display(self.db, self.edition));
641                }
642            }
643            Expr::Break { expr, label } => {
644                w!(self, "break");
645                if let Some(lbl) = label {
646                    w!(self, " {}", self.store[*lbl].name.display(self.db, self.edition));
647                }
648                if let Some(expr) = expr {
649                    self.whitespace();
650                    self.print_expr_in(prec, *expr);
651                }
652            }
653            Expr::Return { expr } => {
654                w!(self, "return");
655                if let Some(expr) = expr {
656                    self.whitespace();
657                    self.print_expr_in(prec, *expr);
658                }
659            }
660            Expr::Become { expr } => {
661                w!(self, "become");
662                self.whitespace();
663                self.print_expr_in(prec, *expr);
664            }
665            Expr::Yield { expr } => {
666                w!(self, "yield");
667                if let Some(expr) = expr {
668                    self.whitespace();
669                    self.print_expr_in(prec, *expr);
670                }
671            }
672            Expr::Yeet { expr } => {
673                w!(self, "do");
674                self.whitespace();
675                w!(self, "yeet");
676                if let Some(expr) = expr {
677                    self.whitespace();
678                    self.print_expr_in(prec, *expr);
679                }
680            }
681            Expr::RecordLit { path, fields, spread } => {
682                self.print_path(path);
683
684                w!(self, "{{");
685                let edition = self.edition;
686                self.indented(|p| {
687                    for field in &**fields {
688                        w!(p, "{}: ", field.name.display(self.db, edition));
689                        p.print_expr(field.expr);
690                        wln!(p, ",");
691                    }
692                    match spread {
693                        RecordSpread::None => {}
694                        RecordSpread::FieldDefaults => {
695                            w!(p, "..");
696                            wln!(p);
697                        }
698                        RecordSpread::Expr(spread_expr) => {
699                            w!(p, "..");
700                            p.print_expr(*spread_expr);
701                            wln!(p);
702                        }
703                    }
704                });
705                w!(self, "}}");
706            }
707            Expr::Field { expr, name } => {
708                self.print_expr_in(prec, *expr);
709                w!(self, ".{}", name.display(self.db, self.edition));
710            }
711            Expr::Await { expr } => {
712                self.print_expr_in(prec, *expr);
713                w!(self, ".await");
714            }
715            Expr::Cast { expr, type_ref } => {
716                self.print_expr_in(prec, *expr);
717                w!(self, " as ");
718                self.print_type_ref(*type_ref);
719            }
720            Expr::Ref { expr, rawness, mutability } => {
721                w!(self, "&");
722                if rawness.is_raw() {
723                    w!(self, "raw ");
724                }
725                if mutability.is_mut() {
726                    w!(self, "mut ");
727                }
728                self.print_expr_in(prec, *expr);
729            }
730            Expr::UnaryOp { expr, op } => {
731                let op = match op {
732                    ast::UnaryOp::Deref => "*",
733                    ast::UnaryOp::Not => "!",
734                    ast::UnaryOp::Neg => "-",
735                };
736                w!(self, "{}", op);
737                self.print_expr_in(prec, *expr);
738            }
739            Expr::BinaryOp { lhs, rhs, op } => {
740                self.print_expr_in(prec, *lhs);
741                self.whitespace();
742                match op {
743                    Some(op) => w!(self, "{}", op),
744                    None => w!(self, "�"), // :)
745                }
746                self.whitespace();
747                self.print_expr_in(prec, *rhs);
748            }
749            Expr::Index { base, index } => {
750                self.print_expr_in(prec, *base);
751                w!(self, "[");
752                self.print_expr(*index);
753                w!(self, "]");
754            }
755            Expr::Closure { args, arg_types, ret_type, body, closure_kind, capture_by } => {
756                let mut body = *body;
757                let mut print_pipes = true;
758                match closure_kind {
759                    ClosureKind::OldCoroutine(Movability::Static) => {
760                        w!(self, "static ");
761                    }
762                    ClosureKind::CoroutineClosure(kind) => {
763                        if let Expr::Closure {
764                            body: inner_body,
765                            closure_kind: ClosureKind::Coroutine { .. },
766                            ..
767                        } = self.store[body]
768                        {
769                            body = inner_body;
770                        } else {
771                            never!("coroutine closure should always have a coroutine body");
772                        }
773
774                        match kind {
775                            CoroutineKind::Async => w!(self, "async "),
776                            CoroutineKind::Gen => w!(self, "gen "),
777                            CoroutineKind::AsyncGen => w!(self, "async gen "),
778                        }
779                    }
780                    ClosureKind::Coroutine { kind, .. } => {
781                        match kind {
782                            CoroutineKind::Async => w!(self, "async "),
783                            CoroutineKind::Gen => w!(self, "gen "),
784                            CoroutineKind::AsyncGen => w!(self, "async gen "),
785                        }
786                        print_pipes = false;
787                    }
788                    ClosureKind::Closure | ClosureKind::OldCoroutine(Movability::Movable) => (),
789                }
790                match capture_by {
791                    CaptureBy::Value => {
792                        w!(self, "move ");
793                    }
794                    CaptureBy::Ref => (),
795                }
796                if print_pipes {
797                    w!(self, "|");
798                    for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
799                        if i != 0 {
800                            w!(self, ", ");
801                        }
802                        self.print_pat(*pat);
803                        if let Some(ty) = ty {
804                            w!(self, ": ");
805                            self.print_type_ref(*ty);
806                        }
807                    }
808                    w!(self, "|");
809                    if let Some(ret_ty) = ret_type {
810                        w!(self, " -> ");
811                        self.print_type_ref(*ret_ty);
812                    }
813                    self.whitespace();
814                }
815                self.print_expr(body);
816            }
817            Expr::Tuple { exprs } => {
818                w!(self, "(");
819                for expr in exprs.iter() {
820                    self.print_expr(*expr);
821                    w!(self, ", ");
822                }
823                w!(self, ")");
824            }
825            Expr::Array(arr) => {
826                w!(self, "[");
827                if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
828                    self.indented(|p| match arr {
829                        Array::ElementList { elements } => {
830                            for elem in elements.iter() {
831                                p.print_expr(*elem);
832                                w!(p, ", ");
833                            }
834                        }
835                        Array::Repeat { initializer, repeat } => {
836                            p.print_expr(*initializer);
837                            w!(p, "; ");
838                            p.print_expr(*repeat);
839                        }
840                    });
841                    self.newline();
842                }
843                w!(self, "]");
844            }
845            Expr::Literal(lit) => self.print_literal(lit),
846            Expr::Block { id: _, statements, tail, label, unsafe_ } => {
847                let label = label.map(|lbl| {
848                    format!("{}: ", self.store[lbl].name.display(self.db, self.edition))
849                });
850                self.print_block(label.as_deref(), *unsafe_, statements, tail);
851            }
852            Expr::Const(id) => {
853                w!(self, "const {{ /* {id:?} */ }}");
854            }
855            &Expr::Assignment { target, value } => {
856                self.print_pat(target);
857                w!(self, " = ");
858                self.print_expr_in(prec, value);
859            }
860        }
861
862        if needs_parens {
863            w!(self, ")");
864        }
865    }
866
867    fn print_block(
868        &mut self,
869        label: Option<&str>,
870        unsafe_: Unsafe,
871        statements: &[Statement],
872        tail: &Option<la_arena::Idx<Expr>>,
873    ) {
874        self.whitespace();
875        if let Some(lbl) = label {
876            w!(self, "{}", lbl);
877        }
878        if unsafe_ == Unsafe::Yes {
879            w!(self, "unsafe ");
880        }
881        w!(self, "{{");
882        if !statements.is_empty() || tail.is_some() {
883            self.indented(|p| {
884                for stmt in statements {
885                    p.print_stmt(stmt);
886                }
887                if let Some(tail) = tail {
888                    p.print_expr(*tail);
889                }
890                p.newline();
891            });
892        }
893        w!(self, "}}");
894    }
895
896    fn print_pat(&mut self, pat: PatId) {
897        let prec = Some(ast::prec::ExprPrecedence::Shift);
898        let pat = &self.store[pat];
899
900        match pat {
901            Pat::Missing => w!(self, "�"),
902            Pat::Rest => w!(self, ".."),
903            Pat::Wild => w!(self, "_"),
904            Pat::NotNull => w!(self, "!null"),
905            Pat::Tuple { args, ellipsis } => {
906                w!(self, "(");
907                for (i, pat) in args.iter().enumerate() {
908                    if i != 0 {
909                        w!(self, ", ");
910                    }
911                    if *ellipsis == Some(i as u32) {
912                        w!(self, ".., ");
913                    }
914                    self.print_pat(*pat);
915                }
916                w!(self, ")");
917            }
918            Pat::Or(pats) => {
919                w!(self, "(");
920                for (i, pat) in pats.iter().enumerate() {
921                    if i != 0 {
922                        w!(self, " | ");
923                    }
924                    self.print_pat(*pat);
925                }
926                w!(self, ")");
927            }
928            Pat::Record { path, args, ellipsis } => {
929                self.print_path(path);
930
931                w!(self, " {{");
932                let edition = self.edition;
933                let oneline = matches!(self.line_format, LineFormat::Oneline);
934                self.indented(|p| {
935                    for (idx, arg) in args.iter().enumerate() {
936                        let field_name = arg.name.display(self.db, edition).to_string();
937
938                        let mut same_name = false;
939                        if let Pat::Bind { id, subpat: None } = &self.store[arg.pat]
940                            && let Binding { name, mode: BindingAnnotation::Unannotated, .. } =
941                                &self.store.assert_expr_only().bindings[*id]
942                            && name.as_str() == field_name
943                        {
944                            same_name = true;
945                        }
946
947                        w!(p, "{}", field_name);
948
949                        if !same_name {
950                            w!(p, ": ");
951                            p.print_pat(arg.pat);
952                        }
953
954                        // Do not print the extra comma if the line format is oneline
955                        if oneline && idx == args.len() - 1 {
956                            w!(p, " ");
957                        } else {
958                            wln!(p, ",");
959                        }
960                    }
961
962                    if *ellipsis {
963                        wln!(p, "..");
964                    }
965                });
966                w!(self, "}}");
967            }
968            Pat::Range { start, end, range_type } => {
969                if let Some(start) = start {
970                    self.print_expr_in(prec, *start);
971                }
972                match range_type {
973                    RangeOp::Inclusive => w!(self, "..="),
974                    RangeOp::Exclusive => w!(self, ".."),
975                }
976                if let Some(end) = end {
977                    self.print_expr_in(prec, *end);
978                }
979            }
980            Pat::Slice { prefix, slice, suffix } => {
981                w!(self, "[");
982                for pat in prefix.iter() {
983                    self.print_pat(*pat);
984                    w!(self, ", ");
985                }
986                if let Some(pat) = slice {
987                    self.print_pat(*pat);
988                    w!(self, ", ");
989                }
990                for pat in suffix.iter() {
991                    self.print_pat(*pat);
992                    w!(self, ", ");
993                }
994                w!(self, "]");
995            }
996            Pat::Path(path) => self.print_path(path),
997            Pat::Lit(expr) => self.print_expr_in(prec, *expr),
998            Pat::Bind { id, subpat } => {
999                self.print_binding(*id);
1000                if let Some(pat) = subpat {
1001                    self.whitespace();
1002                    w!(self, "@ ");
1003                    self.print_pat(*pat);
1004                }
1005            }
1006            Pat::TupleStruct { path, args, ellipsis } => {
1007                self.print_path(path);
1008                w!(self, "(");
1009                for (i, arg) in args.iter().enumerate() {
1010                    if i != 0 {
1011                        w!(self, ", ");
1012                    }
1013                    if *ellipsis == Some(i as u32) {
1014                        w!(self, ", ..");
1015                    }
1016                    self.print_pat(*arg);
1017                }
1018                w!(self, ")");
1019            }
1020            Pat::Ref { pat, mutability } => {
1021                w!(self, "&");
1022                if mutability.is_mut() {
1023                    w!(self, "mut ");
1024                }
1025                self.print_pat(*pat);
1026            }
1027            Pat::Box { inner } => {
1028                w!(self, "box ");
1029                self.print_pat(*inner);
1030            }
1031            Pat::Deref { inner } => {
1032                w!(self, "deref!(");
1033                self.print_pat(*inner);
1034                w!(self, ")");
1035            }
1036            Pat::Expr(expr) => {
1037                self.print_expr_in(prec, *expr);
1038            }
1039        }
1040    }
1041
1042    fn print_stmt(&mut self, stmt: &Statement) {
1043        match stmt {
1044            Statement::Let { pat, type_ref, initializer, else_branch } => {
1045                w!(self, "let ");
1046                self.print_pat(*pat);
1047                if let Some(ty) = type_ref {
1048                    w!(self, ": ");
1049                    self.print_type_ref(*ty);
1050                }
1051                if let Some(init) = initializer {
1052                    w!(self, " = ");
1053                    self.print_expr(*init);
1054                }
1055                if let Some(els) = else_branch {
1056                    w!(self, " else ");
1057                    self.print_expr(*els);
1058                }
1059                wln!(self, ";");
1060            }
1061            Statement::Expr { expr, has_semi } => {
1062                self.print_expr(*expr);
1063                if *has_semi {
1064                    w!(self, ";");
1065                }
1066                wln!(self);
1067            }
1068            Statement::Item(_) => (),
1069        }
1070    }
1071
1072    fn print_literal(&mut self, literal: &Literal) {
1073        match literal {
1074            Literal::String(it) => w!(self, "{:?}", it),
1075            Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
1076            Literal::CString(it) => w!(self, "\"{}\\0\"", it.escape_ascii()),
1077            Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
1078            Literal::Bool(it) => w!(self, "{}", it),
1079            Literal::Int(i, suffix) => {
1080                w!(self, "{}", i);
1081                if let Some(suffix) = suffix {
1082                    w!(self, "{}", suffix);
1083                }
1084            }
1085            Literal::Uint(i, suffix) => {
1086                w!(self, "{}", i);
1087                if let Some(suffix) = suffix {
1088                    w!(self, "{}", suffix);
1089                }
1090            }
1091            Literal::Float(f, suffix) => {
1092                w!(self, "{}", f);
1093                if let Some(suffix) = suffix {
1094                    w!(self, "{}", suffix);
1095                }
1096            }
1097        }
1098    }
1099
1100    fn print_binding(&mut self, id: BindingId) {
1101        let Binding { name, mode, .. } = &self.store.assert_expr_only().bindings[id];
1102        let mode = match mode {
1103            BindingAnnotation::Unannotated => "",
1104            BindingAnnotation::Mutable => "mut ",
1105            BindingAnnotation::Ref => "ref ",
1106            BindingAnnotation::RefMut => "ref mut ",
1107        };
1108        w!(self, "{}{}", mode, name.display(self.db, self.edition));
1109    }
1110
1111    fn print_path(&mut self, path: &Path) {
1112        if let Path::LangItem(it, s) = path {
1113            w!(self, "builtin#lang(");
1114            macro_rules! write_name {
1115                ($it:ident) => {{
1116                    w!(self, "{}", item_name(self.db, $it, "<missing>"));
1117                }};
1118            }
1119            match *it {
1120                LangItemTarget::ImplId(it) => w!(self, "{it:?}"),
1121                LangItemTarget::EnumId(it) => write_name!(it),
1122                LangItemTarget::FunctionId(it) => write_name!(it),
1123                LangItemTarget::StaticId(it) => write_name!(it),
1124                LangItemTarget::StructId(it) => write_name!(it),
1125                LangItemTarget::UnionId(it) => write_name!(it),
1126                LangItemTarget::TypeAliasId(it) => write_name!(it),
1127                LangItemTarget::TraitId(it) => write_name!(it),
1128                LangItemTarget::EnumVariantId(it) => write_name!(it),
1129                LangItemTarget::ConstId(it) => write_name!(it),
1130                LangItemTarget::MacroId(MacroId::Macro2Id(it)) => write_name!(it),
1131                LangItemTarget::MacroId(MacroId::MacroRulesId(it)) => write_name!(it),
1132                LangItemTarget::MacroId(MacroId::ProcMacroId(it)) => write_name!(it),
1133            }
1134
1135            if let Some(s) = s {
1136                w!(self, "::{}", s.display(self.db, self.edition));
1137            }
1138            return w!(self, ")");
1139        }
1140        match path.type_anchor() {
1141            Some(anchor) => {
1142                w!(self, "<");
1143                self.print_type_ref(anchor);
1144                w!(self, ">::");
1145            }
1146            None => match path.kind() {
1147                PathKind::Plain => {}
1148                &PathKind::SELF => w!(self, "self"),
1149                PathKind::Super(n) => {
1150                    for i in 0..*n {
1151                        if i == 0 {
1152                            w!(self, "super");
1153                        } else {
1154                            w!(self, "::super");
1155                        }
1156                    }
1157                }
1158                PathKind::Crate => w!(self, "crate"),
1159                PathKind::Abs => {}
1160                PathKind::DollarCrate(krate) => w!(
1161                    self,
1162                    "{}",
1163                    krate
1164                        .extra_data(self.db)
1165                        .display_name
1166                        .as_ref()
1167                        .map(|it| it.crate_name().symbol().as_str())
1168                        .unwrap_or("$crate")
1169                ),
1170            },
1171        }
1172
1173        for (i, segment) in path.segments().iter().enumerate() {
1174            if i != 0 || !matches!(path.kind(), PathKind::Plain) {
1175                w!(self, "::");
1176            }
1177
1178            w!(self, "{}", segment.name.display(self.db, self.edition));
1179            if let Some(generics) = segment.args_and_bindings {
1180                w!(self, "::<");
1181                self.print_generic_args(generics);
1182
1183                w!(self, ">");
1184            }
1185        }
1186    }
1187
1188    pub(crate) fn print_generic_args(&mut self, generics: &GenericArgs) {
1189        let mut first = true;
1190        let args = if generics.has_self_type {
1191            let (self_ty, args) = generics.args.split_first().unwrap();
1192            w!(self, "Self=");
1193            self.print_generic_arg(self_ty);
1194            first = false;
1195            args
1196        } else {
1197            &generics.args
1198        };
1199        for arg in args {
1200            if !first {
1201                w!(self, ", ");
1202            }
1203            first = false;
1204            self.print_generic_arg(arg);
1205        }
1206        for binding in generics.bindings.iter() {
1207            if !first {
1208                w!(self, ", ");
1209            }
1210            first = false;
1211            w!(self, "{}", binding.name.display(self.db, self.edition));
1212            if !binding.bounds.is_empty() {
1213                w!(self, ": ");
1214                self.print_type_bounds(&binding.bounds);
1215            }
1216            if let Some(ty) = binding.type_ref {
1217                w!(self, " = ");
1218                self.print_type_ref(ty);
1219            }
1220        }
1221    }
1222
1223    pub(crate) fn print_generic_arg(&mut self, arg: &GenericArg) {
1224        match arg {
1225            GenericArg::Type(ty) => self.print_type_ref(*ty),
1226            GenericArg::Const(ConstRef { expr }) => {
1227                self.print_expr_in(Some(ast::prec::ExprPrecedence::Unambiguous), *expr)
1228            }
1229            GenericArg::Lifetime(lt) => self.print_lifetime_ref(*lt),
1230        }
1231    }
1232
1233    pub(crate) fn print_type_param(&mut self, param: TypeParamId) {
1234        let generic_params = GenericParams::of(self.db, param.parent());
1235
1236        match generic_params[param.local_id()].name() {
1237            Some(name) => w!(self, "{}", name.display(self.db, self.edition)),
1238            None => w!(self, "Param[{}]", param.local_id().into_raw()),
1239        }
1240    }
1241
1242    pub(crate) fn print_lifetime_param(&mut self, param: LifetimeParamId) {
1243        let generic_params = GenericParams::of(self.db, param.parent);
1244        w!(self, "{}", generic_params[param.local_id].name.display(self.db, self.edition))
1245    }
1246
1247    pub(crate) fn print_lifetime_ref(&mut self, lt_ref: LifetimeRefId) {
1248        match &self.store[lt_ref] {
1249            LifetimeRef::Static => w!(self, "'static"),
1250            LifetimeRef::Named(lt) => {
1251                w!(self, "{}", lt.display(self.db, self.edition))
1252            }
1253            LifetimeRef::Placeholder => w!(self, "'_"),
1254            LifetimeRef::Error => w!(self, "'{{error}}"),
1255            &LifetimeRef::Param(p) => self.print_lifetime_param(p),
1256        }
1257    }
1258
1259    pub(crate) fn print_type_ref(&mut self, type_ref: TypeRefId) {
1260        // FIXME: deduplicate with `HirDisplay` impl
1261        match &self.store[type_ref] {
1262            TypeRef::Never => w!(self, "!"),
1263            &TypeRef::TypeParam(p) => self.print_type_param(p),
1264            TypeRef::Placeholder => w!(self, "_"),
1265            TypeRef::Tuple(fields) => {
1266                w!(self, "(");
1267                for (i, field) in fields.iter().enumerate() {
1268                    if i != 0 {
1269                        w!(self, ", ");
1270                    }
1271                    self.print_type_ref(*field);
1272                }
1273                w!(self, ")");
1274            }
1275            TypeRef::Path(path) => self.print_path(path),
1276            TypeRef::RawPtr(pointee, mtbl) => {
1277                let mtbl = match mtbl {
1278                    Mutability::Shared => "*const",
1279                    Mutability::Mut => "*mut",
1280                };
1281                w!(self, "{mtbl} ");
1282                self.print_type_ref(*pointee);
1283            }
1284            TypeRef::Reference(ref_) => {
1285                let mtbl = match ref_.mutability {
1286                    Mutability::Shared => "",
1287                    Mutability::Mut => "mut ",
1288                };
1289                w!(self, "&");
1290                if let Some(lt) = &ref_.lifetime {
1291                    self.print_lifetime_ref(*lt);
1292                    w!(self, " ");
1293                }
1294                w!(self, "{mtbl}");
1295                self.print_type_ref(ref_.ty);
1296            }
1297            TypeRef::Array(array) => {
1298                w!(self, "[");
1299                self.print_type_ref(array.ty);
1300                w!(self, "; ");
1301                self.print_generic_arg(&GenericArg::Const(array.len));
1302                w!(self, "]");
1303            }
1304            TypeRef::Slice(elem) => {
1305                w!(self, "[");
1306                self.print_type_ref(*elem);
1307                w!(self, "]");
1308            }
1309            TypeRef::Fn(fn_) => {
1310                let ((_, return_type), args) =
1311                    fn_.params.split_last().expect("TypeRef::Fn is missing return type");
1312                if let Some(binder) = &fn_.binder {
1313                    w!(
1314                        self,
1315                        "for<{}> ",
1316                        binder
1317                            .iter()
1318                            .map(|it| it.display(self.db, self.edition))
1319                            .format(", ")
1320                            .to_string()
1321                    );
1322                }
1323                if fn_.is_unsafe {
1324                    w!(self, "unsafe ");
1325                }
1326                if fn_.abi != ExternAbi::Rust {
1327                    w!(self, "extern ");
1328                    w!(self, "{}", fn_.abi.as_str());
1329                    w!(self, " ");
1330                }
1331                w!(self, "fn(");
1332                for (i, (_, typeref)) in args.iter().enumerate() {
1333                    if i != 0 {
1334                        w!(self, ", ");
1335                    }
1336                    self.print_type_ref(*typeref);
1337                }
1338                if fn_.is_varargs {
1339                    if !args.is_empty() {
1340                        w!(self, ", ");
1341                    }
1342                    w!(self, "...");
1343                }
1344                w!(self, ") -> ");
1345                self.print_type_ref(*return_type);
1346            }
1347            TypeRef::Error => w!(self, "{{error}}"),
1348            TypeRef::ImplTrait(bounds) => {
1349                w!(self, "impl ");
1350                self.print_type_bounds(bounds);
1351            }
1352            TypeRef::DynTrait(bounds) => {
1353                w!(self, "dyn ");
1354                self.print_type_bounds(bounds);
1355            }
1356            TypeRef::PatternType(ty, pat) => {
1357                self.print_type_ref(*ty);
1358                w!(self, " is ");
1359                self.print_pat(*pat);
1360            }
1361        }
1362    }
1363
1364    pub(crate) fn print_type_bounds(&mut self, bounds: &[TypeBound]) {
1365        for (i, bound) in bounds.iter().enumerate() {
1366            if i != 0 {
1367                w!(self, " + ");
1368            }
1369
1370            match bound {
1371                TypeBound::Path(path, modifier) => {
1372                    match modifier {
1373                        TraitBoundModifier::None => (),
1374                        TraitBoundModifier::Maybe => w!(self, "?"),
1375                    }
1376                    self.print_path(&self.store[*path]);
1377                }
1378                TypeBound::ForLifetime(lifetimes, path) => {
1379                    w!(
1380                        self,
1381                        "for<{}> ",
1382                        lifetimes
1383                            .iter()
1384                            .map(|it| it.display(self.db, self.edition))
1385                            .format(", ")
1386                            .to_string()
1387                    );
1388                    self.print_path(&self.store[*path]);
1389                }
1390                TypeBound::Lifetime(lt) => self.print_lifetime_ref(*lt),
1391                TypeBound::Use(args) => {
1392                    w!(self, "use<");
1393                    let mut first = true;
1394                    for arg in args {
1395                        if !mem::take(&mut first) {
1396                            w!(self, ", ");
1397                        }
1398                        match arg {
1399                            UseArgRef::Name(it) => {
1400                                w!(self, "{}", it.display(self.db, self.edition))
1401                            }
1402                            UseArgRef::Lifetime(it) => self.print_lifetime_ref(*it),
1403                        }
1404                    }
1405                    w!(self, ">")
1406                }
1407                TypeBound::Error => w!(self, "{{unknown}}"),
1408            }
1409        }
1410    }
1411}