Skip to main content

charon_lib/pretty/
fmt_with_ctx.rs

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