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