charon_lib/pretty/
fmt_with_ctx.rs

1//! Utilities for pretty-printing (u)llbc.
2use crate::{
3    common::{repeat_except_first, TAB_INCR},
4    formatter::*,
5    gast,
6    llbc_ast::{self as llbc, *},
7    reorder_decls::*,
8    transform::utils::GenericsSource,
9    ullbc_ast::{self as ullbc, *},
10};
11use either::Either;
12use itertools::Itertools;
13use std::{
14    borrow::Cow,
15    fmt::{self, Debug, Display},
16};
17
18pub struct WithCtx<'a, C, T: ?Sized> {
19    val: &'a T,
20    ctx: &'a C,
21}
22
23impl<'a, C, T: ?Sized> Display for WithCtx<'a, C, T>
24where
25    T: FmtWithCtx<C>,
26{
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        self.val.fmt_with_ctx(self.ctx, f)
29    }
30}
31
32/// Format the AST type as a string.
33pub trait FmtWithCtx<C> {
34    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result;
35
36    /// Returns a struct that implements `Display`. This allows the following:
37    /// ```text
38    ///     println!("{}", self.with_ctx(ctx));
39    /// ```
40    fn with_ctx<'a>(&'a self, ctx: &'a C) -> WithCtx<'a, C, Self> {
41        WithCtx { val: self, ctx }
42    }
43
44    fn to_string_with_ctx(&self, ctx: &C) -> String {
45        self.with_ctx(ctx).to_string()
46    }
47}
48
49macro_rules! impl_display_via_ctx {
50    ($ty:ty) => {
51        impl Display for $ty {
52            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53                self.fmt_with_ctx(&FmtCtx::new(), f)
54            }
55        }
56    };
57}
58macro_rules! impl_debug_via_display {
59    ($ty:ty) => {
60        impl Debug for $ty {
61            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62                <_ as Display>::fmt(self, f)
63            }
64        }
65    };
66}
67
68//------- Impls, sorted by name --------
69
70impl<C: AstFormatter> FmtWithCtx<C> for AbortKind {
71    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            AbortKind::Panic(name) => {
74                write!(f, "panic")?;
75                if let Some(name) = name {
76                    write!(f, "({})", name.with_ctx(ctx))?;
77                }
78                Ok(())
79            }
80            AbortKind::UndefinedBehavior => write!(f, "undefined_behavior"),
81            AbortKind::UnwindTerminate => write!(f, "unwind_terminate"),
82        }
83    }
84}
85
86impl<C: AstFormatter> FmtWithCtx<C> for AnyTransId {
87    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match ctx
89            .get_crate()
90            .and_then(|translated| translated.item_short_name(*self))
91        {
92            None => write!(f, "{self}"),
93            Some(name) => name.fmt_with_ctx(ctx, f),
94        }
95    }
96}
97
98impl Display for AnyTransId {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
100        let s = match self {
101            AnyTransId::Type(x) => x.to_pretty_string(),
102            AnyTransId::Fun(x) => x.to_pretty_string(),
103            AnyTransId::Global(x) => x.to_pretty_string(),
104            AnyTransId::TraitDecl(x) => x.to_pretty_string(),
105            AnyTransId::TraitImpl(x) => x.to_pretty_string(),
106        };
107        f.write_str(&s)
108    }
109}
110
111impl<C: AstFormatter> FmtWithCtx<C> for AnyTransItem<'_> {
112    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            AnyTransItem::Type(d) => write!(f, "{}", d.with_ctx(ctx)),
115            AnyTransItem::Fun(d) => write!(f, "{}", d.with_ctx(ctx)),
116            AnyTransItem::Global(d) => write!(f, "{}", d.with_ctx(ctx)),
117            AnyTransItem::TraitDecl(d) => write!(f, "{}", d.with_ctx(ctx)),
118            AnyTransItem::TraitImpl(d) => write!(f, "{}", d.with_ctx(ctx)),
119        }
120    }
121}
122
123impl<C: AstFormatter> FmtWithCtx<C> for Assert {
124    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        write!(
126            f,
127            "assert({} == {})",
128            self.cond.with_ctx(ctx),
129            self.expected,
130        )
131    }
132}
133
134impl<T> Binder<T> {
135    /// Format the parameters and contents of this binder and returns the resulting strings. Note:
136    /// this assumes the binder fully replaces the existing generics.
137    fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
138    where
139        C: AstFormatter,
140        T: FmtWithCtx<C::Reborrow<'a>>,
141    {
142        let ctx = &ctx.push_binder(Cow::Borrowed(&self.params));
143        (
144            self.params.fmt_with_ctx_single_line(ctx),
145            self.skip_binder.to_string_with_ctx(ctx),
146        )
147    }
148}
149
150impl Display for BinOp {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
152        match self {
153            BinOp::BitXor => write!(f, "^"),
154            BinOp::BitAnd => write!(f, "&"),
155            BinOp::BitOr => write!(f, "|"),
156            BinOp::Eq => write!(f, "=="),
157            BinOp::Lt => write!(f, "<"),
158            BinOp::Le => write!(f, "<="),
159            BinOp::Ne => write!(f, "!="),
160            BinOp::Ge => write!(f, ">="),
161            BinOp::Gt => write!(f, ">"),
162            BinOp::Div => write!(f, "/"),
163            BinOp::Rem => write!(f, "%"),
164            BinOp::Add => write!(f, "+"),
165            BinOp::Sub => write!(f, "-"),
166            BinOp::Mul => write!(f, "*"),
167            BinOp::WrappingAdd => write!(f, "wrapping.+"),
168            BinOp::WrappingSub => write!(f, "wrapping.-"),
169            BinOp::WrappingMul => write!(f, "wrapping.*"),
170            BinOp::CheckedAdd => write!(f, "checked.+"),
171            BinOp::CheckedSub => write!(f, "checked.-"),
172            BinOp::CheckedMul => write!(f, "checked.*"),
173            BinOp::Shl => write!(f, "<<"),
174            BinOp::Shr => write!(f, ">>"),
175            BinOp::Cmp => write!(f, "cmp"),
176            BinOp::Offset => write!(f, "offset"),
177        }
178    }
179}
180
181impl<C: AstFormatter> FmtWithCtx<C> for llbc::Block {
182    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        for st in &self.statements {
184            writeln!(f, "{}", st.with_ctx(ctx))?;
185        }
186        Ok(())
187    }
188}
189
190impl<C: AstFormatter> FmtWithCtx<C> for ullbc::BlockData {
191    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        for statement in &self.statements {
193            writeln!(f, "{};", statement.with_ctx(ctx))?;
194        }
195        write!(f, "{};", self.terminator.with_ctx(ctx))?;
196        Ok(())
197    }
198}
199
200impl<C: AstFormatter> FmtWithCtx<C> for gast::Body {
201    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        match self {
203            Body::Unstructured(b) => write!(f, "{}", b.with_ctx(ctx)),
204            Body::Structured(b) => write!(f, "{}", b.with_ctx(ctx)),
205        }
206    }
207}
208
209impl Display for BorrowKind {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
211        // Reuse the derived `Debug` impl to get the variant name.
212        write!(f, "{self:?}")
213    }
214}
215
216impl Display for BuiltinFunId {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
218        let name = match *self {
219            BuiltinFunId::BoxNew => "BoxNew",
220            BuiltinFunId::ArrayToSliceShared => "ArrayToSliceShared",
221            BuiltinFunId::ArrayToSliceMut => "ArrayToSliceMut",
222            BuiltinFunId::ArrayRepeat => "ArrayRepeat",
223            BuiltinFunId::Index(BuiltinIndexOp {
224                is_array,
225                mutability,
226                is_range,
227            }) => {
228                let ty = if is_array { "Array" } else { "Slice" };
229                let op = if is_range { "SubSlice" } else { "Index" };
230                let mutability = mutability.variant_name();
231                &format!("{ty}{op}{mutability}")
232            }
233            BuiltinFunId::PtrFromParts(mutability) => {
234                let mutability = mutability.variant_name();
235                &format!("PtrFromParts{mutability}")
236            }
237        };
238        f.write_str(name)
239    }
240}
241
242impl<C: AstFormatter> FmtWithCtx<C> for Call {
243    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244        let dest = self.dest.with_ctx(ctx);
245        let func = self.func.with_ctx(ctx);
246        let args = self.args.iter().map(|x| x.with_ctx(ctx)).format(", ");
247        write!(f, "{dest} := {func}({args})")
248    }
249}
250
251impl<C: AstFormatter> FmtWithCtx<C> for CastKind {
252    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253        match self {
254            CastKind::Scalar(src, tgt) => write!(f, "cast<{src}, {tgt}>"),
255            CastKind::FnPtr(src, tgt) | CastKind::RawPtr(src, tgt) => {
256                write!(f, "cast<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
257            }
258            CastKind::Unsize(src, tgt) => {
259                write!(
260                    f,
261                    "unsize_cast<{}, {}>",
262                    src.with_ctx(ctx),
263                    tgt.with_ctx(ctx)
264                )
265            }
266            CastKind::Transmute(src, tgt) => {
267                write!(f, "transmute<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
268            }
269        }
270    }
271}
272
273impl<C: AstFormatter> FmtWithCtx<C> for ClauseDbVar {
274    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275        ctx.format_bound_var(f, *self, "@TraitClause", |_| None)
276    }
277}
278
279impl_display_via_ctx!(ConstantExpr);
280impl<C: AstFormatter> FmtWithCtx<C> for ConstantExpr {
281    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        write!(f, "{}", self.value.with_ctx(ctx))
283    }
284}
285
286impl<C: AstFormatter> FmtWithCtx<C> for ConstGeneric {
287    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288        match self {
289            ConstGeneric::Var(id) => write!(f, "{}", id.with_ctx(ctx)),
290            ConstGeneric::Value(v) => write!(f, "{v}"),
291            ConstGeneric::Global(id) => write!(f, "{}", id.with_ctx(ctx)),
292        }
293    }
294}
295
296impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericDbVar {
297    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298        ctx.format_bound_var(f, *self, "@ConstGeneric", |v| Some(v.to_string()))
299    }
300}
301
302impl_display_via_ctx!(ConstGenericVar);
303impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericVar {
304    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        write!(f, "const {} : {}", self.name, self.ty)
306    }
307}
308
309impl Display for DeBruijnId {
310    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
311        write!(f, "{}", self.index)
312    }
313}
314
315impl<Id: Display> Display for DeBruijnVar<Id> {
316    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317        match self {
318            Self::Bound(dbid, varid) => write!(f, "{dbid}_{varid}"),
319            Self::Free(varid) => write!(f, "{varid}"),
320        }
321    }
322}
323
324impl<C: AstFormatter> FmtWithCtx<C> for DeclarationGroup {
325    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326        use DeclarationGroup::*;
327        match self {
328            Type(g) => write!(f, "Type decls group: {}", g.with_ctx(ctx)),
329            Fun(g) => write!(f, "Fun decls group: {}", g.with_ctx(ctx)),
330            Global(g) => write!(f, "Global decls group: {}", g.with_ctx(ctx)),
331            TraitDecl(g) => write!(f, "Trait decls group: {}", g.with_ctx(ctx)),
332            TraitImpl(g) => write!(f, "Trait impls group: {}", g.with_ctx(ctx)),
333            Mixed(g) => write!(f, "Mixed group: {}", g.with_ctx(ctx)),
334        }
335    }
336}
337
338impl<C: AstFormatter> FmtWithCtx<C> for ExistentialPredicate {
339    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        write!(f, "exists(TODO)")
341    }
342}
343
344impl_display_via_ctx!(Field);
345impl<C: AstFormatter> FmtWithCtx<C> for Field {
346    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        if let Some(name) = &self.name {
348            write!(f, "{}: ", name)?
349        }
350        write!(f, "{}", self.ty.with_ctx(ctx))
351    }
352}
353
354impl Display for FileName {
355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
356        match self {
357            FileName::Virtual(path_buf) | FileName::Local(path_buf) => {
358                write!(f, "{}", path_buf.display())
359            }
360            FileName::NotReal(name) => write!(f, "{}", name),
361        }
362    }
363}
364
365impl Display for FloatTy {
366    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
367        match self {
368            FloatTy::F16 => write!(f, "f16"),
369            FloatTy::F32 => write!(f, "f32"),
370            FloatTy::F64 => write!(f, "f64"),
371            FloatTy::F128 => write!(f, "f128"),
372        }
373    }
374}
375
376impl Display for FloatValue {
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
378        let v = &self.value;
379        match self.ty {
380            FloatTy::F16 => write!(f, "{v} : f16"),
381            FloatTy::F32 => write!(f, "{v} : f32"),
382            FloatTy::F64 => write!(f, "{v} : f64"),
383            FloatTy::F128 => write!(f, "{v} : f128"),
384        }
385    }
386}
387
388impl<C: AstFormatter> FmtWithCtx<C> for FnOperand {
389    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390        match self {
391            FnOperand::Regular(func) => write!(f, "{}", func.with_ctx(ctx)),
392            FnOperand::Move(p) => write!(f, "(move {})", p.with_ctx(ctx)),
393        }
394    }
395}
396
397impl<C: AstFormatter> FmtWithCtx<C> for FnPtr {
398    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399        match self.func.as_ref() {
400            FunIdOrTraitMethodRef::Fun(FunId::Regular(def_id)) => {
401                write!(f, "{}", def_id.with_ctx(ctx))?
402            }
403            FunIdOrTraitMethodRef::Fun(FunId::Builtin(builtin)) => write!(f, "@{}", builtin)?,
404            FunIdOrTraitMethodRef::Trait(trait_ref, method_id, _) => {
405                write!(f, "{}::{}", trait_ref.with_ctx(ctx), &method_id.0)?
406            }
407        };
408        write!(f, "{}", self.generics.with_ctx(ctx))
409    }
410}
411
412impl<C: AstFormatter> FmtWithCtx<C> for FunDecl {
413    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414        let keyword = if self.signature.is_unsafe {
415            "unsafe fn"
416        } else {
417            "fn"
418        };
419        self.item_meta
420            .fmt_item_intro(f, ctx, keyword, self.def_id)?;
421
422        // Update the context
423        let ctx = &ctx.set_generics(&self.signature.generics);
424
425        // Generic parameters
426        let (params, preds) = self.signature.generics.fmt_with_ctx_with_trait_clauses(ctx);
427        write!(f, "{params}")?;
428
429        // Arguments
430        let mut args: Vec<String> = Vec::new();
431        for (i, ty) in self.signature.inputs.iter().enumerate() {
432            // The input variables start at index 1
433            // TODO: use the locals to get the variable names
434            let id = LocalId::new(i + 1);
435            args.push(format!("{}: {}", id.to_pretty_string(), ty.with_ctx(ctx)));
436        }
437        let args = args.join(", ");
438        write!(f, "({args})")?;
439
440        // Return type
441        if !self.signature.output.is_unit() {
442            write!(f, " -> {}", self.signature.output.with_ctx(ctx))?;
443        };
444        write!(f, "{preds}")?;
445
446        // Body
447        match &self.body {
448            Ok(body) => {
449                let tab = ctx.indent();
450                let body = body.with_ctx(ctx);
451                write!(f, "\n{tab}{{\n{body}{tab}}}")?;
452            }
453            Err(Opaque) => {}
454        }
455
456        Ok(())
457    }
458}
459
460impl<C: AstFormatter> FmtWithCtx<C> for FunDeclId {
461    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462        AnyTransId::from(*self).fmt_with_ctx(ctx, f)
463    }
464}
465
466impl<C: AstFormatter> FmtWithCtx<C> for FunDeclRef {
467    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468        let id = self.id.with_ctx(ctx);
469        let generics = self.generics.with_ctx(ctx);
470        write!(f, "{id}{generics}")
471    }
472}
473
474impl<C: AstFormatter> FmtWithCtx<C> for FunSig {
475    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476        let ctx = &ctx.set_generics(&self.generics);
477
478        // Unsafe keyword
479        if self.is_unsafe {
480            write!(f, "unsafe ")?;
481        }
482
483        // Generic parameters
484        let (params, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
485        write!(f, "fn{params}")?;
486
487        // Arguments
488        let args = self
489            .inputs
490            .iter()
491            .map(|ty| ty.with_ctx(ctx).to_string())
492            .format(", ");
493        write!(f, "({args})")?;
494
495        // Return type
496        if !self.output.is_unit() {
497            write!(f, " -> {}", self.output.with_ctx(ctx))?;
498        }
499
500        write!(f, "{clauses}")?;
501        Ok(())
502    }
503}
504
505impl<Id: Copy, C: AstFormatter> FmtWithCtx<C> for GDeclarationGroup<Id>
506where
507    Id: FmtWithCtx<C>,
508{
509    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510        use GDeclarationGroup::*;
511        match self {
512            NonRec(id) => write!(f, "Non rec: {}", id.with_ctx(ctx)),
513            Rec(ids) => {
514                let ids = ids.iter().map(|id| id.with_ctx(ctx)).format(", ");
515                write!(f, "Rec: {}", ids)
516            }
517        }
518    }
519}
520
521impl GenericArgs {
522    pub(crate) fn fmt_explicits<'a, C: AstFormatter>(
523        &'a self,
524        ctx: &'a C,
525    ) -> impl Iterator<Item = impl Display + 'a> {
526        let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
527        let types = self.types.iter().map(|x| x.with_ctx(ctx));
528        let const_generics = self.const_generics.iter().map(|x| x.with_ctx(ctx));
529        regions.map(Either::Left).chain(
530            types
531                .map(Either::Left)
532                .chain(const_generics.map(Either::Right))
533                .map(Either::Right),
534        )
535    }
536
537    pub(crate) fn fmt_implicits<'a, C: AstFormatter>(
538        &'a self,
539        ctx: &'a C,
540    ) -> impl Iterator<Item = impl Display + 'a> {
541        self.trait_refs.iter().map(|x| x.with_ctx(ctx))
542    }
543}
544
545impl_display_via_ctx!(GenericArgs);
546impl_debug_via_display!(GenericArgs);
547impl<C: AstFormatter> FmtWithCtx<C> for GenericArgs {
548    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549        if self.has_explicits() {
550            write!(f, "<{}>", self.fmt_explicits(ctx).format(", "))?;
551        }
552        if self.has_implicits() {
553            write!(f, "[{}]", self.fmt_implicits(ctx).format(", "))?;
554        }
555        Ok(())
556    }
557}
558
559impl GenericParams {
560    fn formatted_params<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
561    where
562        C: AstFormatter,
563    {
564        let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
565        let types = self.types.iter();
566        let const_generics = self.const_generics.iter();
567        regions.map(Either::Left).chain(
568            types
569                .map(Either::Left)
570                .chain(const_generics.map(Either::Right))
571                .map(Either::Right),
572        )
573    }
574
575    fn formatted_clauses<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
576    where
577        C: AstFormatter,
578    {
579        let trait_clauses = self.trait_clauses.iter().map(|x| x.to_string_with_ctx(ctx));
580        let types_outlive = self.types_outlive.iter().map(|x| x.fmt_as_for(ctx));
581        let regions_outlive = self.regions_outlive.iter().map(|x| x.fmt_as_for(ctx));
582        let type_constraints = self
583            .trait_type_constraints
584            .iter()
585            .map(|x| x.fmt_as_for(ctx));
586        trait_clauses.map(Either::Left).chain(
587            types_outlive
588                .chain(regions_outlive)
589                .chain(type_constraints)
590                .map(Either::Right),
591        )
592    }
593
594    pub fn fmt_with_ctx_with_trait_clauses<C>(&self, ctx: &C) -> (String, String)
595    where
596        C: AstFormatter,
597    {
598        let tab = ctx.indent();
599        let params = if self.has_explicits() {
600            let params = self.formatted_params(ctx).format(", ");
601            format!("<{}>", params)
602        } else {
603            String::new()
604        };
605        let clauses = if self.has_predicates() {
606            let clauses = self
607                .formatted_clauses(ctx)
608                .map(|x| format!("\n{tab}{TAB_INCR}{x},"))
609                .format("");
610            format!("\n{tab}where{clauses}")
611        } else {
612            String::new()
613        };
614        (params, clauses)
615    }
616
617    pub fn fmt_with_ctx_single_line<C>(&self, ctx: &C) -> String
618    where
619        C: AstFormatter,
620    {
621        if self.is_empty() {
622            String::new()
623        } else {
624            let params = self
625                .formatted_params(ctx)
626                .map(Either::Left)
627                .chain(self.formatted_clauses(ctx).map(Either::Right))
628                .format(", ");
629            format!("<{}>", params)
630        }
631    }
632}
633
634impl_debug_via_display!(GenericParams);
635impl Display for GenericParams {
636    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
637        write!(f, "{}", self.fmt_with_ctx_single_line(&FmtCtx::new()))
638    }
639}
640
641impl<C: AstFormatter> FmtWithCtx<C> for GenericsSource {
642    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643        match self {
644            GenericsSource::Item(id) => write!(f, "{}", id.with_ctx(ctx)),
645            GenericsSource::Method(id, name) => write!(f, "{}::{name}", id.with_ctx(ctx)),
646            GenericsSource::Builtin => write!(f, "<builtin>"),
647            GenericsSource::Other => write!(f, "<unknown>"),
648        }
649    }
650}
651
652impl<T> GExprBody<T> {
653    fn fmt_with_ctx_and_callback<C: AstFormatter>(
654        &self,
655        ctx: &C,
656        f: &mut fmt::Formatter<'_>,
657        fmt_body: impl FnOnce(
658            &mut fmt::Formatter<'_>,
659            &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
660            &T,
661        ) -> fmt::Result,
662    ) -> fmt::Result {
663        // Update the context
664        let ctx = &ctx.set_locals(&self.locals);
665        let ctx = &ctx.increase_indent();
666        let tab = ctx.indent();
667
668        // Format the local variables
669        for v in &self.locals.locals {
670            write!(f, "{tab}")?;
671            write!(f, "let {v}: {};", v.ty.with_ctx(ctx))?;
672
673            write!(f, " // ")?;
674            let index = v.index.index();
675            if index == 0 {
676                write!(f, "return")?;
677            } else if index <= self.locals.arg_count {
678                write!(f, "arg #{index}")?
679            } else {
680                match &v.name {
681                    Some(_) => write!(f, "local")?,
682                    None => write!(f, "anonymous local")?,
683                }
684            }
685            writeln!(f)?;
686        }
687
688        fmt_body(f, ctx, &self.body)?;
689
690        Ok(())
691    }
692}
693
694impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<llbc_ast::Block> {
695    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696        // Inference fails when this is a closure.
697        fn fmt_body<C: AstFormatter>(
698            f: &mut fmt::Formatter<'_>,
699            ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
700            body: &Block,
701        ) -> Result<(), fmt::Error> {
702            writeln!(f)?;
703            body.fmt_with_ctx(ctx, f)?;
704            Ok(())
705        }
706        self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
707    }
708}
709impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<ullbc_ast::BodyContents> {
710    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
711        // Inference fails when this is a closure.
712        fn fmt_body<C: AstFormatter>(
713            f: &mut fmt::Formatter<'_>,
714            ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
715            body: &Vector<BlockId, BlockData>,
716        ) -> Result<(), fmt::Error> {
717            let tab = ctx.indent();
718            let ctx = &ctx.increase_indent();
719            for (bid, block) in body.iter_indexed_values() {
720                writeln!(f)?;
721                writeln!(f, "{tab}bb{}: {{", bid.index())?;
722                writeln!(f, "{}", block.with_ctx(ctx))?;
723                writeln!(f, "{tab}}}")?;
724            }
725            Ok(())
726        }
727        self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
728    }
729}
730
731impl<C> FmtWithCtx<C> for GlobalDecl
732where
733    C: AstFormatter,
734{
735    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736        let keyword = match self.global_kind {
737            GlobalKind::Static => "static",
738            GlobalKind::AnonConst | GlobalKind::NamedConst => "const",
739        };
740        self.item_meta
741            .fmt_item_intro(f, ctx, keyword, self.def_id)?;
742
743        // Update the context with the generics
744        let ctx = &ctx.set_generics(&self.generics);
745
746        // Translate the parameters and the trait clauses
747        let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
748
749        // Type
750        let ty = self.ty.with_ctx(ctx);
751        write!(f, "{params}: {ty}")?;
752
753        // Predicates
754        write!(f, "{preds}")?;
755        if self.generics.has_predicates() {
756            write!(f, "\n")?;
757        }
758        write!(f, " ")?;
759
760        // Decl name
761        let initializer = self.init.with_ctx(ctx);
762        write!(f, "= {initializer}()")?;
763
764        Ok(())
765    }
766}
767
768impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclId {
769    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770        AnyTransId::from(*self).fmt_with_ctx(ctx, f)
771    }
772}
773
774impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclRef {
775    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776        let id = self.id.with_ctx(ctx);
777        let generics = self.generics.with_ctx(ctx);
778        write!(f, "{id}{generics}")
779    }
780}
781
782impl<C: AstFormatter> FmtWithCtx<C> for ImplElem {
783    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784        write!(f, "{{")?;
785        match self {
786            ImplElem::Ty(bound_ty) => {
787                // Just printing the generics (not the predicates)
788                let ctx = ctx.set_generics(&bound_ty.params);
789                bound_ty.skip_binder.fmt_with_ctx(&ctx, f)?
790            }
791            ImplElem::Trait(impl_id) => {
792                match ctx.get_crate().and_then(|tr| tr.trait_impls.get(*impl_id)) {
793                    None => write!(f, "impl#{impl_id}")?,
794                    Some(timpl) => {
795                        // We need to put the first type parameter aside: it is the type for which
796                        // we implement the trait.
797                        let ctx = &ctx.set_generics(&timpl.generics);
798                        let mut impl_trait = timpl.impl_trait.clone();
799                        let self_ty = impl_trait.generics.types.remove(TypeVarId::ZERO).unwrap();
800                        write!(
801                            f,
802                            "impl {} for {}",
803                            impl_trait.with_ctx(ctx),
804                            self_ty.with_ctx(ctx)
805                        )?;
806                    }
807                }
808            }
809        }
810        write!(f, "}}")
811    }
812}
813
814impl Display for IntegerTy {
815    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
816        match self {
817            IntegerTy::Isize => write!(f, "isize"),
818            IntegerTy::I8 => write!(f, "i8"),
819            IntegerTy::I16 => write!(f, "i16"),
820            IntegerTy::I32 => write!(f, "i32"),
821            IntegerTy::I64 => write!(f, "i64"),
822            IntegerTy::I128 => write!(f, "i128"),
823            IntegerTy::Usize => write!(f, "usize"),
824            IntegerTy::U8 => write!(f, "u8"),
825            IntegerTy::U16 => write!(f, "u16"),
826            IntegerTy::U32 => write!(f, "u32"),
827            IntegerTy::U64 => write!(f, "u64"),
828            IntegerTy::U128 => write!(f, "u128"),
829        }
830    }
831}
832
833impl ItemMeta {
834    /// Format the start of an item definition, up to the name.
835    pub fn fmt_item_intro<C: AstFormatter>(
836        &self,
837        f: &mut fmt::Formatter<'_>,
838        ctx: &C,
839        keyword: &str,
840        id: impl Into<AnyTransId>,
841    ) -> fmt::Result {
842        let tab = ctx.indent();
843        let full_name = self.name.with_ctx(ctx);
844        let name = if let Some(tr) = ctx.get_crate()
845            && let Some(short_name) = tr.short_names.get(&id.into())
846        {
847            writeln!(f, "// Full name: {full_name}")?;
848            short_name.with_ctx(ctx)
849        } else {
850            full_name
851        };
852        if let Some(id) = &self.lang_item {
853            writeln!(f, "{tab}#[lang_item(\"{id}\")]")?;
854        }
855        write!(f, "{tab}")?;
856        if self.attr_info.public {
857            write!(f, "pub ")?;
858        }
859        write!(f, "{keyword} {name}")
860    }
861}
862
863impl Display for Literal {
864    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
865        match self {
866            Literal::Scalar(v) => write!(f, "{v}"),
867            Literal::Float(v) => write!(f, "{v}"),
868            Literal::Bool(v) => write!(f, "{v}"),
869            Literal::Char(v) => write!(f, "{v}"),
870            Literal::Str(v) => write!(f, "\"{}\"", v.replace("\\", "\\\\").replace("\n", "\\n")),
871            Literal::ByteStr(v) => write!(f, "{v:?}"),
872        }
873    }
874}
875
876impl Display for LiteralTy {
877    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
878        match self {
879            LiteralTy::Integer(ty) => write!(f, "{ty}"),
880            LiteralTy::Float(ty) => write!(f, "{ty}"),
881            LiteralTy::Char => write!(f, "char"),
882            LiteralTy::Bool => write!(f, "bool"),
883        }
884    }
885}
886
887impl Display for Loc {
888    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
889        write!(f, "{}:{}", self.line, self.col)
890    }
891}
892
893impl Display for Local {
894    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895        // We display both the variable name and its id because some
896        // variables may have the same name (in different scopes)
897        if let Some(name) = &self.name {
898            write!(f, "{name}")?
899        }
900        write!(f, "{}", self.index.to_pretty_string())?;
901        Ok(())
902    }
903}
904
905impl<C: AstFormatter> FmtWithCtx<C> for LocalId {
906    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        ctx.format_local_id(f, *self)
908    }
909}
910
911impl<C: AstFormatter> FmtWithCtx<C> for Name {
912    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
913        let name = self.name.iter().map(|x| x.with_ctx(ctx)).format("::");
914        write!(f, "{}", name)
915    }
916}
917
918impl<C: AstFormatter> FmtWithCtx<C> for NullOp {
919    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
920        let op = match self {
921            NullOp::SizeOf => "size_of",
922            NullOp::AlignOf => "align_of",
923            NullOp::OffsetOf(_) => "offset_of(?)",
924            NullOp::UbChecks => "ub_checks",
925        };
926        write!(f, "{op}")
927    }
928}
929
930impl_display_via_ctx!(Operand);
931impl<C: AstFormatter> FmtWithCtx<C> for Operand {
932    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933        match self {
934            Operand::Copy(p) => write!(f, "copy ({})", p.with_ctx(ctx)),
935            Operand::Move(p) => write!(f, "move ({})", p.with_ctx(ctx)),
936            Operand::Const(c) => write!(f, "const ({})", c.with_ctx(ctx)),
937        }
938    }
939}
940
941impl<C: AstFormatter, T, U> FmtWithCtx<C> for OutlivesPred<T, U>
942where
943    T: FmtWithCtx<C>,
944    U: FmtWithCtx<C>,
945{
946    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947        write!(f, "{} : {}", self.0.with_ctx(ctx), self.1.with_ctx(ctx))
948    }
949}
950
951impl<C: AstFormatter> FmtWithCtx<C> for PathElem {
952    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
953        match self {
954            PathElem::Ident(s, d) => {
955                write!(f, "{s}")?;
956                if !d.is_zero() {
957                    write!(f, "#{}", d)?;
958                }
959                Ok(())
960            }
961            PathElem::Impl(impl_elem) => {
962                write!(f, "{}", impl_elem.with_ctx(ctx))
963            }
964            PathElem::Monomorphized(args) => {
965                write!(f, "<{}>", args.fmt_explicits(ctx).format(", "))
966            }
967        }
968    }
969}
970
971impl_display_via_ctx!(Place);
972impl<C: AstFormatter> FmtWithCtx<C> for Place {
973    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
974        match &self.kind {
975            PlaceKind::Local(var_id) => write!(f, "{}", var_id.with_ctx(ctx)),
976            PlaceKind::Projection(subplace, projection) => {
977                let sub = subplace.with_ctx(ctx);
978                match projection {
979                    ProjectionElem::Deref => {
980                        write!(f, "*({sub})")
981                    }
982                    ProjectionElem::Field(proj_kind, field_id) => match proj_kind {
983                        FieldProjKind::Adt(adt_id, opt_variant_id) => {
984                            write!(f, "({sub}")?;
985                            if let Some(variant_id) = opt_variant_id {
986                                write!(f, " as variant ")?;
987                                ctx.format_enum_variant(f, *adt_id, *variant_id)?;
988                            }
989                            write!(f, ").")?;
990                            ctx.format_field_name(f, *adt_id, *opt_variant_id, *field_id)?;
991                            Ok(())
992                        }
993                        FieldProjKind::Tuple(_) => {
994                            write!(f, "({sub}).{field_id}")
995                        }
996                    },
997                    ProjectionElem::Index {
998                        offset,
999                        from_end: true,
1000                        ..
1001                    } => write!(f, "({sub})[-{}]", offset.with_ctx(ctx)),
1002                    ProjectionElem::Index {
1003                        offset,
1004                        from_end: false,
1005                        ..
1006                    } => write!(f, "({sub})[{}]", offset.with_ctx(ctx)),
1007                    ProjectionElem::Subslice {
1008                        from,
1009                        to,
1010                        from_end: true,
1011                        ..
1012                    } => write!(f, "({sub})[{}..-{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1013                    ProjectionElem::Subslice {
1014                        from,
1015                        to,
1016                        from_end: false,
1017                        ..
1018                    } => write!(f, "({sub})[{}..{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1019                }
1020            }
1021        }
1022    }
1023}
1024
1025impl<C: AstFormatter> FmtWithCtx<C> for PolyTraitDeclRef {
1026    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1027        write!(f, "{}", self.fmt_as_for(ctx))
1028    }
1029}
1030
1031impl Display for RawAttribute {
1032    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1033        write!(f, "{}", self.path)?;
1034        if let Some(args) = &self.args {
1035            write!(f, "({args})")?;
1036        }
1037        Ok(())
1038    }
1039}
1040
1041impl<C: AstFormatter> FmtWithCtx<C> for RawConstantExpr {
1042    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043        match self {
1044            RawConstantExpr::Literal(c) => write!(f, "{}", c.to_string()),
1045            RawConstantExpr::Adt(variant_id, values) => {
1046                // It is a bit annoying: in order to properly format the value,
1047                // we need the type (which contains the type def id).
1048                // Anyway, the printing utilities are mostly for debugging.
1049                let variant_id = match variant_id {
1050                    Some(id) => format!("Some({id})"),
1051                    None => "None".to_string(),
1052                };
1053                let values = values.iter().map(|v| v.with_ctx(ctx)).format(", ");
1054                write!(f, "ConstAdt {} [{}]", variant_id, values)
1055            }
1056            RawConstantExpr::Array(values) => {
1057                let values = values.iter().map(|v| v.with_ctx(ctx)).format(", ");
1058                write!(f, "[{}]", values)
1059            }
1060            RawConstantExpr::Global(global_ref) => {
1061                write!(f, "{}", global_ref.with_ctx(ctx))
1062            }
1063            RawConstantExpr::TraitConst(trait_ref, name) => {
1064                write!(f, "{}::{name}", trait_ref.with_ctx(ctx),)
1065            }
1066            RawConstantExpr::Ref(cv) => {
1067                write!(f, "&{}", cv.with_ctx(ctx))
1068            }
1069            RawConstantExpr::Ptr(rk, cv) => match rk {
1070                RefKind::Mut => write!(f, "&raw mut {}", cv.with_ctx(ctx)),
1071                RefKind::Shared => write!(f, "&raw const {}", cv.with_ctx(ctx)),
1072            },
1073            RawConstantExpr::Var(id) => write!(f, "{}", id.with_ctx(ctx)),
1074            RawConstantExpr::FnPtr(fp) => {
1075                write!(f, "{}", fp.with_ctx(ctx))
1076            }
1077            RawConstantExpr::RawMemory(bytes) => write!(f, "RawMemory({bytes:?})"),
1078            RawConstantExpr::Opaque(cause) => write!(f, "Opaque({cause})"),
1079        }
1080    }
1081}
1082
1083impl<C: AstFormatter> FmtWithCtx<C> for Region {
1084    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1085        match self {
1086            Region::Static => write!(f, "'static"),
1087            Region::Var(var) => write!(f, "{}", var.with_ctx(ctx)),
1088            Region::Erased => write!(f, "'_"),
1089        }
1090    }
1091}
1092
1093impl<T> RegionBinder<T> {
1094    /// Format the parameters and contents of this binder and returns the resulting strings.
1095    fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
1096    where
1097        C: AstFormatter,
1098        T: FmtWithCtx<C::Reborrow<'a>>,
1099    {
1100        let ctx = &ctx.push_bound_regions(&self.regions);
1101        (
1102            self.regions
1103                .iter()
1104                .map(|r| r.with_ctx(ctx))
1105                .format(", ")
1106                .to_string(),
1107            self.skip_binder.to_string_with_ctx(ctx),
1108        )
1109    }
1110
1111    /// Formats the binder as `for<params> value`.
1112    fn fmt_as_for<'a, C>(&'a self, ctx: &'a C) -> String
1113    where
1114        C: AstFormatter,
1115        T: FmtWithCtx<C::Reborrow<'a>>,
1116    {
1117        let (regions, value) = self.fmt_split(ctx);
1118        let regions = if regions.is_empty() {
1119            "".to_string()
1120        } else {
1121            format!("for<{regions}> ",)
1122        };
1123        format!("{regions}{value}",)
1124    }
1125}
1126
1127impl<C: AstFormatter> FmtWithCtx<C> for RegionDbVar {
1128    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1129        ctx.format_bound_var(f, *self, "'_", |v| {
1130            v.name.as_ref().map(|name| name.to_string())
1131        })
1132    }
1133}
1134
1135impl_display_via_ctx!(RegionVar);
1136impl<C: AstFormatter> FmtWithCtx<C> for RegionVar {
1137    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1138        match &self.name {
1139            Some(name) => write!(f, "{name}"),
1140            None => write!(f, "'_{}", self.index),
1141        }
1142    }
1143}
1144
1145impl_display_via_ctx!(Rvalue);
1146impl<C: AstFormatter> FmtWithCtx<C> for Rvalue {
1147    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1148        match self {
1149            Rvalue::Use(x) => write!(f, "{}", x.with_ctx(ctx)),
1150            Rvalue::Ref(place, borrow_kind) => {
1151                let borrow_kind = match borrow_kind {
1152                    BorrowKind::Shared => "&",
1153                    BorrowKind::Mut => "&mut ",
1154                    BorrowKind::TwoPhaseMut => "&two-phase-mut ",
1155                    BorrowKind::UniqueImmutable => "&uniq ",
1156                    BorrowKind::Shallow => "&shallow ",
1157                };
1158                write!(f, "{borrow_kind}{}", place.with_ctx(ctx))
1159            }
1160            Rvalue::RawPtr(place, mutability) => {
1161                let ptr_kind = match mutability {
1162                    RefKind::Shared => "&raw const ",
1163                    RefKind::Mut => "&raw mut ",
1164                };
1165                write!(f, "{ptr_kind}{}", place.with_ctx(ctx))
1166            }
1167
1168            Rvalue::BinaryOp(binop, x, y) => {
1169                write!(f, "{} {} {}", x.with_ctx(ctx), binop, y.with_ctx(ctx))
1170            }
1171            Rvalue::UnaryOp(unop, x) => {
1172                write!(f, "{}({})", unop.with_ctx(ctx), x.with_ctx(ctx))
1173            }
1174            Rvalue::NullaryOp(op, ty) => {
1175                write!(f, "{}<{}>", op.with_ctx(ctx), ty.with_ctx(ctx))
1176            }
1177            Rvalue::Discriminant(p, _) => {
1178                write!(f, "@discriminant({})", p.with_ctx(ctx),)
1179            }
1180            Rvalue::Aggregate(kind, ops) => {
1181                let ops_s = ops.iter().map(|op| op.with_ctx(ctx)).format(", ");
1182                match kind {
1183                    AggregateKind::Adt(ty_ref, variant_id, field_id) => {
1184                        match ty_ref.id {
1185                            TypeId::Tuple => write!(f, "({})", ops_s),
1186                            TypeId::Builtin(_) => unreachable!(),
1187                            TypeId::Adt(ty_id) => {
1188                                match variant_id {
1189                                    None => ty_id.fmt_with_ctx(ctx, f)?,
1190                                    Some(variant_id) => {
1191                                        ctx.format_enum_variant(f, ty_id, *variant_id)?
1192                                    }
1193                                }
1194                                write!(f, " {{ ")?;
1195                                for (comma, (i, op)) in
1196                                    repeat_except_first(", ").zip(ops.iter().enumerate())
1197                                {
1198                                    write!(f, "{}", comma.unwrap_or_default())?;
1199                                    let field_id = match *field_id {
1200                                        None => FieldId::new(i),
1201                                        Some(field_id) => {
1202                                            assert_eq!(i, 0); // there should be only one operand
1203                                            field_id
1204                                        }
1205                                    };
1206                                    ctx.format_field_name(f, ty_id, *variant_id, field_id)?;
1207                                    write!(f, ": {}", op.with_ctx(ctx))?;
1208                                }
1209                                write!(f, " }}")
1210                            }
1211                        }
1212                    }
1213                    AggregateKind::Array(..) => {
1214                        write!(f, "[{}]", ops_s)
1215                    }
1216                    AggregateKind::RawPtr(_, rmut) => {
1217                        let mutability = match rmut {
1218                            RefKind::Shared => "const",
1219                            RefKind::Mut => "mut ",
1220                        };
1221                        write!(f, "*{} ({})", mutability, ops_s)
1222                    }
1223                }
1224            }
1225            Rvalue::Global(global_ref) => write!(f, "{}", global_ref.with_ctx(ctx)),
1226            Rvalue::GlobalRef(global_ref, RefKind::Shared) => {
1227                write!(f, "&{}", global_ref.with_ctx(ctx))
1228            }
1229            Rvalue::GlobalRef(global_ref, RefKind::Mut) => {
1230                write!(f, "&raw mut {}", global_ref.with_ctx(ctx))
1231            }
1232            Rvalue::Len(place, ..) => write!(f, "len({})", place.with_ctx(ctx)),
1233            Rvalue::Repeat(op, _ty, cg) => {
1234                write!(f, "[{}; {}]", op.with_ctx(ctx), cg.with_ctx(ctx))
1235            }
1236            Rvalue::ShallowInitBox(op, ty) => {
1237                write!(
1238                    f,
1239                    "shallow_init_box::<{}>({})",
1240                    ty.with_ctx(ctx),
1241                    op.with_ctx(ctx)
1242                )
1243            }
1244        }
1245    }
1246}
1247
1248impl Display for ScalarValue {
1249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1250        match self {
1251            ScalarValue::Isize(v) => write!(f, "{v} : isize"),
1252            ScalarValue::I8(v) => write!(f, "{v} : i8"),
1253            ScalarValue::I16(v) => write!(f, "{v} : i16"),
1254            ScalarValue::I32(v) => write!(f, "{v} : i32"),
1255            ScalarValue::I64(v) => write!(f, "{v} : i64"),
1256            ScalarValue::I128(v) => write!(f, "{v} : i128"),
1257            ScalarValue::Usize(v) => write!(f, "{v} : usize"),
1258            ScalarValue::U8(v) => write!(f, "{v} : u8"),
1259            ScalarValue::U16(v) => write!(f, "{v} : u16"),
1260            ScalarValue::U32(v) => write!(f, "{v} : u32"),
1261            ScalarValue::U64(v) => write!(f, "{v} : u64"),
1262            ScalarValue::U128(v) => write!(f, "{v} : u128"),
1263        }
1264    }
1265}
1266
1267impl<C: AstFormatter> FmtWithCtx<C> for ullbc::Statement {
1268    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1269        let tab = ctx.indent();
1270        use ullbc::RawStatement;
1271        for line in &self.comments_before {
1272            writeln!(f, "{tab}// {line}")?;
1273        }
1274        match &self.content {
1275            RawStatement::Assign(place, rvalue) => write!(
1276                f,
1277                "{tab}{} := {}",
1278                place.with_ctx(ctx),
1279                rvalue.with_ctx(ctx),
1280            ),
1281            RawStatement::SetDiscriminant(place, variant_id) => write!(
1282                f,
1283                "{tab}@discriminant({}) := {}",
1284                place.with_ctx(ctx),
1285                variant_id
1286            ),
1287            RawStatement::CopyNonOverlapping(box CopyNonOverlapping { src, dst, count }) => write!(
1288                f,
1289                "{}copy_nonoverlapping({}, {}, {})",
1290                tab,
1291                src.with_ctx(ctx),
1292                dst.with_ctx(ctx),
1293                count.with_ctx(ctx),
1294            ),
1295            RawStatement::StorageLive(var_id) => {
1296                write!(f, "{tab}storage_live({})", var_id.with_ctx(ctx))
1297            }
1298            RawStatement::StorageDead(var_id) => {
1299                write!(f, "{tab}storage_dead({})", var_id.with_ctx(ctx))
1300            }
1301            RawStatement::Deinit(place) => {
1302                write!(f, "{tab}deinit({})", place.with_ctx(ctx))
1303            }
1304            RawStatement::Drop(place) => {
1305                write!(f, "{tab}drop {}", place.with_ctx(ctx))
1306            }
1307            RawStatement::Assert(assert) => write!(f, "{tab}{}", assert.with_ctx(ctx)),
1308            RawStatement::Nop => write!(f, "{tab}nop"),
1309            RawStatement::Error(s) => write!(f, "{tab}@Error({})", s),
1310        }
1311    }
1312}
1313
1314impl<C: AstFormatter> FmtWithCtx<C> for llbc::Statement {
1315    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1316        let tab = ctx.indent();
1317        use llbc::RawStatement;
1318        for line in &self.comments_before {
1319            writeln!(f, "{tab}// {line}")?;
1320        }
1321        write!(f, "{tab}")?;
1322        match &self.content {
1323            RawStatement::Assign(place, rvalue) => {
1324                write!(f, "{} := {}", place.with_ctx(ctx), rvalue.with_ctx(ctx),)
1325            }
1326            RawStatement::SetDiscriminant(place, variant_id) => write!(
1327                f,
1328                "@discriminant({}) := {}",
1329                place.with_ctx(ctx),
1330                variant_id
1331            ),
1332            RawStatement::CopyNonOverlapping(box CopyNonOverlapping { src, dst, count }) => write!(
1333                f,
1334                "copy_nonoverlapping({}, {}, {})",
1335                src.with_ctx(ctx),
1336                dst.with_ctx(ctx),
1337                count.with_ctx(ctx),
1338            ),
1339            RawStatement::StorageLive(var_id) => {
1340                write!(f, "storage_live({})", var_id.with_ctx(ctx))
1341            }
1342            RawStatement::StorageDead(var_id) => {
1343                write!(f, "storage_dead({})", var_id.with_ctx(ctx))
1344            }
1345            RawStatement::Deinit(place) => {
1346                write!(f, "deinit({})", place.with_ctx(ctx))
1347            }
1348            RawStatement::Drop(place) => {
1349                write!(f, "drop {}", place.with_ctx(ctx))
1350            }
1351            RawStatement::Assert(assert) => {
1352                write!(f, "{}", assert.with_ctx(ctx),)
1353            }
1354            RawStatement::Call(call) => {
1355                write!(f, "{}", call.with_ctx(ctx))
1356            }
1357            RawStatement::Abort(kind) => {
1358                write!(f, "{}", kind.with_ctx(ctx))
1359            }
1360            RawStatement::Return => write!(f, "return"),
1361            RawStatement::Break(index) => write!(f, "break {index}"),
1362            RawStatement::Continue(index) => write!(f, "continue {index}"),
1363            RawStatement::Nop => write!(f, "nop"),
1364            RawStatement::Switch(switch) => match switch {
1365                Switch::If(discr, true_st, false_st) => {
1366                    let ctx = &ctx.increase_indent();
1367                    write!(
1368                        f,
1369                        "if {} {{\n{}{tab}}}\n{tab}else {{\n{}{tab}}}",
1370                        discr.with_ctx(ctx),
1371                        true_st.with_ctx(ctx),
1372                        false_st.with_ctx(ctx),
1373                    )
1374                }
1375                Switch::SwitchInt(discr, _ty, maps, otherwise) => {
1376                    writeln!(f, "switch {} {{", discr.with_ctx(ctx))?;
1377                    let ctx1 = &ctx.increase_indent();
1378                    let inner_tab1 = ctx1.indent();
1379                    let ctx2 = &ctx1.increase_indent();
1380                    for (pvl, st) in maps {
1381                        // Note that there may be several pattern values
1382                        let pvl = pvl.iter().format(" | ");
1383                        writeln!(
1384                            f,
1385                            "{inner_tab1}{} => {{\n{}{inner_tab1}}},",
1386                            pvl,
1387                            st.with_ctx(ctx2),
1388                        )?;
1389                    }
1390                    writeln!(
1391                        f,
1392                        "{inner_tab1}_ => {{\n{}{inner_tab1}}},",
1393                        otherwise.with_ctx(ctx2),
1394                    )?;
1395                    write!(f, "{tab}}}")
1396                }
1397                Switch::Match(discr, maps, otherwise) => {
1398                    writeln!(f, "match {} {{", discr.with_ctx(ctx))?;
1399                    let ctx1 = &ctx.increase_indent();
1400                    let inner_tab1 = ctx1.indent();
1401                    let ctx2 = &ctx1.increase_indent();
1402                    let discr_type: Option<TypeDeclId> = discr
1403                        .ty
1404                        .kind()
1405                        .as_adt()
1406                        .and_then(|tref| tref.id.as_adt())
1407                        .copied();
1408                    for (cases, st) in maps {
1409                        write!(f, "{inner_tab1}",)?;
1410                        // Note that there may be several pattern values
1411                        for (bar, v) in repeat_except_first(" | ").zip(cases.iter()) {
1412                            write!(f, "{}", bar.unwrap_or_default())?;
1413                            match discr_type {
1414                                Some(type_id) => ctx.format_enum_variant(f, type_id, *v)?,
1415                                None => write!(f, "{}", v.to_pretty_string())?,
1416                            }
1417                        }
1418                        writeln!(f, " => {{\n{}{inner_tab1}}},", st.with_ctx(ctx2),)?;
1419                    }
1420                    if let Some(otherwise) = otherwise {
1421                        writeln!(
1422                            f,
1423                            "{inner_tab1}_ => {{\n{}{inner_tab1}}},",
1424                            otherwise.with_ctx(ctx2),
1425                        )?;
1426                    }
1427                    write!(f, "{tab}}}")
1428                }
1429            },
1430            RawStatement::Loop(body) => {
1431                let ctx = &ctx.increase_indent();
1432                write!(f, "loop {{\n{}{tab}}}", body.with_ctx(ctx))
1433            }
1434            RawStatement::Error(s) => write!(f, "@ERROR({})", s),
1435        }
1436    }
1437}
1438
1439impl<C: AstFormatter> FmtWithCtx<C> for Terminator {
1440    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1441        let tab = ctx.indent();
1442        for line in &self.comments_before {
1443            writeln!(f, "{tab}// {line}")?;
1444        }
1445        write!(f, "{tab}")?;
1446        match &self.content {
1447            RawTerminator::Goto { target } => write!(f, "goto bb{target}"),
1448            RawTerminator::Switch { discr, targets } => match targets {
1449                SwitchTargets::If(true_block, false_block) => write!(
1450                    f,
1451                    "if {} -> bb{} else -> bb{}",
1452                    discr.with_ctx(ctx),
1453                    true_block,
1454                    false_block
1455                ),
1456                SwitchTargets::SwitchInt(_ty, maps, otherwise) => {
1457                    let maps = maps
1458                        .iter()
1459                        .map(|(v, bid)| format!("{}: bb{}", v.to_string(), bid))
1460                        .chain([format!("otherwise: bb{otherwise}")])
1461                        .format(", ");
1462                    write!(f, "switch {} -> {}", discr.with_ctx(ctx), maps)
1463                }
1464            },
1465            RawTerminator::Call {
1466                call,
1467                target,
1468                on_unwind,
1469            } => {
1470                let call = call.with_ctx(ctx);
1471                write!(f, "{call} -> bb{target} (unwind: bb{on_unwind})",)
1472            }
1473            RawTerminator::Abort(kind) => write!(f, "{}", kind.with_ctx(ctx)),
1474            RawTerminator::Return => write!(f, "return"),
1475            RawTerminator::UnwindResume => write!(f, "unwind_continue"),
1476        }
1477    }
1478}
1479
1480impl<C: AstFormatter> FmtWithCtx<C> for TraitClause {
1481    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1482        let clause_id = self.clause_id.to_pretty_string();
1483        let trait_ = self.trait_.with_ctx(ctx);
1484        write!(f, "[{clause_id}]: {trait_}")
1485    }
1486}
1487
1488impl<C: AstFormatter> FmtWithCtx<C> for TraitDecl {
1489    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1490        // Update the context
1491        let ctx = &ctx.set_generics(&self.generics);
1492
1493        self.item_meta
1494            .fmt_item_intro(f, ctx, "trait", self.def_id)?;
1495
1496        let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
1497        write!(f, "{generics}{clauses}")?;
1498
1499        let any_item = !self.parent_clauses.is_empty()
1500            || !self.type_clauses.is_empty()
1501            || !self.consts.is_empty()
1502            || !self.types.is_empty()
1503            || self.methods().count() > 0;
1504        if any_item {
1505            write!(f, "\n{{\n")?;
1506            for c in &self.parent_clauses {
1507                writeln!(
1508                    f,
1509                    "{TAB_INCR}parent_clause{} : {}",
1510                    c.clause_id,
1511                    c.with_ctx(ctx)
1512                )?;
1513            }
1514            for (name, clauses) in &self.type_clauses {
1515                for c in clauses {
1516                    writeln!(
1517                        f,
1518                        "{TAB_INCR}item_clause_{name}_{} : {}",
1519                        c.clause_id.to_string(),
1520                        c.with_ctx(ctx)
1521                    )?;
1522                }
1523            }
1524            for (name, ty) in &self.consts {
1525                let ty = ty.with_ctx(ctx);
1526                writeln!(f, "{TAB_INCR}const {name} : {ty}")?;
1527            }
1528            for name in &self.types {
1529                writeln!(f, "{TAB_INCR}type {name}")?;
1530            }
1531            for (name, bound_fn) in self.methods() {
1532                let (params, fn_ref) = bound_fn.fmt_split(ctx);
1533                writeln!(f, "{TAB_INCR}fn {name}{params} = {fn_ref}")?;
1534            }
1535            write!(f, "}}")?;
1536        }
1537        Ok(())
1538    }
1539}
1540
1541impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclId {
1542    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1543        AnyTransId::from(*self).fmt_with_ctx(ctx, f)
1544    }
1545}
1546
1547impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclRef {
1548    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1549        let trait_id = self.id.with_ctx(ctx);
1550        let generics = self.generics.with_ctx(ctx);
1551        write!(f, "{trait_id}{generics}")
1552    }
1553}
1554
1555impl<C: AstFormatter> FmtWithCtx<C> for TraitImpl {
1556    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1557        let full_name = self.item_meta.name.with_ctx(ctx);
1558        writeln!(f, "// Full name: {full_name}")?;
1559
1560        // Update the context
1561        let ctx = &ctx.set_generics(&self.generics);
1562
1563        let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
1564        let mut impl_trait = self.impl_trait.clone();
1565        let self_ty = impl_trait.generics.types.remove(TypeVarId::ZERO).unwrap();
1566        let self_ty = self_ty.with_ctx(ctx);
1567        let impl_trait = impl_trait.with_ctx(ctx);
1568        write!(f, "impl{generics} {impl_trait} for {self_ty}{clauses}")?;
1569
1570        let newline = if clauses.is_empty() {
1571            " ".to_string()
1572        } else {
1573            "\n".to_string()
1574        };
1575        write!(f, "{newline}{{")?;
1576
1577        let any_item = !self.parent_trait_refs.is_empty()
1578            || !self.type_clauses.is_empty()
1579            || !self.consts.is_empty()
1580            || !self.types.is_empty()
1581            || self.methods().count() > 0;
1582        if any_item {
1583            writeln!(f)?;
1584            for (i, c) in self.parent_trait_refs.iter().enumerate() {
1585                let i = TraitClauseId::new(i);
1586                writeln!(f, "{TAB_INCR}parent_clause{i} = {}", c.with_ctx(ctx))?;
1587            }
1588            for (name, clauses) in &self.type_clauses {
1589                for (i, c) in clauses.iter().enumerate() {
1590                    let i = TraitClauseId::new(i);
1591                    writeln!(f, "{TAB_INCR}item_clause_{name}_{i} = {}", c.with_ctx(ctx))?;
1592                }
1593            }
1594            for (name, global) in &self.consts {
1595                writeln!(f, "{TAB_INCR}const {name} = {}", global.with_ctx(ctx))?;
1596            }
1597            for (name, ty) in &self.types {
1598                writeln!(f, "{TAB_INCR}type {name} = {}", ty.with_ctx(ctx))?;
1599            }
1600            for (name, bound_fn) in self.methods() {
1601                let (params, fn_ref) = bound_fn.fmt_split(ctx);
1602                writeln!(f, "{TAB_INCR}fn {name}{params} = {fn_ref}")?;
1603            }
1604        }
1605        write!(f, "}}")?;
1606        Ok(())
1607    }
1608}
1609
1610impl<C: AstFormatter> FmtWithCtx<C> for TraitImplId {
1611    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1612        AnyTransId::from(*self).fmt_with_ctx(ctx, f)
1613    }
1614}
1615
1616impl<C: AstFormatter> FmtWithCtx<C> for TraitImplRef {
1617    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1618        let id = self.id.with_ctx(ctx);
1619        let generics = self.generics.with_ctx(ctx);
1620        write!(f, "{id}{generics}")
1621    }
1622}
1623
1624impl Display for TraitItemName {
1625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1626        write!(f, "{}", self.0)
1627    }
1628}
1629
1630impl<C: AstFormatter> FmtWithCtx<C> for TraitRefKind {
1631    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1632        match self {
1633            TraitRefKind::SelfId => write!(f, "Self"),
1634            TraitRefKind::ParentClause(id, _decl_id, clause_id) => {
1635                let id = id.with_ctx(ctx);
1636                write!(f, "{id}::parent_clause{clause_id}")
1637            }
1638            TraitRefKind::ItemClause(id, _decl_id, type_name, clause_id) => {
1639                let id = id.with_ctx(ctx);
1640                // Using on purpose `to_pretty_string` instead of `with_ctx`: the clause is local
1641                // to the associated type, so it should not be referenced in the current context.
1642                let clause = clause_id.to_pretty_string();
1643                write!(f, "({id}::{type_name}::[{clause}])")
1644            }
1645            TraitRefKind::TraitImpl(impl_ref) => {
1646                write!(f, "{}", impl_ref.with_ctx(ctx))
1647            }
1648            TraitRefKind::Clause(id) => write!(f, "{}", id.with_ctx(ctx)),
1649            TraitRefKind::BuiltinOrAuto {
1650                trait_decl_ref: tr,
1651                types,
1652                ..
1653            } => {
1654                write!(f, "{}", tr.with_ctx(ctx))?;
1655                if !types.is_empty() {
1656                    let types = types
1657                        .iter()
1658                        .map(|(name, ty)| {
1659                            let ty = ty.with_ctx(ctx);
1660                            format!("{name}  = {ty}")
1661                        })
1662                        .join(", ");
1663                    write!(f, " where {types}")?;
1664                }
1665                Ok(())
1666            }
1667            TraitRefKind::Dyn(tr) => write!(f, "{}", tr.with_ctx(ctx)),
1668            TraitRefKind::Unknown(msg) => write!(f, "UNKNOWN({msg})"),
1669        }
1670    }
1671}
1672
1673impl<C: AstFormatter> FmtWithCtx<C> for TraitRef {
1674    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1675        self.kind.fmt_with_ctx(ctx, f)
1676    }
1677}
1678
1679impl<C: AstFormatter> FmtWithCtx<C> for TraitTypeConstraint {
1680    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1681        let trait_ref = self.trait_ref.with_ctx(ctx);
1682        let ty = self.ty.with_ctx(ctx);
1683        write!(f, "{}::{} = {}", trait_ref, self.type_name, ty)
1684    }
1685}
1686
1687impl<C: AstFormatter> FmtWithCtx<C> for RegionBinder<(Vec<Ty>, Ty)> {
1688    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1689        // Update the bound regions
1690        let ctx = &ctx.push_bound_regions(&self.regions);
1691
1692        write!(f, "fn")?;
1693        if !self.regions.is_empty() {
1694            write!(
1695                f,
1696                "<{}>",
1697                self.regions.iter().map(|r| r.with_ctx(ctx)).format(", ")
1698            )?;
1699        }
1700        let (inputs, output) = &self.skip_binder;
1701        let inputs = inputs.iter().map(|x| x.with_ctx(ctx)).format(", ");
1702        write!(f, "({inputs})")?;
1703        if !output.is_unit() {
1704            let output = output.with_ctx(ctx);
1705            write!(f, " -> {output}")?;
1706        }
1707        Ok(())
1708    }
1709}
1710
1711impl<C: AstFormatter> FmtWithCtx<C> for Ty {
1712    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1713        match self.kind() {
1714            TyKind::Adt(tref) => {
1715                if tref.id.is_tuple() {
1716                    assert!(tref.generics.trait_refs.is_empty());
1717                    let generics = tref.generics.fmt_explicits(ctx).format(", ");
1718                    write!(f, "({generics})")
1719                } else {
1720                    write!(f, "{}", tref.with_ctx(ctx))
1721                }
1722            }
1723            TyKind::TypeVar(id) => write!(f, "{}", id.with_ctx(ctx)),
1724            TyKind::Literal(kind) => write!(f, "{kind}"),
1725            TyKind::Never => write!(f, "!"),
1726            TyKind::Ref(r, ty, kind) => {
1727                write!(f, "&{} ", r.with_ctx(ctx))?;
1728                if let RefKind::Mut = kind {
1729                    write!(f, "mut ")?;
1730                }
1731                write!(f, "({})", ty.with_ctx(ctx))
1732            }
1733            TyKind::RawPtr(ty, kind) => {
1734                write!(f, "*")?;
1735                match kind {
1736                    RefKind::Shared => write!(f, "const")?,
1737                    RefKind::Mut => write!(f, "mut")?,
1738                }
1739                write!(f, " {}", ty.with_ctx(ctx))
1740            }
1741            TyKind::TraitType(trait_ref, name) => {
1742                write!(f, "{}::{name}", trait_ref.with_ctx(ctx),)
1743            }
1744            TyKind::DynTrait(pred) => write!(f, "dyn ({})", pred.with_ctx(ctx)),
1745            TyKind::FnPtr(io) => {
1746                write!(f, "{}", io.with_ctx(ctx))
1747            }
1748            TyKind::FnDef(binder) => {
1749                let (regions, value) = binder.fmt_split(ctx);
1750                if !regions.is_empty() {
1751                    write!(f, "for<{regions}> ",)?
1752                };
1753                write!(f, "{value}",)
1754            }
1755            TyKind::Error(msg) => write!(f, "type_error(\"{msg}\")"),
1756        }
1757    }
1758}
1759
1760impl<C: AstFormatter> FmtWithCtx<C> for TypeDbVar {
1761    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1762        ctx.format_bound_var(f, *self, "@Type", |v| Some(v.to_string()))
1763    }
1764}
1765
1766impl<C: AstFormatter> FmtWithCtx<C> for TypeDecl {
1767    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1768        let keyword = match &self.kind {
1769            TypeDeclKind::Struct(..) => "struct",
1770            TypeDeclKind::Union(..) => "union",
1771            TypeDeclKind::Enum(..) => "enum",
1772            TypeDeclKind::Alias(..) => "type",
1773            TypeDeclKind::Opaque | TypeDeclKind::Error(..) => "opaque type",
1774        };
1775        self.item_meta
1776            .fmt_item_intro(f, ctx, keyword, self.def_id)?;
1777
1778        let ctx = &ctx.set_generics(&self.generics);
1779        let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
1780        write!(f, "{params}{preds}")?;
1781
1782        let nl_or_space = if !self.generics.has_predicates() {
1783            " ".to_string()
1784        } else {
1785            "\n".to_string()
1786        };
1787        match &self.kind {
1788            TypeDeclKind::Struct(fields) => {
1789                write!(f, "{nl_or_space}{{")?;
1790                if !fields.is_empty() {
1791                    writeln!(f)?;
1792                    for field in fields {
1793                        writeln!(f, "  {},", field.with_ctx(ctx))?;
1794                    }
1795                }
1796                write!(f, "}}")
1797            }
1798            TypeDeclKind::Union(fields) => {
1799                write!(f, "{nl_or_space}{{")?;
1800                writeln!(f)?;
1801                for field in fields {
1802                    writeln!(f, "  {},", field.with_ctx(ctx))?;
1803                }
1804                write!(f, "}}")
1805            }
1806            TypeDeclKind::Enum(variants) => {
1807                write!(f, "{nl_or_space}{{")?;
1808                writeln!(f)?;
1809                for variant in variants {
1810                    writeln!(f, "  {},", variant.with_ctx(ctx))?;
1811                }
1812                write!(f, "}}")
1813            }
1814            TypeDeclKind::Alias(ty) => write!(f, " = {}", ty.with_ctx(ctx)),
1815            TypeDeclKind::Opaque => write!(f, ""),
1816            TypeDeclKind::Error(msg) => write!(f, " = ERROR({msg})"),
1817        }
1818    }
1819}
1820
1821impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclId {
1822    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1823        AnyTransId::from(*self).fmt_with_ctx(ctx, f)
1824    }
1825}
1826
1827impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclRef {
1828    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1829        let id = self.id.with_ctx(ctx);
1830        let generics = self.generics.with_ctx(ctx);
1831        write!(f, "{id}{generics}")
1832    }
1833}
1834
1835impl<C: AstFormatter> FmtWithCtx<C> for TypeId {
1836    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1837        match self {
1838            TypeId::Tuple => Ok(()),
1839            TypeId::Adt(def_id) => write!(f, "{}", def_id.with_ctx(ctx)),
1840            TypeId::Builtin(aty) => write!(f, "{}", aty.get_name().with_ctx(ctx)),
1841        }
1842    }
1843}
1844
1845impl_display_via_ctx!(TypeVar);
1846impl<C: AstFormatter> FmtWithCtx<C> for TypeVar {
1847    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1848        write!(f, "{}", self.name)
1849    }
1850}
1851
1852impl<C: AstFormatter> FmtWithCtx<C> for UnOp {
1853    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1854        match self {
1855            UnOp::Not => write!(f, "~"),
1856            UnOp::Neg => write!(f, "-"),
1857            UnOp::PtrMetadata => write!(f, "ptr_metadata"),
1858            UnOp::Cast(kind) => write!(f, "{}", kind.with_ctx(ctx)),
1859            UnOp::ArrayToSlice(..) => write!(f, "array_to_slice"),
1860        }
1861    }
1862}
1863
1864impl_display_via_ctx!(Variant);
1865impl<C: AstFormatter> FmtWithCtx<C> for Variant {
1866    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1867        write!(f, "{}", self.name)?;
1868        if !self.fields.is_empty() {
1869            let fields = self.fields.iter().map(|f| f.with_ctx(ctx)).format(", ");
1870            write!(f, "({})", fields)?;
1871        }
1872        Ok(())
1873    }
1874}