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