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