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