Skip to main content

charon_lib/pretty/
fmt_with_ctx.rs

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