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