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