Skip to main content

charon_lib/pretty/
fmt_with_ctx.rs

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