Skip to main content

charon_lib/pretty/
fmt_with_ctx.rs

1//! Utilities for pretty-printing (u)llbc.
2use crate::{
3    ast,
4    formatter::*,
5    ids::IndexVec,
6    llbc_ast::{self as llbc, *},
7    transform::utils::GenericsSource,
8    ullbc_ast::{self as ullbc, *},
9    utils::{TAB_INCR, repeat_except_first},
10};
11use either::Either;
12use itertools::Itertools;
13use std::{
14    borrow::Cow,
15    fmt::{self, Debug, Display},
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
68fn fmt_where_clauses<'a, I>(clauses: I, indent: &'a str) -> impl Display + 'a
69where
70    I: IntoIterator,
71    I::Item: Display,
72{
73    let clauses = clauses
74        .into_iter()
75        .map(|clause| clause.to_string())
76        .collect_vec();
77    std::fmt::from_fn(move |f| {
78        if !clauses.is_empty() {
79            write!(f, "\n{indent}where")?;
80            for (i, clause) in clauses.iter().enumerate() {
81                let sep = if i + 1 == clauses.len() { ";" } else { "," };
82                write!(f, "\n{indent}{TAB_INCR}{clause}{sep}")?;
83            }
84        }
85        Ok(())
86    })
87}
88
89//------- Impls, sorted by name --------
90
91impl<C: AstFormatter> FmtWithCtx<C> for AbortKind {
92    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        match self {
94            AbortKind::Panic(name) => {
95                write!(f, "panic")?;
96                if let Some(name) = name {
97                    write!(f, "({})", name.with_ctx(ctx))?;
98                }
99                Ok(())
100            }
101            AbortKind::UndefinedBehavior => write!(f, "undefined_behavior"),
102            AbortKind::UnwindTerminate => write!(f, "unwind_terminate"),
103        }
104    }
105}
106
107impl<C: AstFormatter> FmtWithCtx<C> for Abi {
108    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        write!(f, "{}", self.rust_name())
110    }
111}
112
113impl<C: AstFormatter> FmtWithCtx<C> for BuiltinAssertKind {
114    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        match self {
116            BuiltinAssertKind::BoundsCheck { .. } => write!(f, "bounds_check"),
117            BuiltinAssertKind::Overflow(..) => write!(f, "overflow"),
118            BuiltinAssertKind::OverflowNeg(..) => write!(f, "overflow_neg"),
119            BuiltinAssertKind::DivisionByZero(..) => write!(f, "division_by_zero"),
120            BuiltinAssertKind::RemainderByZero(..) => write!(f, "remainder_by_zero"),
121            BuiltinAssertKind::MisalignedPointerDereference { .. } => {
122                write!(f, "misaligned_pointer_dereference")
123            }
124            BuiltinAssertKind::NullPointerDereference => write!(f, "null_pointer_dereference"),
125            BuiltinAssertKind::NullReferenceCreated => write!(f, "null_reference_created"),
126            BuiltinAssertKind::InvalidEnumConstruction(..) => {
127                write!(f, "invalid_enum_construction")
128            }
129            BuiltinAssertKind::ResumedAfterReturn => write!(f, "resumed_after_return"),
130            BuiltinAssertKind::ResumedAfterDrop => write!(f, "resumed_after_drop"),
131            BuiltinAssertKind::ResumedAfterPanic => write!(f, "resumed_after_panic"),
132        }
133    }
134}
135
136impl<C: AstFormatter> FmtWithCtx<C> for ItemId {
137    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        match ctx.get_crate() {
139            None => write!(f, "{self}"),
140            Some(translated) => translated.item_short_name(*self).fmt_with_ctx(ctx, f),
141        }
142    }
143}
144
145impl Display for ItemId {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
147        let s = match self {
148            ItemId::Type(x) => x.to_pretty_string(),
149            ItemId::Fun(x) => x.to_pretty_string(),
150            ItemId::Global(x) => x.to_pretty_string(),
151            ItemId::TraitDecl(x) => x.to_pretty_string(),
152            ItemId::TraitImpl(x) => x.to_pretty_string(),
153        };
154        f.write_str(&s)
155    }
156}
157
158impl<C: AstFormatter> FmtWithCtx<C> for MaybeAssocItemId {
159    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        match self {
161            MaybeAssocItemId::Free(id) => id.fmt_with_ctx(ctx, f),
162            MaybeAssocItemId::Assoc(trait_id, item_id) => {
163                write!(f, "{}::", ItemId::TraitDecl(*trait_id).with_ctx(ctx),)?;
164                ctx.format_assoc_item_name(f, *trait_id, *item_id)
165            }
166        }
167    }
168}
169
170impl<C: AstFormatter> FmtWithCtx<C> for ItemRef<'_> {
171    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        match self {
173            ItemRef::Type(d) => write!(f, "{}", d.with_ctx(ctx)),
174            ItemRef::Fun(d) => write!(f, "{}", d.with_ctx(ctx)),
175            ItemRef::Global(d) => write!(f, "{}", d.with_ctx(ctx)),
176            ItemRef::TraitDecl(d) => write!(f, "{}", d.with_ctx(ctx)),
177            ItemRef::TraitImpl(d) => write!(f, "{}", d.with_ctx(ctx)),
178        }
179    }
180}
181
182impl<C: AstFormatter> FmtWithCtx<C> for Assert {
183    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(
185            f,
186            "assert({} == {})",
187            self.cond.with_ctx(ctx),
188            self.expected,
189        )?;
190        if let Some(check_kind) = &self.check_kind {
191            write!(f, " ({})", check_kind.with_ctx(ctx))?;
192        }
193        Ok(())
194    }
195}
196
197impl<T> Binder<T> {
198    /// Format the parameters and contents of this binder and returns the resulting strings.
199    fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
200    where
201        C: AstFormatter,
202        T: FmtWithCtx<C::Reborrow<'a>>,
203    {
204        self.fmt_split_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
205    }
206    /// Format the parameters and contents of this binder and returns the resulting strings.
207    fn fmt_split_with<'a, C>(
208        &'a self,
209        ctx: &'a C,
210        fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
211    ) -> (String, String)
212    where
213        C: AstFormatter,
214    {
215        let ctx = &ctx.push_binder(Cow::Borrowed(&self.params));
216        (
217            self.params.fmt_with_ctx_single_line(ctx),
218            fmt_inner(ctx, &self.skip_binder),
219        )
220    }
221}
222
223impl Display for OverflowMode {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
225        match self {
226            OverflowMode::Panic => write!(f, "panic"),
227            OverflowMode::Wrap => write!(f, "wrap"),
228            OverflowMode::UB => write!(f, "ub"),
229        }
230    }
231}
232
233impl Display for BinOp {
234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
235        match self {
236            BinOp::BitXor => write!(f, "^"),
237            BinOp::BitAnd => write!(f, "&"),
238            BinOp::BitOr => write!(f, "|"),
239            BinOp::Eq => write!(f, "=="),
240            BinOp::Lt => write!(f, "<"),
241            BinOp::Le => write!(f, "<="),
242            BinOp::Ne => write!(f, "!="),
243            BinOp::Ge => write!(f, ">="),
244            BinOp::Gt => write!(f, ">"),
245            BinOp::Add(mode) => write!(f, "{}.+", mode),
246            BinOp::Sub(mode) => write!(f, "{}.-", mode),
247            BinOp::Mul(mode) => write!(f, "{}.*", mode),
248            BinOp::Div(mode) => write!(f, "{}./", mode),
249            BinOp::Rem(mode) => write!(f, "{}.%", mode),
250            BinOp::AddChecked => write!(f, "checked.+"),
251            BinOp::SubChecked => write!(f, "checked.-"),
252            BinOp::MulChecked => write!(f, "checked.*"),
253            BinOp::Shl(mode) => write!(f, "{}.<<", mode),
254            BinOp::Shr(mode) => write!(f, "{}.>>", mode),
255            BinOp::Cmp => write!(f, "cmp"),
256            BinOp::Offset => write!(f, "offset"),
257        }
258    }
259}
260
261impl<C: AstFormatter> FmtWithCtx<C> for llbc::Block {
262    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263        for st in &self.statements {
264            st.fmt_with_ctx(ctx, f)?;
265        }
266        Ok(())
267    }
268}
269
270const LLBC_UNWIND_PREFIX: &str = "↳⚡ ";
271
272fn fmt_llbc_unwind_block<C: AstFormatter>(
273    ctx: &C,
274    f: &mut fmt::Formatter<'_>,
275    on_unwind: &llbc::Block,
276) -> fmt::Result {
277    let tab = ctx.indent();
278    let block = on_unwind.to_string_with_ctx(&ctx.reset_indent());
279    let mut lines = block.lines();
280    if let Some(first) = lines.next() {
281        write!(f, "\n{tab}{LLBC_UNWIND_PREFIX}{first}")?;
282        let ctx = ctx.increase_indent();
283        let tab = ctx.indent();
284        for line in lines {
285            write!(f, "\n{tab}{line}")?;
286        }
287    }
288    Ok(())
289}
290
291impl<C: AstFormatter> FmtWithCtx<C> for ullbc::BlockData {
292    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293        for statement in &self.statements {
294            statement.fmt_with_ctx(ctx, f)?;
295        }
296        write!(f, "{};", self.terminator.with_ctx(ctx))?;
297        Ok(())
298    }
299}
300
301impl<C: AstFormatter> FmtWithCtx<C> for ast::Body {
302    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        let tab = ctx.indent();
304        write!(f, "\n{tab}")?;
305        match self {
306            Body::Unstructured(body) => {
307                let body = body.with_ctx(ctx);
308                write!(f, "{{\n{body}{tab}}}")
309            }
310            Body::Structured(body) => {
311                let body = body.with_ctx(ctx);
312                write!(f, "{{\n{body}{tab}}}")
313            }
314            Body::Extern(name) => write!(f, "= <extern:{name}>"),
315            Body::Intrinsic { name, .. } => write!(f, "= <intrinsic:{name}>"),
316            Body::Opaque => write!(f, "= <opaque>"),
317            Body::Missing => write!(f, "= <missing>"),
318            Body::Error(error) => write!(f, "= error(\"{}\")", error.msg),
319            Body::TargetDispatch(targets) => {
320                writeln!(f, "= target_dispatch {{")?;
321                for (target, fun) in targets {
322                    let fun = fun.with_ctx(ctx);
323                    writeln!(f, "{tab}{TAB_INCR}{target} => {fun},")?;
324                }
325                write!(f, "{tab}}}")
326            }
327        }
328    }
329}
330
331impl Display for BorrowKind {
332    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
333        // Reuse the derived `Debug` impl to get the variant name.
334        write!(f, "{self:?}")
335    }
336}
337
338impl<C: AstFormatter> FmtWithCtx<C> for Call {
339    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        let dest = self.dest.with_ctx(ctx);
341        let func = self.func.with_ctx(ctx);
342        let args = self.args.iter().map(|x| x.with_ctx(ctx)).format(", ");
343        write!(f, "{dest} = {func}({args})")
344    }
345}
346
347impl<C: AstFormatter> FmtWithCtx<C> for UnsizingMetadata {
348    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349        match self {
350            UnsizingMetadata::Length(len) => write!(f, "{}", len.with_ctx(ctx)),
351            UnsizingMetadata::VTable(_, vtable) => {
352                write!(f, "{}", vtable.with_ctx(ctx))
353            }
354            UnsizingMetadata::VTableUpcast(fields) => {
355                write!(f, " at [")?;
356                let fields = fields.iter().map(|x| format!("{}", x.index())).format(", ");
357                write!(f, "{fields}]")
358            }
359            UnsizingMetadata::Unknown => {
360                write!(f, "?")
361            }
362        }
363    }
364}
365
366impl<C: AstFormatter> FmtWithCtx<C> for CastKind {
367    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368        match self {
369            CastKind::Scalar(src, tgt) => write!(f, "cast<{src}, {tgt}>"),
370            CastKind::FnPtr(src, tgt) | CastKind::RawPtr(src, tgt) => {
371                write!(f, "cast<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
372            }
373            CastKind::Unsize(src, tgt, meta) => write!(
374                f,
375                "unsize_cast<{}, {}, {}>",
376                src.with_ctx(ctx),
377                tgt.with_ctx(ctx),
378                meta.with_ctx(ctx)
379            ),
380            CastKind::Transmute(src, tgt) => {
381                write!(f, "transmute<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
382            }
383            CastKind::Concretize(ty, ty1) => {
384                write!(f, "concretize<{}, {}>", ty.with_ctx(ctx), ty1.with_ctx(ctx))
385            }
386        }
387    }
388}
389
390impl<C: AstFormatter> FmtWithCtx<C> for ClauseDbVar {
391    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392        ctx.format_bound_var(f, *self, "TraitClause", |_| None)
393    }
394}
395
396impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericDbVar {
397    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398        ctx.format_bound_var(f, *self, "@ConstGeneric", |v| Some(v.name.clone()))
399    }
400}
401
402impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericParam {
403    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        write!(f, "const {} : {}", self.name, self.ty.with_ctx(ctx))
405    }
406}
407
408impl Display for DeBruijnId {
409    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
410        write!(f, "{}", self.index)
411    }
412}
413
414impl<Id: Display> Display for DeBruijnVar<Id> {
415    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416        match self {
417            Self::Bound(dbid, varid) => write!(f, "Bound({dbid}, {varid})"),
418            Self::Free(varid) => write!(f, "{varid}"),
419        }
420    }
421}
422
423impl<C: AstFormatter> FmtWithCtx<C> for DeclarationGroup {
424    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425        use DeclarationGroup::*;
426        match self {
427            Type(g) => write!(f, "Type decls group: {}", g.with_ctx(ctx)),
428            Fun(g) => write!(f, "Fun decls group: {}", g.with_ctx(ctx)),
429            Global(g) => write!(f, "Global decls group: {}", g.with_ctx(ctx)),
430            TraitDecl(g) => write!(f, "Trait decls group: {}", g.with_ctx(ctx)),
431            TraitImpl(g) => write!(f, "Trait impls group: {}", g.with_ctx(ctx)),
432            Mixed(g) => write!(f, "Mixed group: {}", g.with_ctx(ctx)),
433        }
434    }
435}
436
437impl<C: AstFormatter> FmtWithCtx<C> for Discriminator {
438    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439        match self {
440            Discriminator::Known(variant_id) => ctx.format_current_variant_name(f, *variant_id),
441            Discriminator::Invalid => write!(f, "invalid"),
442            Discriminator::Branch {
443                offset,
444                children,
445                fallback,
446                ..
447            } => {
448                write!(f, "read at offset {} {{ ", offset.with_ctx(ctx))?;
449                for (range, child) in children {
450                    if range.start() == range.end() {
451                        write!(f, "{}", range.start())?;
452                    } else {
453                        write!(f, "{}..={}", range.start(), range.end())?;
454                    }
455                    write!(f, " => {}, ", child.with_ctx(ctx))?;
456                }
457                write!(f, "_ => {} }}", fallback.with_ctx(ctx))
458            }
459        }
460    }
461}
462
463impl<C: AstFormatter> FmtWithCtx<C> for DynPredicate {
464    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465        let params = &self.binder.params;
466        let ctx = &ctx.push_binder(Cow::Borrowed(params));
467        let GenericParams {
468            regions,
469            types,
470            const_generics,
471            trait_clauses,
472            regions_outlive,
473            types_outlive,
474            trait_type_constraints,
475        } = params;
476        assert!(regions.is_empty());
477        assert!(const_generics.is_empty());
478        assert!(regions_outlive.is_empty());
479        assert_eq!(types.len(), 1);
480
481        // Format the clauses with their assoc types, e.g. `Iterator<Item = ...>`.
482        let mut cstrs_per_clause: IndexVec<TraitClauseId, Vec<String>> =
483            trait_clauses.map_ref(|_| vec![]);
484        for cstr in trait_type_constraints {
485            let mut tgt_clause = None;
486            let (_, cstr) = cstr.fmt_split_with(ctx, |ctx, cstr| {
487                let mut path = vec![];
488                let mut tref = &cstr.trait_ref;
489                loop {
490                    match &tref.kind {
491                        TraitRefKind::ParentClause(parent_trait_ref, clause_id) => {
492                            path.push(*clause_id);
493                            tref = parent_trait_ref;
494                        }
495                        &TraitRefKind::Clause(DeBruijnVar::Bound(_, clause_id)) => {
496                            tgt_clause = Some(clause_id);
497                            break;
498                        }
499                        _ => unreachable!(),
500                    }
501                }
502                let ty = cstr.ty.with_ctx(ctx);
503                let path_fmt = path.iter().map(|id| id.format_as_implied()).format("::");
504                std::fmt::from_fn(|f| {
505                    write!(f, "{path_fmt}")?;
506                    if !path.is_empty() {
507                        write!(f, "::")?;
508                    }
509                    ctx.format_assoc_type_name(f, cstr.trait_ref.trait_id(), cstr.type_id)?;
510                    write!(f, " = {ty}")?;
511                    Ok(())
512                })
513                .to_string()
514            });
515            if let Some(cstrs) = cstrs_per_clause.get_mut(tgt_clause.unwrap()) {
516                cstrs.push(cstr);
517            }
518        }
519        let trait_clauses = trait_clauses.iter().map(|clause| {
520            let cstrs = &cstrs_per_clause[clause.clause_id];
521            clause.trait_.fmt_as_for_with(ctx, |ctx, pred| {
522                let (_, pred) = pred.split_self();
523                let trait_id = pred.id.with_ctx(ctx);
524                let generics = if pred.generics.has_explicits() || !cstrs.is_empty() {
525                    let xs = pred
526                        .generics
527                        .fmt_explicits(ctx)
528                        .map(Either::Left)
529                        .chain(cstrs.iter().map(Either::Right))
530                        .format(", ");
531                    format!("<{}>", xs)
532                } else {
533                    String::new()
534                };
535                format!("{trait_id}{generics}")
536            })
537        });
538
539        let types_outlive = types_outlive
540            .iter()
541            .filter(|x| !x.skip_binder.1.is_erased())
542            .map(|x| {
543                x.fmt_as_for_with(ctx, |ctx, types_outlive| {
544                    types_outlive.1.to_string_with_ctx(ctx)
545                })
546            });
547        let clauses = trait_clauses.chain(types_outlive).format(" + ");
548        write!(f, "{clauses}")
549    }
550}
551
552impl_display_via_ctx!(Field);
553impl<C: AstFormatter> FmtWithCtx<C> for Field {
554    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555        write!(f, "{}: {}", self.name, self.ty.with_ctx(ctx))
556    }
557}
558
559impl Display for FileName {
560    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
561        match self {
562            FileName::Virtual(path_buf) | FileName::Local(path_buf) => {
563                write!(f, "{}", path_buf.display())
564            }
565            FileName::NotReal(name) => write!(f, "{}", name),
566        }
567    }
568}
569
570impl Display for FloatTy {
571    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
572        match self {
573            FloatTy::F16 => write!(f, "f16"),
574            FloatTy::F32 => write!(f, "f32"),
575            FloatTy::F64 => write!(f, "f64"),
576            FloatTy::F128 => write!(f, "f128"),
577        }
578    }
579}
580
581impl Display for FloatValue {
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
583        let v = &self.value;
584        let ty = self.ty;
585        write!(f, "{v}{ty}")
586    }
587}
588
589impl<C: AstFormatter> FmtWithCtx<C> for FnOperand {
590    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591        match self {
592            FnOperand::Regular(func) => write!(f, "{}", func.with_ctx(ctx)),
593            FnOperand::Dynamic(op) => write!(f, "({})", op.with_ctx(ctx)),
594        }
595    }
596}
597
598impl<C: AstFormatter> FmtWithCtx<C> for FnPtr {
599    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600        match self.kind.as_ref() {
601            FnPtrKind::Fun(def_id) => write!(f, "{}", def_id.with_ctx(ctx))?,
602            FnPtrKind::Trait(trait_ref, method_id) => {
603                write!(f, "{}::", trait_ref.with_ctx(ctx))?;
604                ctx.format_method_name(f, trait_ref.trait_id(), *method_id)?;
605            }
606        };
607        write!(f, "{}", self.generics.with_ctx(ctx))
608    }
609}
610
611impl<C: AstFormatter> FmtWithCtx<C> for FunDecl {
612    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613        let mut keyword = String::new();
614        if self.signature.is_unsafe {
615            keyword.push_str("unsafe ");
616        }
617        if !self.signature.abi.is_rust() {
618            keyword.push_str(&format!("extern \"{}\" ", self.signature.abi.with_ctx(ctx)));
619        }
620        keyword.push_str("fn");
621        self.item_meta
622            .fmt_item_intro(f, ctx, &keyword, self.def_id)?;
623
624        // Update the context
625        let ctx = &ctx.set_generics(&self.generics);
626
627        // Generic parameters
628        let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
629        write!(f, "{params}")?;
630
631        // Arguments
632        let n_args = self.signature.inputs.len();
633        let args_of_locals = |l: &Locals| {
634            let ctx = ctx.set_locals(l);
635            l.locals
636                .iter()
637                .skip(1)
638                .take(n_args)
639                .map(|l| format!("{}", l.index.with_ctx(&ctx)))
640                .collect::<Vec<String>>()
641        };
642
643        let arg_names = match &self.body {
644            Body::Unstructured(body) => args_of_locals(&body.locals),
645            Body::Structured(body) => args_of_locals(&body.locals),
646            Body::Intrinsic { arg_names, .. } => arg_names
647                .iter()
648                .enumerate()
649                .map(|(i, name)| {
650                    let id = LocalId::new(i + 1);
651                    match name {
652                        Some(name) => format!("{name}_{id}"),
653                        None => format!("_{id}"),
654                    }
655                })
656                .collect(),
657            Body::Error(..)
658            | Body::Extern(..)
659            | Body::Missing
660            | Body::Opaque
661            | Body::TargetDispatch(..) => (0..n_args)
662                .map(|i| format!("{}", LocalId::new(i + 1).with_ctx(ctx)))
663                .collect(),
664        };
665        let mut args: Vec<String> = Vec::new();
666        for (ty, name) in self.signature.inputs.iter().zip(arg_names) {
667            args.push(format!("{}: {}", name, ty.with_ctx(ctx)));
668        }
669        let args = args.join(", ");
670        if self.signature.is_variadic {
671            if args.is_empty() {
672                write!(f, "(...)")?;
673            } else {
674                write!(f, "({args}, ...)")?;
675            }
676        } else {
677            write!(f, "({args})")?;
678        }
679
680        // Return type
681        if !self.signature.output.is_unit() {
682            write!(f, " -> {}", self.signature.output.with_ctx(ctx))?;
683        };
684        write!(f, "{preds}")?;
685        write!(f, "{}", self.body.with_ctx(ctx))?;
686
687        Ok(())
688    }
689}
690
691impl<C: AstFormatter> FmtWithCtx<C> for FunDeclId {
692    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693        ItemId::from(*self).fmt_with_ctx(ctx, f)
694    }
695}
696
697impl<C: AstFormatter> FmtWithCtx<C> for FunDeclRef {
698    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699        let id = self.id.with_ctx(ctx);
700        let generics = self.generics.with_ctx(ctx);
701        write!(f, "{id}{generics}")
702    }
703}
704
705impl<C: AstFormatter> FmtWithCtx<C> for RegionBinder<FunSig> {
706    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707        // Update the bound regions
708        let ctx = &ctx.push_bound_regions(&self.regions);
709        let FunSig {
710            is_unsafe,
711            abi,
712            is_variadic,
713            inputs,
714            output,
715        } = &self.skip_binder;
716
717        if *is_unsafe {
718            write!(f, "unsafe ")?;
719        }
720
721        if !abi.is_rust() {
722            write!(f, "extern \"{}\" ", abi.with_ctx(ctx))?;
723        }
724
725        write!(f, "fn")?;
726        if !self.regions.is_empty() {
727            write!(
728                f,
729                "<{}>",
730                self.regions.iter().map(|r| r.with_ctx(ctx)).format(", ")
731            )?;
732        }
733        let is_empty = inputs.is_empty();
734        let inputs = inputs.iter().map(|x| x.with_ctx(ctx)).format(", ");
735        if *is_variadic {
736            if is_empty {
737                write!(f, "(...)")?;
738            } else {
739                write!(f, "({inputs}, ...)")?;
740            }
741        } else {
742            write!(f, "({inputs})")?;
743        }
744        if !output.is_unit() {
745            let output = output.with_ctx(ctx);
746            write!(f, " -> {output}")?;
747        }
748        Ok(())
749    }
750}
751
752impl<Id: Copy, C: AstFormatter> FmtWithCtx<C> for GDeclarationGroup<Id>
753where
754    Id: FmtWithCtx<C>,
755{
756    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        use GDeclarationGroup::*;
758        match self {
759            NonRec(id) => write!(f, "Non rec: {}", id.with_ctx(ctx)),
760            Rec(ids) => {
761                let ids = ids.iter().map(|id| id.with_ctx(ctx)).format(", ");
762                write!(f, "Rec: {}", ids)
763            }
764        }
765    }
766}
767
768impl GenericArgs {
769    pub(crate) fn fmt_explicits<'a, C: AstFormatter>(
770        &'a self,
771        ctx: &'a C,
772    ) -> impl Iterator<Item = impl Display + 'a> {
773        let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
774        let types = self.types.iter().map(|x| x.with_ctx(ctx));
775        let const_generics = self.const_generics.iter().map(|x| x.with_ctx(ctx));
776        regions.map(Either::Left).chain(
777            types
778                .map(Either::Left)
779                .chain(const_generics.map(Either::Right))
780                .map(Either::Right),
781        )
782    }
783
784    pub(crate) fn fmt_implicits<'a, C: AstFormatter>(
785        &'a self,
786        ctx: &'a C,
787    ) -> impl Iterator<Item = impl Display + 'a> {
788        self.trait_refs.iter().map(|x| x.with_ctx(ctx))
789    }
790}
791
792impl_display_via_ctx!(GenericArgs);
793impl_debug_via_display!(GenericArgs);
794impl<C: AstFormatter> FmtWithCtx<C> for GenericArgs {
795    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796        if self.has_explicits() {
797            write!(f, "<{}>", self.fmt_explicits(ctx).format(", "))?;
798        }
799        if self.has_implicits() {
800            write!(f, "[{}]", self.fmt_implicits(ctx).format(", "))?;
801        }
802        Ok(())
803    }
804}
805
806impl GenericParams {
807    fn formatted_params<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
808    where
809        C: AstFormatter,
810    {
811        let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
812        let types = self.types.iter().map(|x| x.with_ctx(ctx));
813        let const_generics = self.const_generics.iter().map(|x| x.with_ctx(ctx));
814        regions.map(Either::Left).chain(
815            types
816                .map(Either::Left)
817                .chain(const_generics.map(Either::Right))
818                .map(Either::Right),
819        )
820    }
821
822    fn formatted_clauses<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
823    where
824        C: AstFormatter,
825    {
826        let trait_clauses = self.trait_clauses.iter().map(|x| x.to_string_with_ctx(ctx));
827        let types_outlive = self
828            .types_outlive
829            .iter()
830            .enumerate()
831            .map(|(i, x)| format!("TypeOutlives{i}: {}", x.fmt_as_for(ctx)));
832        let regions_outlive = self
833            .regions_outlive
834            .iter()
835            .enumerate()
836            .map(|(i, x)| format!("RegionOutlives{i}: {}", x.fmt_as_for(ctx)));
837        let type_constraints = self
838            .trait_type_constraints
839            .iter_enumerated()
840            .map(|(i, x)| format!("TypeConstraint{i}: {}", x.fmt_as_for(ctx)));
841        trait_clauses.map(Either::Left).chain(
842            types_outlive
843                .chain(regions_outlive)
844                .chain(type_constraints)
845                .map(Either::Right),
846        )
847    }
848
849    pub fn fmt_with_ctx_with_trait_clauses<C>(&self, ctx: &C) -> (String, String)
850    where
851        C: AstFormatter,
852    {
853        let tab = ctx.indent();
854        let params = if self.has_explicits() {
855            let params = self.formatted_params(ctx).format(", ");
856            format!("<{}>", params)
857        } else {
858            String::new()
859        };
860        let clauses = if self.has_predicates() {
861            let clauses = self
862                .formatted_clauses(ctx)
863                .map(|x| format!("\n{tab}{TAB_INCR}{x},"))
864                .format("");
865            format!("\n{tab}where{clauses}")
866        } else {
867            String::new()
868        };
869        (params, clauses)
870    }
871
872    pub fn fmt_with_ctx_single_line<C>(&self, ctx: &C) -> String
873    where
874        C: AstFormatter,
875    {
876        if self.is_empty() {
877            String::new()
878        } else {
879            let params = self
880                .formatted_params(ctx)
881                .map(Either::Left)
882                .chain(self.formatted_clauses(ctx).map(Either::Right))
883                .format(", ");
884            format!("<{}>", params)
885        }
886    }
887}
888
889impl_debug_via_display!(GenericParams);
890impl Display for GenericParams {
891    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
892        write!(f, "{}", self.fmt_with_ctx_single_line(&FmtCtx::new()))
893    }
894}
895
896impl<C: AstFormatter> FmtWithCtx<C> for GenericsSource {
897    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898        match self {
899            GenericsSource::Item(id) => write!(f, "{}", id.with_ctx(ctx)),
900            GenericsSource::Method(id, name) => write!(f, "{}::{name}", id.with_ctx(ctx)),
901            GenericsSource::TraitType(id, name) => {
902                write!(f, "{}::", id.with_ctx(ctx))?;
903                ctx.format_assoc_type_name(f, *id, *name)
904            }
905            GenericsSource::Builtin => write!(f, "<builtin>"),
906            GenericsSource::Other => write!(f, "<unknown>"),
907        }
908    }
909}
910
911impl<T> GExprBody<T> {
912    fn fmt_with_ctx_and_callback<C: AstFormatter>(
913        &self,
914        ctx: &C,
915        f: &mut fmt::Formatter<'_>,
916        fmt_body: impl FnOnce(
917            &mut fmt::Formatter<'_>,
918            &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
919            &T,
920        ) -> fmt::Result,
921    ) -> fmt::Result {
922        // Update the context
923        let ctx = &ctx.set_locals(&self.locals);
924        let ctx = &ctx.increase_indent();
925        let tab = ctx.indent();
926
927        // Format the local variables
928        for v in &self.locals.locals {
929            write!(f, "{tab}")?;
930            write!(f, "let {}: {};", v.index.with_ctx(ctx), v.ty.with_ctx(ctx))?;
931
932            write!(f, " // ")?;
933            if v.index.is_zero() {
934                write!(f, "return")?;
935            } else if self.locals.is_return_or_arg(v.index) {
936                write!(f, "arg #{}", v.index.index())?
937            } else {
938                match &v.name {
939                    Some(_) => write!(f, "local")?,
940                    None => write!(f, "anonymous local")?,
941                }
942            }
943            writeln!(f)?;
944        }
945
946        fmt_body(f, ctx, &self.body)?;
947
948        Ok(())
949    }
950}
951
952impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<llbc_ast::Block> {
953    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954        // Inference fails when this is a closure.
955        fn fmt_body<C: AstFormatter>(
956            f: &mut fmt::Formatter<'_>,
957            ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
958            body: &Block,
959        ) -> Result<(), fmt::Error> {
960            writeln!(f)?;
961            body.fmt_with_ctx(ctx, f)?;
962            Ok(())
963        }
964        self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
965    }
966}
967impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<ullbc_ast::BodyContents> {
968    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
969        // Inference fails when this is a closure.
970        fn fmt_body<C: AstFormatter>(
971            f: &mut fmt::Formatter<'_>,
972            ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
973            body: &IndexVec<ullbc::BlockId, BlockData>,
974        ) -> Result<(), fmt::Error> {
975            let tab = ctx.indent();
976            let ctx = &ctx.increase_indent();
977            for (bid, block) in body.iter_enumerated() {
978                writeln!(f)?;
979                writeln!(f, "{tab}bb{}: {{", bid.index())?;
980                writeln!(f, "{}", block.with_ctx(ctx))?;
981                writeln!(f, "{tab}}}")?;
982            }
983            Ok(())
984        }
985        self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
986    }
987}
988
989impl<C> FmtWithCtx<C> for GlobalDecl
990where
991    C: AstFormatter,
992{
993    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994        let keyword = match self.global_kind {
995            GlobalKind::Static => "static",
996            GlobalKind::ThreadLocal => "thread_local",
997            GlobalKind::AnonConst | GlobalKind::NamedConst => "const",
998        };
999        self.item_meta
1000            .fmt_item_intro(f, ctx, keyword, self.def_id)?;
1001
1002        // Update the context with the generics
1003        let ctx = &ctx.set_generics(&self.generics);
1004
1005        // Translate the parameters and the trait clauses
1006        let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
1007
1008        // Type
1009        let ty = self.ty.with_ctx(ctx);
1010        write!(f, "{params}: {ty}")?;
1011
1012        // Predicates
1013        write!(f, "{preds}")?;
1014        if self.generics.has_predicates() {
1015            writeln!(f)?;
1016        }
1017        write!(f, " ")?;
1018
1019        // Value
1020        let value = self.value.with_ctx(ctx);
1021        write!(f, "= {value}")?;
1022
1023        Ok(())
1024    }
1025}
1026
1027impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclId {
1028    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1029        ItemId::from(*self).fmt_with_ctx(ctx, f)
1030    }
1031}
1032
1033impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclRef {
1034    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1035        let id = self.id.with_ctx(ctx);
1036        let generics = self.generics.with_ctx(ctx);
1037        write!(f, "{id}{generics}")
1038    }
1039}
1040
1041impl<C: AstFormatter> FmtWithCtx<C> for ImplElem {
1042    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043        write!(f, "{{")?;
1044        match self {
1045            ImplElem::Ty(bound_ty) => {
1046                // Just printing the generics (not the predicates)
1047                let ctx = ctx.set_generics(&bound_ty.params);
1048                bound_ty.skip_binder.fmt_with_ctx(&ctx, f)?
1049            }
1050            ImplElem::Trait(impl_id) => {
1051                match ctx.get_crate().and_then(|tr| tr.trait_impls.get(*impl_id)) {
1052                    None => write!(f, "impl#{impl_id}")?,
1053                    Some(timpl) => {
1054                        // We need to put the first type parameter aside: it is the type for which
1055                        // we implement the trait.
1056                        let ctx = &ctx.set_generics(&timpl.generics);
1057                        let mut impl_trait = timpl.impl_trait.clone();
1058                        match impl_trait
1059                            .generics
1060                            .types
1061                            .remove_and_shift_ids(TypeVarId::ZERO)
1062                        {
1063                            Some(self_ty) => {
1064                                let self_ty = self_ty.with_ctx(ctx);
1065                                let impl_trait = impl_trait.with_ctx(ctx);
1066                                write!(f, "impl {impl_trait} for {self_ty}")?;
1067                            }
1068                            // TODO(mono): A monomorphized trait doesn't take arguments.
1069                            None => {
1070                                let impl_trait = impl_trait.with_ctx(ctx);
1071                                write!(f, "impl {impl_trait}")?;
1072                            }
1073                        }
1074                    }
1075                }
1076            }
1077        }
1078        write!(f, "}}")
1079    }
1080}
1081
1082impl Display for IntTy {
1083    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1084        match self {
1085            IntTy::Isize => write!(f, "isize"),
1086            IntTy::I8 => write!(f, "i8"),
1087            IntTy::I16 => write!(f, "i16"),
1088            IntTy::I32 => write!(f, "i32"),
1089            IntTy::I64 => write!(f, "i64"),
1090            IntTy::I128 => write!(f, "i128"),
1091        }
1092    }
1093}
1094
1095impl Display for UIntTy {
1096    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1097        match self {
1098            UIntTy::Usize => write!(f, "usize"),
1099            UIntTy::U8 => write!(f, "u8"),
1100            UIntTy::U16 => write!(f, "u16"),
1101            UIntTy::U32 => write!(f, "u32"),
1102            UIntTy::U64 => write!(f, "u64"),
1103            UIntTy::U128 => write!(f, "u128"),
1104        }
1105    }
1106}
1107
1108impl Display for IntegerTy {
1109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1110        match self {
1111            IntegerTy::Signed(int_ty) => write!(f, "{int_ty}"),
1112            IntegerTy::Unsigned(uint_ty) => write!(f, "{uint_ty}"),
1113        }
1114    }
1115}
1116
1117fn trait_impl_short_name<C: AstFormatter>(ctx: &C, impl_id: TraitImplId) -> Option<&Name> {
1118    ctx.get_crate()
1119        .and_then(|tr| tr.short_names.get(&ItemId::TraitImpl(impl_id)))
1120        .filter(|name| matches!(name.name.first(), Some(PathElem::Ident(..))))
1121}
1122
1123impl ItemMeta {
1124    /// Format the start of an item definition, up to the name.
1125    pub fn fmt_item_intro<C: AstFormatter>(
1126        &self,
1127        f: &mut fmt::Formatter<'_>,
1128        ctx: &C,
1129        keyword: &str,
1130        id: impl Into<ItemId>,
1131    ) -> fmt::Result {
1132        let tab = ctx.indent();
1133        let id = id.into();
1134        let mut name = &self.name;
1135        let mut name_is_full = true;
1136        if let Some(tr) = ctx.get_crate()
1137            && let Some(short_name) = tr.short_names.get(&id)
1138        {
1139            name = short_name;
1140            name_is_full = false;
1141        } else if self
1142            .name
1143            .name
1144            .iter()
1145            .filter_map(|ne| ne.as_impl()?.as_trait())
1146            .any(|impl_id| trait_impl_short_name(ctx, *impl_id).is_some())
1147        {
1148            name_is_full = false;
1149        };
1150        if !name_is_full {
1151            writeln!(f, "// Full name: {}", self.name.full_name(ctx))?;
1152        }
1153
1154        for attr in &self.attr_info.attributes {
1155            // Doc-comments are long and don't affect the semantics; skip them.
1156            if attr.is_doc_comment() {
1157                continue;
1158            }
1159            writeln!(f, "{tab}{}", attr.with_ctx(ctx))?;
1160        }
1161        if let Some(id) = &self.lang_item {
1162            writeln!(f, "{tab}#[lang_item({id:?})]")?;
1163        }
1164        if let Some(id) = &self.diagnostic_item {
1165            writeln!(f, "{tab}#[diagnostic_item(\"{id}\")]")?;
1166        }
1167        write!(f, "{tab}")?;
1168        if self.attr_info.public {
1169            write!(f, "pub ")?;
1170        }
1171        write!(f, "{keyword} {}", name.with_ctx(ctx))
1172    }
1173}
1174
1175impl_display_via_ctx!(InhabitedPredicate);
1176impl<C: AstFormatter> FmtWithCtx<C> for InhabitedPredicate {
1177    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1178        match self.kind() {
1179            InhabitedPredicateKind::True => write!(f, "true"),
1180            InhabitedPredicateKind::False => write!(f, "false"),
1181            InhabitedPredicateKind::ConstIsZero(value) => {
1182                write!(f, "{} == 0", value.with_ctx(ctx))
1183            }
1184            InhabitedPredicateKind::GenericType(ty) => {
1185                write!(f, "if_inhabited({})", ty.with_ctx(ctx))
1186            }
1187            InhabitedPredicateKind::And(predicates) => {
1188                write!(
1189                    f,
1190                    "({})",
1191                    predicates.iter().map(|p| p.with_ctx(ctx)).format(" && ")
1192                )
1193            }
1194            InhabitedPredicateKind::Or(predicates) => {
1195                write!(
1196                    f,
1197                    "({})",
1198                    predicates.iter().map(|p| p.with_ctx(ctx)).format(" || ")
1199                )
1200            }
1201        }
1202    }
1203}
1204
1205impl_display_via_ctx!(Layout);
1206impl<C: AstFormatter> FmtWithCtx<C> for Layout {
1207    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1208        let tab = ctx.indent();
1209        writeln!(f, "{tab}size: {},", self.size.with_ctx(ctx))?;
1210        writeln!(f, "{tab}align: {},", self.align.with_ctx(ctx))?;
1211        match &self.discriminator {
1212            Some(discriminator) => {
1213                writeln!(f, "{tab}discriminator: {},", discriminator.with_ctx(ctx))?
1214            }
1215            None => writeln!(f, "{tab}discriminator: none,")?,
1216        }
1217        writeln!(f, "{tab}inhabited: {},", self.inhabited.with_ctx(ctx))?;
1218        writeln!(f, "{tab}variants: [")?;
1219        let ctx1 = &ctx.increase_indent();
1220        let tab1 = ctx1.indent();
1221        for (variant_id, layout) in self.variant_layouts.iter_enumerated() {
1222            write!(f, "{tab1}")?;
1223            ctx1.format_current_variant_name(f, variant_id)?;
1224            write!(f, ": ")?;
1225            match layout {
1226                Some(layout) => writeln!(f, "{},", layout.with_ctx(&(ctx1, variant_id)))?,
1227                None => writeln!(f, "none,")?,
1228            }
1229        }
1230        writeln!(f, "{tab}],")?;
1231        write!(f, "{tab}{},", self.repr)
1232    }
1233}
1234
1235impl Display for ScalarTy {
1236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1237        match self {
1238            ScalarTy::Integer(ty) => write!(f, "{ty}"),
1239            ScalarTy::Float(ty) => write!(f, "{ty}"),
1240            ScalarTy::Char => write!(f, "char"),
1241            ScalarTy::Bool => write!(f, "bool"),
1242        }
1243    }
1244}
1245
1246impl Display for Loc {
1247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1248        write!(f, "{}:{}", self.line, self.col)
1249    }
1250}
1251
1252impl Display for Local {
1253    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1254        // We display both the variable name and its id because some
1255        // variables may have the same name (in different scopes)
1256        if let Some(name) = &self.name {
1257            write!(f, "{name}")?
1258        }
1259        write!(f, "_{}", self.index)?;
1260        Ok(())
1261    }
1262}
1263
1264impl<C: AstFormatter> FmtWithCtx<C> for LocalId {
1265    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1266        ctx.format_local_id(f, *self)
1267    }
1268}
1269
1270impl Display for MetadataValue {
1271    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1272        let name = match self {
1273            MetadataValue::DynSize => "dyn_size",
1274            MetadataValue::DynAlign => "dyn_align",
1275            MetadataValue::SliceLength => "slice_length",
1276        };
1277        write!(f, "{name}")
1278    }
1279}
1280
1281impl<C: AstFormatter> FmtWithCtx<C> for Name {
1282    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1283        // Reset generics to avoid names being displayed differently depending on the current
1284        // binding level.
1285        let ctx = &ctx.no_generics();
1286        let name = self.name.iter().map(|x| x.with_ctx(ctx)).format("::");
1287        write!(f, "{}", name)
1288    }
1289}
1290
1291impl Name {
1292    /// Print the full name, which is different from printing a `Name` since that will use the
1293    /// short name for impls.
1294    fn full_name<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
1295        std::fmt::from_fn(move |f| {
1296            let ctx = &ctx.no_generics();
1297            let name = self
1298                .name
1299                .iter()
1300                .map(|elem| match elem {
1301                    PathElem::Impl(impl_elem) => Either::Left(impl_elem.with_ctx(ctx)),
1302                    _ => Either::Right(elem.with_ctx(ctx)),
1303                })
1304                .format("::");
1305            write!(f, "{name}")
1306        })
1307    }
1308}
1309
1310impl<C: AstFormatter> FmtWithCtx<C> for NullOp {
1311    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1312        let op = match self {
1313            NullOp::UbChecks => "ub_checks",
1314            NullOp::OverflowChecks => "overflow_checks",
1315            NullOp::ContractChecks => "contract_checks",
1316        };
1317        write!(f, "{op}")
1318    }
1319}
1320
1321impl_display_via_ctx!(Operand);
1322impl<C: AstFormatter> FmtWithCtx<C> for Operand {
1323    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1324        match self {
1325            Operand::Copy(p) => write!(f, "copy {}", p.with_ctx(ctx)),
1326            Operand::Move(p) => write!(f, "move {}", p.with_ctx(ctx)),
1327            Operand::Const(c) => write!(f, "const {}", c.with_ctx(ctx)),
1328        }
1329    }
1330}
1331
1332impl<C: AstFormatter> FmtWithCtx<C> for OffsetExpr {
1333    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1334        match self.chosen {
1335            Some(chosen) => write!(f, "{chosen}")?,
1336            None => write!(f, "?")?,
1337        }
1338        if let Some(guarantee) = &self.guarantee {
1339            write!(f, " (guaranteed: {})", guarantee.with_ctx(ctx))?;
1340        }
1341        Ok(())
1342    }
1343}
1344
1345impl<C: AstFormatter> FmtWithCtx<C> for OffsetGuarantee {
1346    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1347        match self {
1348            OffsetGuarantee::AtOffsetZero => write!(f, "zero"),
1349            OffsetGuarantee::GuaranteedAlignment(align) => {
1350                write!(f, "aligned({})", align.with_ctx(ctx))
1351            }
1352            OffsetGuarantee::ReprCField { predecessor } => match predecessor {
1353                Some(predecessor) => write!(f, "repr_c_after({predecessor})"),
1354                None => write!(f, "repr_c_after_tag"),
1355            },
1356        }
1357    }
1358}
1359
1360impl<C: AstFormatter, T, U> FmtWithCtx<C> for OutlivesPred<T, U>
1361where
1362    T: FmtWithCtx<C>,
1363    U: FmtWithCtx<C>,
1364{
1365    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1366        write!(f, "{}: {}", self.0.with_ctx(ctx), self.1.with_ctx(ctx))
1367    }
1368}
1369
1370impl<C: AstFormatter> FmtWithCtx<C> for PathElem {
1371    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1372        match self {
1373            PathElem::Ident(s, d) => {
1374                write!(f, "{s}")?;
1375                if !d.is_zero() {
1376                    write!(f, "#{}", d)?;
1377                }
1378                Ok(())
1379            }
1380            PathElem::Impl(impl_elem) => {
1381                if let ImplElem::Trait(impl_id) = impl_elem
1382                    && let Some(short_name) = trait_impl_short_name(ctx, *impl_id)
1383                {
1384                    return write!(f, "{}", short_name.with_ctx(ctx));
1385                }
1386                write!(f, "{}", impl_elem.with_ctx(ctx))
1387            }
1388            PathElem::Builtin(BuiltinPathElem::Tuple(n), _) => {
1389                let fields = std::iter::repeat_n("_", *n).format(", ");
1390                let trailing_comma = if *n == 1 { "," } else { "" };
1391                write!(f, "({fields}{trailing_comma})")
1392            }
1393            PathElem::Builtin(elem, d) => {
1394                if !elem.is_rust_name() {
1395                    write!(f, "{{")?;
1396                }
1397                write!(f, "{}", elem.ident())?;
1398                if !d.is_zero() {
1399                    write!(f, "#{d}")?;
1400                }
1401                if !elem.is_rust_name() {
1402                    write!(f, "}}")?;
1403                }
1404                Ok(())
1405            }
1406            PathElem::Instantiated(binder) => {
1407                // Anonymize all parameters.
1408                let underscore = "_".to_string();
1409                let params = GenericParams {
1410                    regions: binder.params.regions.map_ref(|x| RegionParam {
1411                        name: Some(underscore.clone()),
1412                        ..*x
1413                    }),
1414                    types: binder.params.types.map_ref(|x| TypeParam {
1415                        name: underscore.clone(),
1416                        ..*x
1417                    }),
1418                    const_generics: binder.params.const_generics.map_ref(|x| ConstGenericParam {
1419                        name: underscore.clone(),
1420                        ty: x.ty.clone(),
1421                        index: x.index,
1422                    }),
1423                    trait_clauses: binder.params.trait_clauses.clone(),
1424                    ..GenericParams::empty()
1425                };
1426                let ctx = &ctx.push_binder(Cow::Owned(params));
1427                write!(
1428                    f,
1429                    "<{}>",
1430                    binder.skip_binder.fmt_explicits(ctx).format(", ")
1431                )
1432            }
1433            PathElem::Target(target) => write!(f, "{target}"),
1434        }
1435    }
1436}
1437
1438impl_display_via_ctx!(Place);
1439impl<C: AstFormatter> FmtWithCtx<C> for Place {
1440    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1441        match &self.kind {
1442            PlaceKind::Local(var_id) => write!(f, "{}", var_id.with_ctx(ctx)),
1443            PlaceKind::Global(global_ref) => global_ref.fmt_with_ctx(ctx, f),
1444            PlaceKind::Projection(subplace, projection) => {
1445                let sub = subplace.with_ctx(ctx);
1446                match projection {
1447                    ProjectionElem::Deref => write!(f, "(*{sub})"),
1448                    ProjectionElem::Field(variant_id, field_id) => {
1449                        let tref = subplace.ty().as_adt().unwrap();
1450                        match variant_id {
1451                            None => write!(f, "{sub}.")?,
1452                            Some(variant_id) => {
1453                                write!(f, "({sub} as variant ")?;
1454                                ctx.format_enum_variant(f, tref.id, *variant_id)?;
1455                                write!(f, ").")?;
1456                            }
1457                        }
1458                        ctx.format_field_name(f, tref.id, *variant_id, *field_id)
1459                    }
1460                    ProjectionElem::PtrMetadata => write!(f, "{sub}.metadata"),
1461                    ProjectionElem::Index {
1462                        offset,
1463                        from_end: true,
1464                        ..
1465                    } => write!(f, "{sub}[-{}]", offset.with_ctx(ctx)),
1466                    ProjectionElem::Index {
1467                        offset,
1468                        from_end: false,
1469                        ..
1470                    } => write!(f, "{sub}[{}]", offset.with_ctx(ctx)),
1471                    ProjectionElem::Subslice {
1472                        from,
1473                        to,
1474                        from_end: true,
1475                        ..
1476                    } => write!(f, "{sub}[{}..-{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1477                    ProjectionElem::Subslice {
1478                        from,
1479                        to,
1480                        from_end: false,
1481                        ..
1482                    } => write!(f, "{sub}[{}..{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1483                }
1484            }
1485        }
1486    }
1487}
1488
1489impl<C: AstFormatter> FmtWithCtx<C> for PolyTraitDeclRef {
1490    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1491        write!(f, "{}", self.fmt_as_for(ctx))
1492    }
1493}
1494
1495impl PolyTraitDeclRef {
1496    fn fmt_trait_proof<'a, C: AstFormatter + 'a>(
1497        &'a self,
1498        id: TraitClauseId,
1499        value: Option<&'a TraitRef>,
1500        ctx: &'a C,
1501    ) -> impl Display + 'a {
1502        std::fmt::from_fn(move |f| {
1503            write!(
1504                f,
1505                "proof {}: {}",
1506                id.format_as_implied(),
1507                self.format_as_pred(ctx)
1508            )?;
1509            if let Some(value) = value {
1510                write!(f, " = {}", value.with_ctx(ctx))?;
1511            }
1512            Ok(())
1513        })
1514    }
1515
1516    fn format_as_pred<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
1517        std::fmt::from_fn(move |f| {
1518            let ctx = &ctx.push_bound_regions(&self.regions);
1519            if !self.regions.is_empty() {
1520                let regions = self.regions.iter().map(|r| r.with_ctx(ctx));
1521                write!(f, "for<{}> ", regions.format(", "))?;
1522            }
1523            write!(f, "({})", self.skip_binder.format_as_pred(ctx))
1524        })
1525    }
1526}
1527
1528impl<C: AstFormatter> FmtWithCtx<C> for Attribute {
1529    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1530        let mut attr = String::new();
1531        self.fmt_unindented(ctx, &mut attr)?;
1532        let sep = format!("\n{}", ctx.indent());
1533        write!(f, "{}", attr.lines().format(sep.as_str()))
1534    }
1535}
1536
1537impl Attribute {
1538    fn fmt_unindented<C: AstFormatter>(&self, ctx: &C, f: &mut impl fmt::Write) -> fmt::Result {
1539        match self {
1540            Attribute::Opaque => write!(f, "#[charon::opaque]"),
1541            Attribute::Exclude => write!(f, "#[charon::exclude]"),
1542            Attribute::Rename(name) => write!(f, "#[charon::rename(\"{name}\")]"),
1543            Attribute::VariantsPrefix(prefix) => {
1544                write!(f, "#[charon::variants_prefix(\"{prefix}\")]")
1545            }
1546            Attribute::VariantsSuffix(suffix) => {
1547                write!(f, "#[charon::variants_suffix(\"{suffix}\")]")
1548            }
1549            Attribute::Transparent => write!(f, "#[charon::transparent]"),
1550            Attribute::IsContract { kind, target } => {
1551                let target = target.with_ctx(ctx).to_string();
1552                write!(f, "#[charon::contract(kind = {kind:?}, for = {target:?})]")
1553            }
1554            Attribute::HasContract { kind, contract } => {
1555                let contract = ItemId::Fun(*contract);
1556                write!(
1557                    f,
1558                    "#[charon::has_contract(kind = {kind:?}, contract = {})]",
1559                    contract.with_ctx(ctx)
1560                )
1561            }
1562            Attribute::DocComment(comment) => {
1563                write!(
1564                    f,
1565                    "{}",
1566                    comment
1567                        .lines()
1568                        .map(|line| format!("///{line}"))
1569                        .format("\n")
1570                )
1571            }
1572            Attribute::Builtin(kind) => write!(f, "#[{kind}]"),
1573            Attribute::Unknown(attr) => write!(f, "#[{attr}]"),
1574        }
1575    }
1576}
1577
1578/// Print a built-in attribute the way it is written in the source.
1579impl Display for from_rustc::AttributeKind {
1580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1581        use from_rustc::AttributeKind;
1582        match self {
1583            AttributeKind::AutomaticallyDerived => write!(f, "automatically_derived"),
1584            AttributeKind::Cold => write!(f, "cold"),
1585            AttributeKind::Deprecated { deprecation, .. } => {
1586                write!(f, "deprecated")?;
1587                let since = match &deprecation.since {
1588                    from_rustc::DeprecatedSince::RustcVersion(v) => {
1589                        Some(format!("{}.{}.{}", v.major, v.minor, v.patch))
1590                    }
1591                    from_rustc::DeprecatedSince::Future => Some("future".to_owned()),
1592                    from_rustc::DeprecatedSince::NonStandard(since) => Some(since.to_string()),
1593                    from_rustc::DeprecatedSince::Unspecified | from_rustc::DeprecatedSince::Err => {
1594                        None
1595                    }
1596                };
1597                let since = since.map(|since| format!("since = \"{since}\""));
1598                let note = deprecation
1599                    .note
1600                    .as_ref()
1601                    .map(|note| format!("note = \"{}\"", note.name));
1602                let args = since.into_iter().chain(note).format(", ").to_string();
1603                if !args.is_empty() {
1604                    write!(f, "({args})")?;
1605                }
1606                Ok(())
1607            }
1608            AttributeKind::Fundamental => write!(f, "fundamental"),
1609            AttributeKind::Ignore { reason, .. } => {
1610                write!(f, "ignore")?;
1611                if let Some(reason) = reason {
1612                    write!(f, " = \"{reason}\"")?;
1613                }
1614                Ok(())
1615            }
1616            AttributeKind::Inline(inline, _) => match inline {
1617                from_rustc::InlineAttr::None => write!(f, "inline"),
1618                from_rustc::InlineAttr::Hint => write!(f, "inline(hint)"),
1619                from_rustc::InlineAttr::Always => write!(f, "inline(always)"),
1620                from_rustc::InlineAttr::Never => write!(f, "inline(never)"),
1621                from_rustc::InlineAttr::Force { .. } => write!(f, "rustc_force_inline"),
1622            },
1623            AttributeKind::MayDangle(_) => write!(f, "may_dangle"),
1624            AttributeKind::Naked(_) => write!(f, "naked"),
1625            AttributeKind::NoLink => write!(f, "no_link"),
1626            AttributeKind::NoMangle(_) => write!(f, "no_mangle"),
1627            AttributeKind::NonExhaustive(_) => write!(f, "non_exhaustive"),
1628            AttributeKind::Optimize(optimize, _) => match optimize {
1629                from_rustc::OptimizeAttr::Default => write!(f, "optimize(default)"),
1630                from_rustc::OptimizeAttr::DoNotOptimize => write!(f, "optimize(none)"),
1631                from_rustc::OptimizeAttr::Speed => write!(f, "optimize(speed)"),
1632                from_rustc::OptimizeAttr::Size => write!(f, "optimize(size)"),
1633            },
1634            AttributeKind::RustcAlign { align, .. } => write!(f, "rustc_align({align})"),
1635            AttributeKind::RustcIntrinsic => write!(f, "rustc_intrinsic"),
1636            AttributeKind::RustcTestEntrypointMarker => write!(f, "rustc_test_entrypoint_marker"),
1637            AttributeKind::ShouldPanic { reason } => {
1638                write!(f, "should_panic")?;
1639                if let Some(reason) = reason {
1640                    write!(f, "(expected = \"{reason}\")")?;
1641                }
1642                Ok(())
1643            }
1644            AttributeKind::TargetFeature { features, .. } => {
1645                let features = features.iter().map(|(feature, _)| feature).format(",");
1646                write!(f, "target_feature(enable = \"{features}\")")
1647            }
1648            AttributeKind::TrackCaller(_) => write!(f, "track_caller"),
1649        }
1650    }
1651}
1652
1653impl Display for RawAttribute {
1654    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1655        write!(f, "{}", self.path)?;
1656        if let Some(args) = &self.args {
1657            write!(f, "({args})")?;
1658        }
1659        Ok(())
1660    }
1661}
1662
1663impl<C: AstFormatter> FmtWithCtx<C> for Byte {
1664    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1665        match self {
1666            Byte::Value(x) => write!(f, "{:#04x}", x),
1667            Byte::Uninit => write!(f, "--"),
1668            Byte::Provenance(p, ofs) => write!(f, "{}[{}]", p.with_ctx(ctx), ofs),
1669        }
1670    }
1671}
1672
1673impl<C: AstFormatter> FmtWithCtx<C> for Provenance {
1674    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1675        match self {
1676            Provenance::Global(g) => write!(f, "&{}", g.with_ctx(ctx)),
1677            Provenance::Function(func) => write!(f, "&{}", func.with_ctx(ctx)),
1678            Provenance::Unknown => write!(f, "&?"),
1679        }
1680    }
1681}
1682
1683impl ConstantExpr {
1684    fn format_as_match_pattern<'a, C: AstFormatter + 'a>(
1685        &'a self,
1686        ctx: &'a C,
1687    ) -> impl Display + 'a {
1688        std::fmt::from_fn(move |f| match self.kind() {
1689            ConstantExprKind::Discriminant(type_ref, variant_id) => {
1690                ctx.format_enum_variant(f, type_ref.id, *variant_id)
1691            }
1692            _ => self.fmt_with_ctx(ctx, f),
1693        })
1694    }
1695}
1696
1697impl_display_via_ctx!(ConstantExpr);
1698impl<C: AstFormatter> FmtWithCtx<C> for ConstantExpr {
1699    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1700        match self.kind() {
1701            ConstantExprKind::Integer(v) => write!(f, "{v}"),
1702            ConstantExprKind::Float(v) => write!(f, "{v}"),
1703            ConstantExprKind::Bool(v) => write!(f, "{v}"),
1704            ConstantExprKind::Char(v) => write!(f, "'{}'", v.escape_debug()),
1705            ConstantExprKind::Str(v) => {
1706                write!(f, "\"{}\"", v.replace("\\", "\\\\").replace("\n", "\\n"))
1707            }
1708            ConstantExprKind::ByteStr(v) => write!(f, "{v:?}"),
1709            ConstantExprKind::Adt(variant_id, values) => {
1710                let values = values.iter().map(|v| v.with_ctx(ctx));
1711                let ty_ref = self.ty().as_adt().unwrap();
1712                if ty_ref.is_tuple() {
1713                    let trailing_comma = if values.len() == 1 { "," } else { "" };
1714                    let values = values.format(", ");
1715                    write!(f, "({values}{trailing_comma})")
1716                } else {
1717                    match variant_id {
1718                        None => ty_ref.id.fmt_with_ctx(ctx, f)?,
1719                        Some(variant_id) => ctx.format_enum_variant(f, ty_ref.id, *variant_id)?,
1720                    }
1721                    write!(f, " {{ ")?;
1722                    for (comma, (i, val)) in repeat_except_first(", ").zip(values.enumerate()) {
1723                        write!(f, "{}", comma.unwrap_or_default())?;
1724                        let field_id = FieldId::new(i);
1725                        ctx.format_field_name(f, ty_ref.id, *variant_id, field_id)?;
1726                        write!(f, ": {}", val)?;
1727                    }
1728                    write!(f, " }}")
1729                }
1730            }
1731            ConstantExprKind::Array(values) => {
1732                let values = values.iter().map(|v| v.with_ctx(ctx)).format(", ");
1733                write!(f, "[{}]", values)
1734            }
1735            ConstantExprKind::Global(global_ref) => {
1736                write!(f, "{}", global_ref.with_ctx(ctx))
1737            }
1738            ConstantExprKind::TraitConst(trait_ref, const_id) => {
1739                write!(f, "{}::", trait_ref.with_ctx(ctx),)?;
1740                ctx.format_assoc_const_name(f, trait_ref.trait_id(), *const_id)?;
1741                Ok(())
1742            }
1743            ConstantExprKind::VTableRef(trait_ref) => {
1744                write!(f, "&vtable_of({})", trait_ref.with_ctx(ctx),)
1745            }
1746            ConstantExprKind::Discriminant(type_ref, variant_id) => {
1747                write!(f, "discriminant_of(")?;
1748                ctx.format_enum_variant(f, type_ref.id, *variant_id)?;
1749                write!(f, ")")
1750            }
1751            ConstantExprKind::Ref(cv, meta) => {
1752                if let Some(meta) = meta {
1753                    write!(
1754                        f,
1755                        "&{} with_metadata({})",
1756                        cv.with_ctx(ctx),
1757                        meta.with_ctx(ctx)
1758                    )
1759                } else {
1760                    write!(f, "&{}", cv.with_ctx(ctx))
1761                }
1762            }
1763            ConstantExprKind::Ptr(rk, cv, meta) => {
1764                let rk = match rk {
1765                    RefKind::Mut => "&raw mut",
1766                    RefKind::Shared => "&raw const",
1767                };
1768                if let Some(meta) = meta {
1769                    write!(
1770                        f,
1771                        "{} {} with_metadata({})",
1772                        rk,
1773                        cv.with_ctx(ctx),
1774                        meta.with_ctx(ctx)
1775                    )
1776                } else {
1777                    write!(f, "{} {}", rk, cv.with_ctx(ctx))
1778                }
1779            }
1780            ConstantExprKind::Var(id) => write!(f, "{}", id.with_ctx(ctx)),
1781            ConstantExprKind::Call(fp, args) => {
1782                let args = args.iter().map(|arg| arg.with_ctx(ctx)).format(", ");
1783                write!(f, "{}({args})", fp.with_ctx(ctx))
1784            }
1785            ConstantExprKind::FnDef(fp) => {
1786                write!(f, "{}", fp.with_ctx(ctx))
1787            }
1788            ConstantExprKind::FnPtr(fp) => {
1789                write!(f, "fnptr({})", fp.with_ctx(ctx))
1790            }
1791            ConstantExprKind::TypeId(ty) => {
1792                write!(f, "TypeId({})", ty.with_ctx(ctx))
1793            }
1794            ConstantExprKind::SizeOf(ty) => {
1795                write!(f, "size_of::<{}>()", ty.with_ctx(ctx))
1796            }
1797            ConstantExprKind::AlignOf(ty) => {
1798                write!(f, "align_of::<{}>()", ty.with_ctx(ctx))
1799            }
1800            &ConstantExprKind::OffsetOf(ref ty, variant, field) => {
1801                write!(f, "offset_of({}.", ty.with_ctx(ctx))?;
1802                if let Some(variant) = variant {
1803                    ctx.format_enum_variant_name(f, ty.id, variant)?;
1804                    write!(f, ".")?;
1805                }
1806                ctx.format_field_name(f, ty.id, variant, field)?;
1807                write!(f, ")")
1808            }
1809            ConstantExprKind::PtrNoProvenance(v) => write!(f, "no-provenance {v}"),
1810            ConstantExprKind::RawMemory(bytes) => {
1811                let bytes = bytes.iter().map(|v| v.with_ctx(ctx)).format(", ");
1812                write!(f, "RawMemory({})", bytes)
1813            }
1814            ConstantExprKind::Opaque(cause) => write!(f, "Opaque({cause})"),
1815        }
1816    }
1817}
1818
1819impl Display for ReprOptions {
1820    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1821        let algorithm = match self.repr_algo {
1822            ReprAlgorithm::Rust => "Rust",
1823            ReprAlgorithm::C => "C",
1824        };
1825        write!(f, "repr({algorithm}")?;
1826        if let Some(modifier) = &self.align_modif {
1827            match modifier {
1828                AlignmentModifier::Align(align) => write!(f, ", align({align})")?,
1829                AlignmentModifier::Pack(pack) => write!(f, ", packed({pack})")?,
1830            }
1831        }
1832        if self.transparent {
1833            write!(f, ", transparent")?;
1834        }
1835        if let Some(int_ty) = self.explicit_discr_type {
1836            write!(f, ", discriminant {int_ty}")?;
1837        }
1838        write!(f, ")")
1839    }
1840}
1841
1842impl<C: AstFormatter> FmtWithCtx<C> for Size {
1843    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1844        match &self.chosen {
1845            Some(chosen) => write!(f, "{}", chosen.with_ctx(ctx))?,
1846            None => write!(f, "?")?,
1847        }
1848        if let Some(guarantee) = &self.guarantee {
1849            write!(f, " (guaranteed: {})", guarantee.with_ctx(ctx))?;
1850        }
1851        Ok(())
1852    }
1853}
1854
1855impl_display_via_ctx!(SizeExpr);
1856impl<C: AstFormatter> FmtWithCtx<C> for SizeExpr {
1857    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1858        match self.kind() {
1859            SizeExprKind::Constant(constant) => write!(f, "{}", constant.with_ctx(ctx)),
1860            SizeExprKind::FromMetadata(metadata) => write!(f, "{metadata}"),
1861            SizeExprKind::Max(values) => write!(
1862                f,
1863                "max({})",
1864                values.iter().map(|value| value.with_ctx(ctx)).format(", ")
1865            ),
1866            SizeExprKind::Min(values) => write!(
1867                f,
1868                "min({})",
1869                values.iter().map(|value| value.with_ctx(ctx)).format(", ")
1870            ),
1871            SizeExprKind::Plus(left, right) => {
1872                write!(f, "({} + {})", left.with_ctx(ctx), right.with_ctx(ctx))
1873            }
1874            SizeExprKind::Scale(base, multiplier) => {
1875                write!(f, "({} * {})", base.with_ctx(ctx), multiplier.with_ctx(ctx))
1876            }
1877            SizeExprKind::AtLeast(value) => write!(f, "at_least({})", value.with_ctx(ctx)),
1878            SizeExprKind::AlignTo { base, target_align } => write!(
1879                f,
1880                "align_to({}, {})",
1881                base.with_ctx(ctx),
1882                target_align.with_ctx(ctx)
1883            ),
1884            SizeExprKind::IfInhabited {
1885                ty,
1886                then_size,
1887                else_size,
1888            } => write!(
1889                f,
1890                "if_inhabited({}, {}, {})",
1891                ty.with_ctx(ctx),
1892                then_size.with_ctx(ctx),
1893                else_size.with_ctx(ctx)
1894            ),
1895        }
1896    }
1897}
1898
1899impl<C: AstFormatter> FmtWithCtx<C> for Region {
1900    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1901        match self {
1902            Region::Static => write!(f, "'static"),
1903            Region::Var(var) => write!(f, "{}", var.with_ctx(ctx)),
1904            Region::Body(id) => write!(f, "'{}", id),
1905            Region::Erased => write!(f, "'_"),
1906        }
1907    }
1908}
1909
1910impl<T> RegionBinder<T> {
1911    /// Format the parameters and contents of this binder and returns the resulting strings.
1912    fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
1913    where
1914        C: AstFormatter,
1915        T: FmtWithCtx<C::Reborrow<'a>>,
1916    {
1917        self.fmt_split_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
1918    }
1919    /// Format the parameters and contents of this binder and returns the resulting strings.
1920    fn fmt_split_with<'a, C>(
1921        &'a self,
1922        ctx: &'a C,
1923        fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
1924    ) -> (String, String)
1925    where
1926        C: AstFormatter,
1927    {
1928        let ctx = &ctx.push_bound_regions(&self.regions);
1929        (
1930            self.regions
1931                .iter()
1932                .map(|r| r.with_ctx(ctx))
1933                .format(", ")
1934                .to_string(),
1935            fmt_inner(ctx, &self.skip_binder),
1936        )
1937    }
1938
1939    /// Formats the binder as `for<params> value`.
1940    fn fmt_as_for<'a, C>(&'a self, ctx: &'a C) -> String
1941    where
1942        C: AstFormatter,
1943        T: FmtWithCtx<C::Reborrow<'a>>,
1944    {
1945        self.fmt_as_for_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
1946    }
1947    /// Formats the binder as `for<params> value`.
1948    fn fmt_as_for_with<'a, C>(
1949        &'a self,
1950        ctx: &'a C,
1951        fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
1952    ) -> String
1953    where
1954        C: AstFormatter,
1955        T: FmtWithCtx<C::Reborrow<'a>>,
1956    {
1957        let (regions, value) = self.fmt_split_with(ctx, fmt_inner);
1958        let regions = if regions.is_empty() {
1959            "".to_string()
1960        } else {
1961            format!("for<{regions}> ",)
1962        };
1963        format!("{regions}{value}",)
1964    }
1965}
1966
1967impl<C: AstFormatter> FmtWithCtx<C> for RegionDbVar {
1968    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1969        ctx.format_bound_var(f, *self, "'_", |v| {
1970            v.name.as_ref().map(|name| name.to_string())
1971        })
1972    }
1973}
1974
1975impl<C: AstFormatter> FmtWithCtx<C> for RegionParam {
1976    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1977        if self.mutability.is_mutable() {
1978            write!(f, "mut ")?;
1979        }
1980        match &self.name {
1981            Some(name) => write!(f, "{name}"),
1982            None => {
1983                write!(f, "'_{}", self.index)?;
1984                if let Some(d @ 1..) = ctx.binder_depth().checked_sub(1) {
1985                    write!(f, "_{d}")?;
1986                }
1987                Ok(())
1988            }
1989        }
1990    }
1991}
1992
1993impl_display_via_ctx!(Rvalue);
1994impl<C: AstFormatter> FmtWithCtx<C> for Rvalue {
1995    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1996        match self {
1997            Rvalue::Use(x, _) => write!(f, "{}", x.with_ctx(ctx)),
1998            Rvalue::Ref {
1999                place,
2000                kind: borrow_kind,
2001                ptr_metadata,
2002            } => {
2003                let borrow_kind = match borrow_kind {
2004                    BorrowKind::Shared => "&",
2005                    BorrowKind::Mut => "&mut ",
2006                    BorrowKind::TwoPhaseMut => "&two-phase-mut ",
2007                    BorrowKind::UniqueImmutable => "&uniq ",
2008                    BorrowKind::Shallow => "&shallow ",
2009                };
2010                if ptr_metadata.ty().is_unit() {
2011                    // Hide unit metadata
2012                    write!(f, "{borrow_kind}{}", place.with_ctx(ctx))?;
2013                } else {
2014                    write!(
2015                        f,
2016                        "{borrow_kind}{} with_metadata({})",
2017                        place.with_ctx(ctx),
2018                        ptr_metadata.with_ctx(ctx)
2019                    )?;
2020                }
2021                Ok(())
2022            }
2023            Rvalue::RawPtr {
2024                place,
2025                kind: mutability,
2026                ptr_metadata,
2027            } => {
2028                let ptr_kind = match mutability {
2029                    RefKind::Shared => "&raw const ",
2030                    RefKind::Mut => "&raw mut ",
2031                };
2032                if ptr_metadata.ty().is_unit() {
2033                    // Hide unit metadata
2034                    write!(f, "{ptr_kind}{}", place.with_ctx(ctx))?;
2035                } else {
2036                    write!(
2037                        f,
2038                        "{ptr_kind}{} with_metadata({})",
2039                        place.with_ctx(ctx),
2040                        ptr_metadata.with_ctx(ctx)
2041                    )?;
2042                }
2043                Ok(())
2044            }
2045
2046            Rvalue::BinaryOp(binop, x, y) => {
2047                write!(f, "{} {} {}", x.with_ctx(ctx), binop, y.with_ctx(ctx))
2048            }
2049            Rvalue::UnaryOp(unop, x) => {
2050                write!(f, "{}({})", unop.with_ctx(ctx), x.with_ctx(ctx))
2051            }
2052            Rvalue::NullaryOp(op) => op.fmt_with_ctx(ctx, f),
2053            Rvalue::Discriminant(p) => {
2054                write!(f, "@discriminant({})", p.with_ctx(ctx),)
2055            }
2056            Rvalue::Aggregate(kind, ops) => {
2057                let ops_s = ops.iter().map(|op| op.with_ctx(ctx)).format(", ");
2058                match kind {
2059                    AggregateKind::Adt(ty_ref, variant_id, field_id) => {
2060                        if ty_ref.is_tuple() {
2061                            let trailing_comma = if ops.len() == 1 { "," } else { "" };
2062                            write!(f, "({ops_s}{trailing_comma})")
2063                        } else {
2064                            match variant_id {
2065                                None => ty_ref.id.fmt_with_ctx(ctx, f)?,
2066                                Some(variant_id) => {
2067                                    ctx.format_enum_variant(f, ty_ref.id, *variant_id)?
2068                                }
2069                            }
2070                            write!(f, " {{ ")?;
2071                            for (comma, (i, op)) in
2072                                repeat_except_first(", ").zip(ops.iter().enumerate())
2073                            {
2074                                write!(f, "{}", comma.unwrap_or_default())?;
2075                                let field_id = match *field_id {
2076                                    None => FieldId::new(i),
2077                                    Some(field_id) => {
2078                                        assert_eq!(i, 0); // there should be only one operand
2079                                        field_id
2080                                    }
2081                                };
2082                                ctx.format_field_name(f, ty_ref.id, *variant_id, field_id)?;
2083                                write!(f, ": {}", op.with_ctx(ctx))?;
2084                            }
2085                            write!(f, " }}")
2086                        }
2087                    }
2088                    AggregateKind::Array(..) => {
2089                        write!(f, "[{}]", ops_s)
2090                    }
2091                    AggregateKind::RawPtr(_, rmut) => {
2092                        let mutability = match rmut {
2093                            RefKind::Shared => "const",
2094                            RefKind::Mut => "mut ",
2095                        };
2096                        write!(f, "*{} ({})", mutability, ops_s)
2097                    }
2098                }
2099            }
2100            Rvalue::Len(place, ..) => write!(f, "len({})", place.with_ctx(ctx)),
2101            Rvalue::Repeat(operand, _, len, _) => {
2102                write!(f, "[{}; {}]", operand.with_ctx(ctx), len.with_ctx(ctx))
2103            }
2104        }
2105    }
2106}
2107
2108impl Display for IntegerValue {
2109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
2110        match self {
2111            IntegerValue::Signed(ty, v) => write!(f, "{v}{ty}"),
2112            IntegerValue::Unsigned(ty, v) => write!(f, "{v}{ty}"),
2113        }
2114    }
2115}
2116
2117impl<C: AstFormatter> FmtWithCtx<C> for BorrowckStatement {
2118    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2119        match self {
2120            BorrowckStatement::FakeRead(place) => {
2121                write!(f, "fake_read({})", place.with_ctx(ctx))
2122            }
2123            BorrowckStatement::SetType {
2124                place,
2125                ty,
2126                variance,
2127            } => {
2128                let relation = match variance {
2129                    Variance::Covariant => "<=",
2130                    Variance::Contravariant => ">=",
2131                    Variance::Invariant => "==",
2132                    Variance::Bivariant => panic!("bivariant SetType statement"),
2133                    Variance::Unknown => panic!("SetType statement with unknown variance"),
2134                };
2135                write!(
2136                    f,
2137                    "set_type(typeof({}) {relation} {})",
2138                    place.with_ctx(ctx),
2139                    ty.with_ctx(ctx)
2140                )
2141            }
2142            BorrowckStatement::SetOutlives(ty, region) => write!(
2143                f,
2144                "set_outlives({}, {})",
2145                ty.with_ctx(ctx),
2146                region.with_ctx(ctx)
2147            ),
2148            BorrowckStatement::PredicateHolds(predicate) => {
2149                write!(f, "predicate_holds({})", predicate.with_ctx(ctx))
2150            }
2151        }
2152    }
2153}
2154
2155impl<C: AstFormatter> FmtWithCtx<C> for ullbc::Statement {
2156    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2157        let tab = ctx.indent();
2158        use ullbc::StatementKind;
2159        if ctx.hide_storage_statements()
2160            && (self.kind.is_storage_live() || self.kind.is_storage_dead())
2161        {
2162            return Ok(());
2163        }
2164        for line in &self.comments_before {
2165            writeln!(f, "{tab}// {line}")?;
2166        }
2167        match &self.kind {
2168            StatementKind::Assign(place, rvalue) => {
2169                write!(f, "{tab}{} = {}", place.with_ctx(ctx), rvalue.with_ctx(ctx),)
2170            }
2171            StatementKind::Borrowck(statement) => {
2172                write!(f, "{tab}{}", statement.with_ctx(ctx))
2173            }
2174            StatementKind::SetDiscriminant(place, variant_id) => write!(
2175                f,
2176                "{tab}@discriminant({}) = {}",
2177                place.with_ctx(ctx),
2178                variant_id
2179            ),
2180            StatementKind::StorageLive(var_id) => {
2181                write!(f, "{tab}storage_live({})", var_id.with_ctx(ctx))
2182            }
2183            StatementKind::StorageDead(var_id) => {
2184                write!(f, "{tab}storage_dead({})", var_id.with_ctx(ctx))
2185            }
2186            StatementKind::PlaceMention(place) => {
2187                write!(f, "{tab}_ = {}", place.with_ctx(ctx))
2188            }
2189            StatementKind::Assert { assert, on_failure } => {
2190                write!(
2191                    f,
2192                    "{tab}{} else {}",
2193                    assert.with_ctx(ctx),
2194                    on_failure.with_ctx(ctx)
2195                )
2196            }
2197            StatementKind::Nop => write!(f, "{tab}nop"),
2198        }?;
2199        writeln!(f, ";")
2200    }
2201}
2202
2203impl<C: AstFormatter> FmtWithCtx<C> for llbc::Statement {
2204    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2205        let tab = ctx.indent();
2206        use llbc::StatementKind;
2207        if ctx.hide_storage_statements()
2208            && (self.kind.is_storage_live() || self.kind.is_storage_dead())
2209        {
2210            return Ok(());
2211        }
2212        for line in &self.comments_before {
2213            writeln!(f, "{tab}// {line}")?;
2214        }
2215        if self.kind.is_nop() {
2216            return Ok(());
2217        }
2218        write!(f, "{tab}")?;
2219        match &self.kind {
2220            StatementKind::Assign(place, rvalue) => {
2221                write!(f, "{} = {}", place.with_ctx(ctx), rvalue.with_ctx(ctx),)
2222            }
2223            StatementKind::Borrowck(statement) => write!(f, "{}", statement.with_ctx(ctx)),
2224            StatementKind::SetDiscriminant(place, variant_id) => {
2225                write!(f, "@discriminant({}) = {}", place.with_ctx(ctx), variant_id)
2226            }
2227            StatementKind::StorageLive(var_id) => {
2228                write!(f, "storage_live({})", var_id.with_ctx(ctx))
2229            }
2230            StatementKind::StorageDead(var_id) => {
2231                write!(f, "storage_dead({})", var_id.with_ctx(ctx))
2232            }
2233            StatementKind::PlaceMention(place) => {
2234                write!(f, "_ = {}", place.with_ctx(ctx))
2235            }
2236            StatementKind::Drop {
2237                place,
2238                fn_ptr,
2239                kind,
2240                on_unwind,
2241            } => {
2242                let kind = match kind {
2243                    DropKind::Precise => "drop",
2244                    DropKind::Conditional => "conditional_drop",
2245                };
2246                write!(
2247                    f,
2248                    "{kind}[{}] {}",
2249                    fn_ptr.with_ctx(ctx),
2250                    place.with_ctx(ctx),
2251                )?;
2252                fmt_llbc_unwind_block(ctx, f, on_unwind)
2253            }
2254            StatementKind::Assert {
2255                assert,
2256                on_failure,
2257                on_unwind,
2258            } => {
2259                write!(
2260                    f,
2261                    "{} else {}",
2262                    assert.with_ctx(ctx),
2263                    on_failure.with_ctx(ctx)
2264                )?;
2265                fmt_llbc_unwind_block(ctx, f, on_unwind)
2266            }
2267            StatementKind::InlineAsm {
2268                asm,
2269                targets,
2270                on_unwind,
2271            } => {
2272                write!(f, "asm!({asm:?})")?;
2273                if !targets.is_empty() {
2274                    write!(f, " {{")?;
2275                    let ctx1 = &ctx.increase_indent();
2276                    for (i, target) in targets.iter().enumerate() {
2277                        let tab = ctx1.indent();
2278                        let ctx = &ctx1.increase_indent();
2279                        write!(
2280                            f,
2281                            "\n{tab}target {i} => {{\n{}{tab}}}",
2282                            target.with_ctx(ctx)
2283                        )?;
2284                    }
2285                    write!(f, "\n{tab}}}")?;
2286                }
2287                fmt_llbc_unwind_block(ctx, f, on_unwind)?;
2288                Ok(())
2289            }
2290            StatementKind::Call { call, on_unwind } => {
2291                write!(f, "{}", call.with_ctx(ctx))?;
2292                fmt_llbc_unwind_block(ctx, f, on_unwind)
2293            }
2294            StatementKind::Abort(kind) => {
2295                write!(f, "{}", kind.with_ctx(ctx))
2296            }
2297            StatementKind::Return => write!(f, "return"),
2298            StatementKind::UnwindResume => write!(f, "unwind_continue"),
2299            StatementKind::Break(index) => write!(f, "break {index}"),
2300            StatementKind::Continue(index) => write!(f, "continue {index}"),
2301            StatementKind::Switch { data, branches } => match &data.scrutinee {
2302                SwitchScrutinee::Value(discr)
2303                    if let Some((then_branch, else_branch)) = data.as_if() =>
2304                {
2305                    let true_st = &branches[then_branch];
2306                    let false_st = &branches[else_branch];
2307                    let ctx = &ctx.increase_indent();
2308                    write!(
2309                        f,
2310                        "if {} {{\n{}{tab}}} else {{\n{}{tab}}}",
2311                        discr.with_ctx(ctx),
2312                        true_st.with_ctx(ctx),
2313                        false_st.with_ctx(ctx),
2314                    )
2315                }
2316                SwitchScrutinee::Value(discr) => {
2317                    writeln!(f, "switch {} {{", discr.with_ctx(ctx))?;
2318                    let ctx1 = &ctx.increase_indent();
2319                    let inner_tab1 = ctx1.indent();
2320                    let ctx2 = &ctx1.increase_indent();
2321                    let cases_by_branch = data.group_by_branch();
2322                    for (branch_id, st) in branches.iter_enumerated() {
2323                        let cases = &cases_by_branch[branch_id];
2324                        let cases = if cases.is_empty() && data.fallback != Some(branch_id) {
2325                            "_".to_owned()
2326                        } else {
2327                            cases
2328                                .iter()
2329                                .map(|value| value.to_string_with_ctx(ctx))
2330                                .chain((data.fallback == Some(branch_id)).then_some("_".to_owned()))
2331                                .format(" | ")
2332                                .to_string()
2333                        };
2334                        writeln!(
2335                            f,
2336                            "{inner_tab1}{} => {{\n{}{inner_tab1}}},",
2337                            cases,
2338                            st.with_ctx(ctx2),
2339                        )?;
2340                    }
2341                    write!(f, "{tab}}}")
2342                }
2343                SwitchScrutinee::Discriminant(discr) => {
2344                    writeln!(f, "match {} {{", discr.with_ctx(ctx))?;
2345                    let ctx1 = &ctx.increase_indent();
2346                    let inner_tab1 = ctx1.indent();
2347                    let ctx2 = &ctx1.increase_indent();
2348                    let cases_by_branch = data.group_by_branch();
2349                    for (branch_id, st) in branches.iter_enumerated() {
2350                        let cases = &cases_by_branch[branch_id];
2351                        let cases = if cases.is_empty() && data.fallback != Some(branch_id) {
2352                            "_".to_owned()
2353                        } else {
2354                            cases
2355                                .iter()
2356                                .map(|value| value.format_as_match_pattern(ctx).to_string())
2357                                .chain((data.fallback == Some(branch_id)).then_some("_".to_owned()))
2358                                .format(" | ")
2359                                .to_string()
2360                        };
2361                        writeln!(
2362                            f,
2363                            "{inner_tab1}{cases} => {{\n{}{inner_tab1}}},",
2364                            st.with_ctx(ctx2),
2365                        )?;
2366                    }
2367                    write!(f, "{tab}}}")
2368                }
2369            },
2370            StatementKind::Loop(body) => {
2371                let ctx = &ctx.increase_indent();
2372                write!(f, "loop {{\n{}{tab}}}", body.with_ctx(ctx))
2373            }
2374            StatementKind::Error(s) => write!(f, "@ERROR({})", s),
2375            StatementKind::Nop => unreachable!(),
2376        }?;
2377        writeln!(f)
2378    }
2379}
2380
2381impl<C: AstFormatter> FmtWithCtx<C> for SwitchScrutinee {
2382    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2383        match self {
2384            SwitchScrutinee::Value(operand) => operand.fmt_with_ctx(ctx, f),
2385            SwitchScrutinee::Discriminant(place) => place.fmt_with_ctx(ctx, f),
2386        }
2387    }
2388}
2389
2390impl<C: AstFormatter> FmtWithCtx<C> for Terminator {
2391    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2392        let tab = ctx.indent();
2393        for line in &self.comments_before {
2394            writeln!(f, "{tab}// {line}")?;
2395        }
2396        write!(f, "{tab}")?;
2397        match &self.kind {
2398            TerminatorKind::Goto { target } => write!(f, "goto bb{target}"),
2399            TerminatorKind::Switch { data, branches } => {
2400                if let Some((then_branch, else_branch)) = data.as_if() {
2401                    let true_block = branches[then_branch];
2402                    let false_block = branches[else_branch];
2403                    write!(
2404                        f,
2405                        "if {} -> bb{} else -> bb{}",
2406                        data.scrutinee.with_ctx(ctx),
2407                        true_block,
2408                        false_block
2409                    )
2410                } else {
2411                    let maps = data
2412                        .branches
2413                        .iter()
2414                        .map(|(value, branch_id)| {
2415                            format!(
2416                                "{}: bb{}",
2417                                value.format_as_match_pattern(ctx),
2418                                branches[*branch_id]
2419                            )
2420                        })
2421                        .chain(
2422                            data.fallback
2423                                .map(|branch_id| format!("otherwise: bb{}", branches[branch_id])),
2424                        )
2425                        .format(", ");
2426                    match &data.scrutinee {
2427                        SwitchScrutinee::Value(discr) => {
2428                            write!(f, "switch {} -> {}", discr.with_ctx(ctx), maps)
2429                        }
2430                        SwitchScrutinee::Discriminant(place) => {
2431                            write!(f, "match {} -> {}", place.with_ctx(ctx), maps)
2432                        }
2433                    }
2434                }
2435            }
2436            TerminatorKind::Call {
2437                call,
2438                target,
2439                on_unwind,
2440            } => {
2441                let call = call.with_ctx(ctx);
2442                write!(f, "{call} -> bb{target} (unwind: bb{on_unwind})",)
2443            }
2444            TerminatorKind::Drop {
2445                kind,
2446                place,
2447                fn_ptr,
2448                target,
2449                on_unwind,
2450            } => {
2451                let kind = match kind {
2452                    DropKind::Precise => "drop",
2453                    DropKind::Conditional => "conditional_drop",
2454                };
2455                write!(
2456                    f,
2457                    "{kind}[{}] {} -> bb{target} (unwind: bb{on_unwind})",
2458                    fn_ptr.with_ctx(ctx),
2459                    place.with_ctx(ctx),
2460                )
2461            }
2462            TerminatorKind::Assert {
2463                assert,
2464                target,
2465                on_unwind,
2466            } => {
2467                write!(
2468                    f,
2469                    "assert {} -> bb{target} (unwind: bb{on_unwind})",
2470                    assert.with_ctx(ctx),
2471                )
2472            }
2473            TerminatorKind::InlineAsm {
2474                asm,
2475                targets,
2476                on_unwind,
2477            } => {
2478                let targets = targets
2479                    .iter()
2480                    .enumerate()
2481                    .map(|(i, target)| format!("target {i}: bb{target}"))
2482                    .chain([format!("unwind: bb{on_unwind}")])
2483                    .format(", ");
2484                write!(f, "asm!({asm:?}) -> {targets}")
2485            }
2486            TerminatorKind::Abort(kind) => write!(f, "{}", kind.with_ctx(ctx)),
2487            TerminatorKind::Return => write!(f, "return"),
2488            TerminatorKind::UnwindResume => write!(f, "unwind_continue"),
2489        }
2490    }
2491}
2492
2493impl<C: AstFormatter> FmtWithCtx<C> for TraitParam {
2494    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2495        write!(f, "{}", self.clause_id.format_as_required())?;
2496        if let Some(d @ 1..) = ctx.binder_depth().checked_sub(1) {
2497            write!(f, "_{d}")?;
2498        }
2499        write!(f, ": {}", self.trait_.format_as_pred(ctx))
2500    }
2501}
2502
2503impl TraitClauseId {
2504    pub(crate) fn format_as_implied(self) -> impl Display {
2505        std::fmt::from_fn(move |f| write!(f, "ImpliedClause{self}"))
2506    }
2507
2508    pub(crate) fn format_as_required(self) -> impl Display {
2509        std::fmt::from_fn(move |f| write!(f, "TraitClause{self}"))
2510    }
2511}
2512
2513impl<C: AstFormatter> FmtWithCtx<C> for TraitDecl {
2514    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2515        // Update the context
2516        let ctx = &ctx.set_generics(&self.generics);
2517
2518        self.item_meta
2519            .fmt_item_intro(f, ctx, "trait", self.def_id)?;
2520
2521        let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2522        write!(f, "{generics}{clauses}")?;
2523
2524        let any_item = !self.implied_clauses.is_empty()
2525            || !self.consts.is_empty()
2526            || !self.types.is_empty()
2527            || !self.methods.is_empty();
2528        if any_item {
2529            write!(f, "\n{{\n")?;
2530            for c in &self.implied_clauses {
2531                writeln!(
2532                    f,
2533                    "{TAB_INCR}{}",
2534                    c.trait_.fmt_trait_proof(c.clause_id, None, ctx)
2535                )?;
2536            }
2537            for assoc_const in &self.consts {
2538                let name = &assoc_const.name;
2539                let ty = assoc_const.ty.with_ctx(ctx);
2540                writeln!(f, "{TAB_INCR}const {name} : {ty}")?;
2541            }
2542            for assoc_ty in &self.types {
2543                let name = assoc_ty.name();
2544                let ctx = &ctx.push_binder(Cow::Borrowed(&assoc_ty.params));
2545                let clauses = assoc_ty
2546                    .params
2547                    .formatted_clauses(ctx)
2548                    .map(|x| x.to_string())
2549                    .chain(assoc_ty.skip_binder.implied_clauses.iter().map(|clause| {
2550                        clause
2551                            .trait_
2552                            .fmt_trait_proof(clause.clause_id, None, ctx)
2553                            .to_string()
2554                    }));
2555                let params = if assoc_ty.params.has_explicits() {
2556                    format!("<{}>", assoc_ty.params.formatted_params(ctx).format(", "))
2557                } else {
2558                    String::new()
2559                };
2560                write!(f, "{TAB_INCR}type {name}{params}")?;
2561                if let Some(default) = &assoc_ty.skip_binder.default {
2562                    write!(f, " = {}", default.value.with_ctx(ctx))?;
2563                }
2564                write!(f, "{}", fmt_where_clauses(clauses, TAB_INCR))?;
2565                writeln!(f)?;
2566            }
2567            for method in self.methods() {
2568                for attr in &method.skip_binder.item_meta.attr_info.attributes {
2569                    if !attr.is_doc_comment() {
2570                        writeln!(f, "{TAB_INCR}{}", attr.with_ctx(ctx))?;
2571                    }
2572                }
2573                let name = method.name();
2574                let (params, method) =
2575                    method.fmt_split_with(ctx, |ctx, method| match &method.default {
2576                        Some(fn_ref) => format!(" = {}", fn_ref.to_string_with_ctx(ctx)),
2577                        None => format!(";"),
2578                    });
2579                writeln!(f, "{TAB_INCR}fn {name}{params}{method}")?;
2580            }
2581            if let Some(vtb_ref) = &self.vtable {
2582                writeln!(f, "{TAB_INCR}vtable: {}", vtb_ref.with_ctx(ctx))?;
2583            } else {
2584                writeln!(f, "{TAB_INCR}non-dyn-compatible")?;
2585            }
2586            write!(f, "}}")?;
2587        }
2588        Ok(())
2589    }
2590}
2591
2592impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclId {
2593    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2594        ItemId::from(*self).fmt_with_ctx(ctx, f)
2595    }
2596}
2597
2598impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclRef {
2599    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2600        let trait_id = self.id.with_ctx(ctx);
2601        let generics = self.generics.with_ctx(ctx);
2602        write!(f, "{trait_id}{generics}")
2603    }
2604}
2605
2606impl TraitDeclRef {
2607    /// Split off the `Self` type. The returned `TraitDeclRef` has incorrect generics. The returned
2608    /// `Self` is `None` for monomorphized traits.
2609    pub fn split_self(&self) -> (Option<Ty>, Self) {
2610        let mut pred = self.clone();
2611        let self_ty = pred.generics.types.remove_and_shift_ids(TypeVarId::ZERO);
2612        (self_ty, pred)
2613    }
2614
2615    fn format_as_pred<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
2616        std::fmt::from_fn(move |f| {
2617            let (self_ty, pred) = self.split_self();
2618            match self_ty {
2619                Some(self_ty) => write!(f, "{}: {}", self_ty.with_ctx(ctx), pred.with_ctx(ctx)),
2620                // Monomorphized traits don't have self types.
2621                None => write!(f, "{}", pred.with_ctx(ctx)),
2622            }
2623        })
2624    }
2625
2626    fn format_as_impl<'a, C: AstFormatter>(&'a self, ctx: &'a C) -> impl Display + 'a {
2627        std::fmt::from_fn(move |f| {
2628            let (self_ty, pred) = self.split_self();
2629            match self_ty {
2630                Some(self_ty) => write!(f, "{} for {}", pred.with_ctx(ctx), self_ty.with_ctx(ctx)),
2631                // Monomorphized traits don't have self types.
2632                None => write!(f, "{}", pred.with_ctx(ctx)),
2633            }
2634        })
2635    }
2636}
2637
2638impl<C: AstFormatter> FmtWithCtx<C> for TraitImpl {
2639    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2640        let trait_id = self.impl_trait.id;
2641        writeln!(f, "// Full name: {}", self.item_meta.name.full_name(ctx))?;
2642
2643        // Update the context
2644        let ctx = &ctx.set_generics(&self.generics);
2645
2646        let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2647        let impl_trait = self.impl_trait.format_as_impl(ctx);
2648        write!(f, "impl{generics}")?;
2649        if let Some(short_name) = trait_impl_short_name(ctx, self.def_id) {
2650            write!(f, " \"{}\"", short_name.with_ctx(ctx))?;
2651        }
2652        write!(f, " {impl_trait}{clauses}",)?;
2653
2654        let newline = if clauses.is_empty() {
2655            " ".to_string()
2656        } else {
2657            "\n".to_string()
2658        };
2659        writeln!(f, "{newline}{{")?;
2660
2661        let any_item = !self.implied_trait_refs.is_empty()
2662            || !self.consts.is_empty()
2663            || !self.types.is_empty()
2664            || !self.methods.is_empty();
2665        if any_item {
2666            for (id, trait_ref) in self.implied_trait_refs.iter_enumerated() {
2667                writeln!(
2668                    f,
2669                    "{TAB_INCR}{}",
2670                    trait_ref
2671                        .trait_decl_ref
2672                        .fmt_trait_proof(id, Some(trait_ref), ctx)
2673                )?;
2674            }
2675            for (const_id, global) in self.consts.iter_enumerated() {
2676                write!(f, "{TAB_INCR}const ")?;
2677                ctx.format_assoc_const_name(f, trait_id, const_id)?;
2678                writeln!(f, " = {}", global.with_ctx(ctx))?;
2679            }
2680            for (type_id, assoc_ty) in self.types.iter_enumerated() {
2681                let ctx = &ctx.push_binder(Cow::Borrowed(&assoc_ty.params));
2682                let params = if assoc_ty.params.has_explicits() {
2683                    format!("<{}>", assoc_ty.params.formatted_params(ctx).format(", "))
2684                } else {
2685                    String::new()
2686                };
2687                let ty = assoc_ty.skip_binder.value.with_ctx(ctx);
2688                let clauses = assoc_ty
2689                    .params
2690                    .formatted_clauses(ctx)
2691                    .map(|x| x.to_string())
2692                    .chain(
2693                        assoc_ty
2694                            .skip_binder
2695                            .implied_trait_refs
2696                            .iter_enumerated()
2697                            .map(|(id, trait_ref)| {
2698                                trait_ref
2699                                    .trait_decl_ref
2700                                    .fmt_trait_proof(id, Some(trait_ref), ctx)
2701                                    .to_string()
2702                            }),
2703                    );
2704                write!(f, "{TAB_INCR}type ")?;
2705                ctx.format_assoc_type_name(f, trait_id, type_id)?;
2706                write!(f, "{params} = {ty}")?;
2707                write!(f, "{}", fmt_where_clauses(clauses, TAB_INCR))?;
2708                writeln!(f)?;
2709            }
2710            for (method_id, bound_fn) in self.methods.iter_enumerated() {
2711                let (params, fn_ref) = bound_fn.fmt_split(ctx);
2712                write!(f, "{TAB_INCR}fn ")?;
2713                ctx.format_method_name(f, trait_id, method_id)?;
2714                writeln!(f, "{params} = {fn_ref}")?;
2715            }
2716        }
2717        if let Some(vtb_ref) = &self.vtable {
2718            writeln!(f, "{TAB_INCR}vtable: {}", vtb_ref.with_ctx(ctx))?;
2719        } else {
2720            writeln!(f, "{TAB_INCR}non-dyn-compatible")?;
2721        }
2722        write!(f, "}}")?;
2723        Ok(())
2724    }
2725}
2726
2727impl<C: AstFormatter> FmtWithCtx<C> for TraitImplId {
2728    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2729        ItemId::from(*self).fmt_with_ctx(ctx, f)
2730    }
2731}
2732
2733impl<C: AstFormatter> FmtWithCtx<C> for TraitImplRef {
2734    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2735        let id = self.id.with_ctx(ctx);
2736        let generics = self.generics.with_ctx(ctx);
2737        write!(f, "{id}{generics}")
2738    }
2739}
2740
2741impl Display for TraitItemName {
2742    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
2743        write!(f, "{}", self.0)
2744    }
2745}
2746
2747impl<C: AstFormatter> FmtWithCtx<C> for TraitRef {
2748    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2749        match &self.kind {
2750            TraitRefKind::SelfId => write!(f, "Self"),
2751            TraitRefKind::ParentClause(sub, clause_id) => {
2752                let sub = sub.with_ctx(ctx);
2753                write!(f, "{sub}::{}", clause_id.format_as_implied())
2754            }
2755            TraitRefKind::ItemClause(sub, type_id, clause_id) => {
2756                write!(f, "{}::", sub.with_ctx(ctx))?;
2757                ctx.format_assoc_type_name(f, sub.trait_id(), *type_id)?;
2758                write!(f, "::{}", clause_id.format_as_implied())
2759            }
2760            TraitRefKind::TraitImpl(impl_ref) => {
2761                write!(f, "{}", impl_ref.with_ctx(ctx))
2762            }
2763            TraitRefKind::Clause(id) => write!(f, "{}", id.with_ctx(ctx)),
2764            TraitRefKind::BuiltinOrAuto { types, .. } => {
2765                let bound_ctx = &ctx.push_bound_regions(&self.trait_decl_ref.regions);
2766                let impl_trait = self.trait_decl_ref.skip_binder.format_as_impl(bound_ctx);
2767                write!(f, "{{built_in impl {impl_trait}")?;
2768                if !types.is_empty() {
2769                    let trait_id = self.trait_decl_ref.skip_binder.id;
2770                    let types = types
2771                        .iter_indexed()
2772                        .map(|(type_id, assoc_ty)| {
2773                            std::fmt::from_fn(move |f| {
2774                                ctx.format_assoc_type_name(f, trait_id, type_id)?;
2775                                let ty = assoc_ty.value.with_ctx(ctx);
2776                                write!(f, "  = {ty}")
2777                            })
2778                        })
2779                        .join(", ");
2780                    write!(f, " where {types}")?;
2781                }
2782                write!(f, "}}")?;
2783                Ok(())
2784            }
2785            TraitRefKind::Dyn => write!(f, "{}", self.trait_decl_ref.with_ctx(ctx)),
2786            TraitRefKind::Unknown(msg) => write!(f, "UNKNOWN({msg})"),
2787        }
2788    }
2789}
2790
2791impl<C: AstFormatter> FmtWithCtx<C> for TraitTypeConstraint {
2792    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2793        let trait_ref = self.trait_ref.with_ctx(ctx);
2794        let ty = self.ty.with_ctx(ctx);
2795        write!(f, "{trait_ref}::")?;
2796        ctx.format_assoc_type_name(f, self.trait_ref.trait_id(), self.type_id)?;
2797        write!(f, " = {ty}")
2798    }
2799}
2800
2801impl<C: AstFormatter> FmtWithCtx<C> for Ty {
2802    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2803        match self.kind() {
2804            // Print tuples as `(T1, T2, ...)` instead of `(_, _, ...)<T1, T2, ...>`.
2805            TyKind::Adt(tref)
2806                if tref.is_tuple()
2807                    && let Some(krate) = ctx.get_crate() =>
2808            {
2809                let fields = self.as_tuple_fields(krate);
2810                let trailing_comma = if fields.len() == 1 { "," } else { "" };
2811                let fields = fields.iter().map(|ty| ty.with_ctx(ctx)).format(", ");
2812                write!(f, "({fields}{trailing_comma})",)
2813            }
2814            TyKind::Adt(tref) if tref.is_str() => write!(f, "str"),
2815            TyKind::Adt(tref) => write!(f, "{}", tref.with_ctx(ctx)),
2816            TyKind::TypeVar(id) => write!(f, "{}", id.with_ctx(ctx)),
2817            TyKind::Scalar(kind) => write!(f, "{kind}"),
2818            TyKind::Never => write!(f, "!"),
2819            TyKind::Pattern(ty, pat) => write!(f, "{} is {}", ty.with_ctx(ctx), pat.with_ctx(ctx)),
2820            TyKind::Ref(r, ty, kind) => {
2821                write!(f, "&{} ", r.with_ctx(ctx))?;
2822                if let RefKind::Mut = kind {
2823                    write!(f, "mut ")?;
2824                }
2825                write!(f, "{}", ty.with_ctx(ctx))
2826            }
2827            TyKind::RawPtr(ty, kind) => {
2828                write!(f, "*")?;
2829                match kind {
2830                    RefKind::Shared => write!(f, "const")?,
2831                    RefKind::Mut => write!(f, "mut")?,
2832                }
2833                write!(f, " {}", ty.with_ctx(ctx))
2834            }
2835            TyKind::Array(ty, len, _) => {
2836                write!(f, "[{}; {}]", ty.with_ctx(ctx), len.with_ctx(ctx))
2837            }
2838            TyKind::Slice(ty, _) => {
2839                write!(f, "[{}]", ty.with_ctx(ctx))
2840            }
2841            TyKind::TraitType(trait_ref, type_id, generics) => {
2842                write!(f, "{}::", trait_ref.with_ctx(ctx))?;
2843                ctx.format_assoc_type_name(f, trait_ref.trait_id(), *type_id)?;
2844                write!(f, "{}", generics.with_ctx(ctx))
2845            }
2846            TyKind::DynTrait(pred) => {
2847                write!(f, "(dyn {})", pred.with_ctx(ctx))
2848            }
2849            TyKind::FnPtr(io) => {
2850                write!(f, "{}", io.with_ctx(ctx))
2851            }
2852            TyKind::FnDef(binder) => {
2853                let (regions, value) = binder.fmt_split(ctx);
2854                if !regions.is_empty() {
2855                    write!(f, "for<{regions}> ",)?
2856                };
2857                write!(f, "{value}",)
2858            }
2859            TyKind::PtrMetadata(ty) => {
2860                write!(f, "PtrMetadata<{}>", ty.with_ctx(ctx))
2861            }
2862            TyKind::Error(msg) => write!(f, "type_error(\"{msg}\")"),
2863        }
2864    }
2865}
2866
2867impl<C: AstFormatter> FmtWithCtx<C> for TypePattern {
2868    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2869        match self {
2870            TypePattern::Range(start, end) => {
2871                write!(f, "{}..={}", start.with_ctx(ctx), end.with_ctx(ctx))
2872            }
2873            TypePattern::OrPattern(patterns) => {
2874                write!(
2875                    f,
2876                    "({})",
2877                    patterns.iter().map(|pat| pat.with_ctx(ctx)).format(" | ")
2878                )
2879            }
2880            TypePattern::NotNull => write!(f, "!null"),
2881        }
2882    }
2883}
2884
2885impl<C: AstFormatter> FmtWithCtx<C> for TypeDbVar {
2886    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2887        ctx.format_bound_var(f, *self, "@Type", |v| Some(v.name.clone()))
2888    }
2889}
2890
2891impl<C: AstFormatter> FmtWithCtx<C> for TypeDecl {
2892    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2893        let keyword = match &self.kind {
2894            TypeDeclKind::Struct(..) => "struct",
2895            TypeDeclKind::Union(..) => "union",
2896            TypeDeclKind::Enum(..) => "enum",
2897            TypeDeclKind::Alias(..) => "type",
2898            TypeDeclKind::Opaque | TypeDeclKind::Error(..) => "opaque type",
2899        };
2900        self.item_meta
2901            .fmt_item_intro(f, ctx, keyword, self.def_id)?;
2902
2903        let ctx = &ctx.set_generics(&self.generics);
2904        let ctx = &ctx.set_current_type(self.def_id);
2905        let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2906        write!(f, "{params}{preds}")?;
2907
2908        let nl_or_space = if !self.generics.has_predicates() {
2909            " ".to_string()
2910        } else {
2911            "\n".to_string()
2912        };
2913        match &self.kind {
2914            TypeDeclKind::Struct(fields) => {
2915                write!(f, "{nl_or_space}{{")?;
2916                if !fields.is_empty() {
2917                    writeln!(f)?;
2918                    for field in fields {
2919                        writeln!(f, "  {},", field.with_ctx(ctx))?;
2920                    }
2921                }
2922                write!(f, "}}")
2923            }
2924            TypeDeclKind::Union(fields) => {
2925                write!(f, "{nl_or_space}{{")?;
2926                writeln!(f)?;
2927                for field in fields {
2928                    writeln!(f, "  {},", field.with_ctx(ctx))?;
2929                }
2930                write!(f, "}}")
2931            }
2932            TypeDeclKind::Enum(variants) => {
2933                write!(f, "{nl_or_space}{{")?;
2934                writeln!(f)?;
2935                for variant in variants {
2936                    writeln!(f, "  {},", variant.with_ctx(ctx))?;
2937                }
2938                write!(f, "}}")
2939            }
2940            TypeDeclKind::Alias(ty) => write!(f, " = {}", ty.with_ctx(ctx)),
2941            TypeDeclKind::Opaque => write!(f, ""),
2942            TypeDeclKind::Error(msg) => write!(f, " = ERROR({msg})"),
2943        }?;
2944
2945        if ctx.include_layouts() {
2946            let layout_type_id = match &self.kind {
2947                TypeDeclKind::Alias(ty) => ty.as_adt().map(|tref| tref.id).unwrap_or(self.def_id),
2948                _ => self.def_id,
2949            };
2950            let ctx = &ctx.set_current_type(layout_type_id);
2951            let fmt_layout =
2952                |f: &mut fmt::Formatter<'_>, heading: &str, layout: &Layout| -> fmt::Result {
2953                    write!(f, "// {heading}:")?;
2954                    let ctx = &ctx.increase_indent();
2955                    for line in layout.to_string_with_ctx(ctx).lines() {
2956                        write!(f, "\n// {line}")?;
2957                    }
2958                    Ok(())
2959                };
2960            match self.layout.len() {
2961                0 => write!(f, "\n// layout: none")?,
2962                1 => {
2963                    let layout = self.layout.values().next().unwrap();
2964                    writeln!(f)?;
2965                    fmt_layout(f, "layout", layout)?;
2966                }
2967                _ => {
2968                    let mut separator = "\n";
2969                    for (target, layout) in &self.layout {
2970                        write!(f, "{separator}")?;
2971                        fmt_layout(f, &format!("layout for target `{target}`"), layout)?;
2972                        separator = "\n\n";
2973                    }
2974                }
2975            }
2976        }
2977
2978        Ok(())
2979    }
2980}
2981
2982impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclId {
2983    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2984        ItemId::from(*self).fmt_with_ctx(ctx, f)
2985    }
2986}
2987
2988impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclRef {
2989    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2990        let id = self.id.with_ctx(ctx);
2991        let generics = self.generics.with_ctx(ctx);
2992        write!(f, "{id}{generics}")
2993    }
2994}
2995
2996impl<C: AstFormatter> FmtWithCtx<C> for TypeParam {
2997    fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2998        write!(f, "{}", self.name)
2999    }
3000}
3001
3002impl<C: AstFormatter> FmtWithCtx<C> for UnOp {
3003    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3004        match self {
3005            UnOp::Not => write!(f, "~"),
3006            UnOp::Neg(mode) => write!(f, "{}.-", mode),
3007            UnOp::Cast(kind) => write!(f, "{}", kind.with_ctx(ctx)),
3008        }
3009    }
3010}
3011
3012impl_display_via_ctx!(Variant);
3013impl<C: AstFormatter> FmtWithCtx<C> for Variant {
3014    fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3015        write!(f, "{}", self.name)?;
3016        if !self.fields.is_empty() {
3017            let fields = self.fields.iter().map(|f| f.with_ctx(ctx)).format(", ");
3018            write!(f, " {{ {} }}", fields)?;
3019        }
3020        Ok(())
3021    }
3022}
3023
3024impl<C: AstFormatter> FmtWithCtx<(&C, VariantId)> for VariantLayout {
3025    fn fmt_with_ctx(
3026        &self,
3027        &(ctx, variant_id): &(&C, VariantId),
3028        f: &mut fmt::Formatter<'_>,
3029    ) -> fmt::Result {
3030        writeln!(f, "{{")?;
3031        let tab = ctx.indent();
3032        let ctx1 = &ctx.increase_indent();
3033        let tab1 = ctx1.indent();
3034        for (field_id, offset) in self.field_offsets.iter_enumerated() {
3035            write!(f, "{tab1}offset of ")?;
3036            ctx1.format_current_field_name(f, variant_id, field_id)?;
3037            writeln!(f, ": {},", offset.with_ctx(ctx1))?;
3038        }
3039        let tagger = self
3040            .tagger
3041            .iter()
3042            .map(|(offset, value)| format!("{offset} := {value}"))
3043            .format(", ");
3044        writeln!(f, "{tab1}inhabited: {},", self.inhabited.with_ctx(ctx1))?;
3045        writeln!(f, "{tab1}tagger: [{tagger}],")?;
3046        write!(f, "{tab}}}")
3047    }
3048}