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