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