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