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