Skip to main content

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