charon_lib/pretty/
fmt_with_ctx.rs

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