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