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