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