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