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