1use crate::{
3 ast,
4 formatter::*,
5 ids::IndexVec,
6 llbc_ast::{self as llbc, *},
7 transform::utils::GenericsSource,
8 ullbc_ast::{self as ullbc, *},
9 utils::{TAB_INCR, repeat_except_first},
10};
11use either::Either;
12use itertools::Itertools;
13use std::{
14 borrow::Cow,
15 fmt::{self, Debug, Display},
16};
17
18pub struct WithCtx<'a, C, T: ?Sized> {
19 val: &'a T,
20 ctx: &'a C,
21}
22
23impl<'a, C, T: ?Sized> Display for WithCtx<'a, C, T>
24where
25 T: FmtWithCtx<C>,
26{
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 self.val.fmt_with_ctx(self.ctx, f)
29 }
30}
31
32pub trait FmtWithCtx<C> {
34 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result;
35
36 fn with_ctx<'a>(&'a self, ctx: &'a C) -> WithCtx<'a, C, Self> {
41 WithCtx { val: self, ctx }
42 }
43
44 fn to_string_with_ctx(&self, ctx: &C) -> String {
45 self.with_ctx(ctx).to_string()
46 }
47}
48
49macro_rules! impl_display_via_ctx {
50 ($ty:ty) => {
51 impl Display for $ty {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 self.fmt_with_ctx(&FmtCtx::new(), f)
54 }
55 }
56 };
57}
58macro_rules! impl_debug_via_display {
59 ($ty:ty) => {
60 impl Debug for $ty {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 <_ as Display>::fmt(self, f)
63 }
64 }
65 };
66}
67
68fn fmt_where_clauses<'a, I>(clauses: I, indent: &'a str) -> impl Display + 'a
69where
70 I: IntoIterator,
71 I::Item: Display,
72{
73 let clauses = clauses
74 .into_iter()
75 .map(|clause| clause.to_string())
76 .collect_vec();
77 std::fmt::from_fn(move |f| {
78 if !clauses.is_empty() {
79 write!(f, "\n{indent}where")?;
80 for (i, clause) in clauses.iter().enumerate() {
81 let sep = if i + 1 == clauses.len() { ";" } else { "," };
82 write!(f, "\n{indent}{TAB_INCR}{clause}{sep}")?;
83 }
84 }
85 Ok(())
86 })
87}
88
89impl<C: AstFormatter> FmtWithCtx<C> for AbortKind {
92 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 match self {
94 AbortKind::Panic(name) => {
95 write!(f, "panic")?;
96 if let Some(name) = name {
97 write!(f, "({})", name.with_ctx(ctx))?;
98 }
99 Ok(())
100 }
101 AbortKind::UndefinedBehavior => write!(f, "undefined_behavior"),
102 AbortKind::UnwindTerminate => write!(f, "unwind_terminate"),
103 }
104 }
105}
106
107impl<C: AstFormatter> FmtWithCtx<C> for Abi {
108 fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{}", self.rust_name())
110 }
111}
112
113impl<C: AstFormatter> FmtWithCtx<C> for BuiltinAssertKind {
114 fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 match self {
116 BuiltinAssertKind::BoundsCheck { .. } => write!(f, "bounds_check"),
117 BuiltinAssertKind::Overflow(..) => write!(f, "overflow"),
118 BuiltinAssertKind::OverflowNeg(..) => write!(f, "overflow_neg"),
119 BuiltinAssertKind::DivisionByZero(..) => write!(f, "division_by_zero"),
120 BuiltinAssertKind::RemainderByZero(..) => write!(f, "remainder_by_zero"),
121 BuiltinAssertKind::MisalignedPointerDereference { .. } => {
122 write!(f, "misaligned_pointer_dereference")
123 }
124 BuiltinAssertKind::NullPointerDereference => write!(f, "null_pointer_dereference"),
125 BuiltinAssertKind::NullReferenceCreated => write!(f, "null_reference_created"),
126 BuiltinAssertKind::InvalidEnumConstruction(..) => {
127 write!(f, "invalid_enum_construction")
128 }
129 BuiltinAssertKind::ResumedAfterReturn => write!(f, "resumed_after_return"),
130 BuiltinAssertKind::ResumedAfterDrop => write!(f, "resumed_after_drop"),
131 BuiltinAssertKind::ResumedAfterPanic => write!(f, "resumed_after_panic"),
132 }
133 }
134}
135
136impl<C: AstFormatter> FmtWithCtx<C> for ItemId {
137 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 match ctx.get_crate() {
139 None => write!(f, "{self}"),
140 Some(translated) => translated.item_short_name(*self).fmt_with_ctx(ctx, f),
141 }
142 }
143}
144
145impl Display for ItemId {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
147 let s = match self {
148 ItemId::Type(x) => x.to_pretty_string(),
149 ItemId::Fun(x) => x.to_pretty_string(),
150 ItemId::Global(x) => x.to_pretty_string(),
151 ItemId::TraitDecl(x) => x.to_pretty_string(),
152 ItemId::TraitImpl(x) => x.to_pretty_string(),
153 };
154 f.write_str(&s)
155 }
156}
157
158impl<C: AstFormatter> FmtWithCtx<C> for MaybeAssocItemId {
159 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 match self {
161 MaybeAssocItemId::Free(id) => id.fmt_with_ctx(ctx, f),
162 MaybeAssocItemId::Assoc(trait_id, item_id) => {
163 write!(f, "{}::", ItemId::TraitDecl(*trait_id).with_ctx(ctx),)?;
164 ctx.format_assoc_item_name(f, *trait_id, *item_id)
165 }
166 }
167 }
168}
169
170impl<C: AstFormatter> FmtWithCtx<C> for ItemRef<'_> {
171 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 match self {
173 ItemRef::Type(d) => write!(f, "{}", d.with_ctx(ctx)),
174 ItemRef::Fun(d) => write!(f, "{}", d.with_ctx(ctx)),
175 ItemRef::Global(d) => write!(f, "{}", d.with_ctx(ctx)),
176 ItemRef::TraitDecl(d) => write!(f, "{}", d.with_ctx(ctx)),
177 ItemRef::TraitImpl(d) => write!(f, "{}", d.with_ctx(ctx)),
178 }
179 }
180}
181
182impl<C: AstFormatter> FmtWithCtx<C> for Assert {
183 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 write!(
185 f,
186 "assert({} == {})",
187 self.cond.with_ctx(ctx),
188 self.expected,
189 )?;
190 if let Some(check_kind) = &self.check_kind {
191 write!(f, " ({})", check_kind.with_ctx(ctx))?;
192 }
193 Ok(())
194 }
195}
196
197impl<T> Binder<T> {
198 fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
200 where
201 C: AstFormatter,
202 T: FmtWithCtx<C::Reborrow<'a>>,
203 {
204 self.fmt_split_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
205 }
206 fn fmt_split_with<'a, C>(
208 &'a self,
209 ctx: &'a C,
210 fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
211 ) -> (String, String)
212 where
213 C: AstFormatter,
214 {
215 let ctx = &ctx.push_binder(Cow::Borrowed(&self.params));
216 (
217 self.params.fmt_with_ctx_single_line(ctx),
218 fmt_inner(ctx, &self.skip_binder),
219 )
220 }
221}
222
223impl Display for OverflowMode {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
225 match self {
226 OverflowMode::Panic => write!(f, "panic"),
227 OverflowMode::Wrap => write!(f, "wrap"),
228 OverflowMode::UB => write!(f, "ub"),
229 }
230 }
231}
232
233impl Display for BinOp {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
235 match self {
236 BinOp::BitXor => write!(f, "^"),
237 BinOp::BitAnd => write!(f, "&"),
238 BinOp::BitOr => write!(f, "|"),
239 BinOp::Eq => write!(f, "=="),
240 BinOp::Lt => write!(f, "<"),
241 BinOp::Le => write!(f, "<="),
242 BinOp::Ne => write!(f, "!="),
243 BinOp::Ge => write!(f, ">="),
244 BinOp::Gt => write!(f, ">"),
245 BinOp::Add(mode) => write!(f, "{}.+", mode),
246 BinOp::Sub(mode) => write!(f, "{}.-", mode),
247 BinOp::Mul(mode) => write!(f, "{}.*", mode),
248 BinOp::Div(mode) => write!(f, "{}./", mode),
249 BinOp::Rem(mode) => write!(f, "{}.%", mode),
250 BinOp::AddChecked => write!(f, "checked.+"),
251 BinOp::SubChecked => write!(f, "checked.-"),
252 BinOp::MulChecked => write!(f, "checked.*"),
253 BinOp::Shl(mode) => write!(f, "{}.<<", mode),
254 BinOp::Shr(mode) => write!(f, "{}.>>", mode),
255 BinOp::Cmp => write!(f, "cmp"),
256 BinOp::Offset => write!(f, "offset"),
257 }
258 }
259}
260
261impl<C: AstFormatter> FmtWithCtx<C> for llbc::Block {
262 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 for st in &self.statements {
264 st.fmt_with_ctx(ctx, f)?;
265 }
266 Ok(())
267 }
268}
269
270const LLBC_UNWIND_PREFIX: &str = "↳⚡ ";
271
272fn fmt_llbc_unwind_block<C: AstFormatter>(
273 ctx: &C,
274 f: &mut fmt::Formatter<'_>,
275 on_unwind: &llbc::Block,
276) -> fmt::Result {
277 let tab = ctx.indent();
278 let block = on_unwind.to_string_with_ctx(&ctx.reset_indent());
279 let mut lines = block.lines();
280 if let Some(first) = lines.next() {
281 write!(f, "\n{tab}{LLBC_UNWIND_PREFIX}{first}")?;
282 let ctx = ctx.increase_indent();
283 let tab = ctx.indent();
284 for line in lines {
285 write!(f, "\n{tab}{line}")?;
286 }
287 }
288 Ok(())
289}
290
291impl<C: AstFormatter> FmtWithCtx<C> for ullbc::BlockData {
292 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 for statement in &self.statements {
294 statement.fmt_with_ctx(ctx, f)?;
295 }
296 write!(f, "{};", self.terminator.with_ctx(ctx))?;
297 Ok(())
298 }
299}
300
301impl<C: AstFormatter> FmtWithCtx<C> for ast::Body {
302 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 let tab = ctx.indent();
304 write!(f, "\n{tab}")?;
305 match self {
306 Body::Unstructured(body) => {
307 let body = body.with_ctx(ctx);
308 write!(f, "{{\n{body}{tab}}}")
309 }
310 Body::Structured(body) => {
311 let body = body.with_ctx(ctx);
312 write!(f, "{{\n{body}{tab}}}")
313 }
314 Body::Extern(name) => write!(f, "= <extern:{name}>"),
315 Body::Intrinsic { name, .. } => write!(f, "= <intrinsic:{name}>"),
316 Body::Opaque => write!(f, "= <opaque>"),
317 Body::Missing => write!(f, "= <missing>"),
318 Body::Error(error) => write!(f, "= error(\"{}\")", error.msg),
319 Body::TargetDispatch(targets) => {
320 writeln!(f, "= target_dispatch {{")?;
321 for (target, fun) in targets {
322 let fun = fun.with_ctx(ctx);
323 writeln!(f, "{tab}{TAB_INCR}{target} => {fun},")?;
324 }
325 write!(f, "{tab}}}")
326 }
327 }
328 }
329}
330
331impl Display for BorrowKind {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
333 write!(f, "{self:?}")
335 }
336}
337
338impl<C: AstFormatter> FmtWithCtx<C> for Call {
339 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340 let dest = self.dest.with_ctx(ctx);
341 let func = self.func.with_ctx(ctx);
342 let args = self.args.iter().map(|x| x.with_ctx(ctx)).format(", ");
343 write!(f, "{dest} = {func}({args})")
344 }
345}
346
347impl<C: AstFormatter> FmtWithCtx<C> for UnsizingMetadata {
348 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349 match self {
350 UnsizingMetadata::Length(len) => write!(f, "{}", len.with_ctx(ctx)),
351 UnsizingMetadata::VTable(_, vtable) => {
352 write!(f, "{}", vtable.with_ctx(ctx))
353 }
354 UnsizingMetadata::VTableUpcast(fields) => {
355 write!(f, " at [")?;
356 let fields = fields.iter().map(|x| format!("{}", x.index())).format(", ");
357 write!(f, "{fields}]")
358 }
359 UnsizingMetadata::Unknown => {
360 write!(f, "?")
361 }
362 }
363 }
364}
365
366impl<C: AstFormatter> FmtWithCtx<C> for CastKind {
367 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 match self {
369 CastKind::Scalar(src, tgt) => write!(f, "cast<{src}, {tgt}>"),
370 CastKind::FnPtr(src, tgt) | CastKind::RawPtr(src, tgt) => {
371 write!(f, "cast<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
372 }
373 CastKind::Unsize(src, tgt, meta) => write!(
374 f,
375 "unsize_cast<{}, {}, {}>",
376 src.with_ctx(ctx),
377 tgt.with_ctx(ctx),
378 meta.with_ctx(ctx)
379 ),
380 CastKind::Transmute(src, tgt) => {
381 write!(f, "transmute<{}, {}>", src.with_ctx(ctx), tgt.with_ctx(ctx))
382 }
383 CastKind::Concretize(ty, ty1) => {
384 write!(f, "concretize<{}, {}>", ty.with_ctx(ctx), ty1.with_ctx(ctx))
385 }
386 }
387 }
388}
389
390impl<C: AstFormatter> FmtWithCtx<C> for ClauseDbVar {
391 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392 ctx.format_bound_var(f, *self, "TraitClause", |_| None)
393 }
394}
395
396impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericDbVar {
397 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398 ctx.format_bound_var(f, *self, "@ConstGeneric", |v| Some(v.name.clone()))
399 }
400}
401
402impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericParam {
403 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 write!(f, "const {} : {}", self.name, self.ty.with_ctx(ctx))
405 }
406}
407
408impl Display for DeBruijnId {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
410 write!(f, "{}", self.index)
411 }
412}
413
414impl<Id: Display> Display for DeBruijnVar<Id> {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 match self {
417 Self::Bound(dbid, varid) => write!(f, "Bound({dbid}, {varid})"),
418 Self::Free(varid) => write!(f, "{varid}"),
419 }
420 }
421}
422
423impl<C: AstFormatter> FmtWithCtx<C> for DeclarationGroup {
424 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 use DeclarationGroup::*;
426 match self {
427 Type(g) => write!(f, "Type decls group: {}", g.with_ctx(ctx)),
428 Fun(g) => write!(f, "Fun decls group: {}", g.with_ctx(ctx)),
429 Global(g) => write!(f, "Global decls group: {}", g.with_ctx(ctx)),
430 TraitDecl(g) => write!(f, "Trait decls group: {}", g.with_ctx(ctx)),
431 TraitImpl(g) => write!(f, "Trait impls group: {}", g.with_ctx(ctx)),
432 Mixed(g) => write!(f, "Mixed group: {}", g.with_ctx(ctx)),
433 }
434 }
435}
436
437impl<C: AstFormatter> FmtWithCtx<C> for Discriminator {
438 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 match self {
440 Discriminator::Known(variant_id) => ctx.format_current_variant_name(f, *variant_id),
441 Discriminator::Invalid => write!(f, "invalid"),
442 Discriminator::Branch {
443 offset,
444 children,
445 fallback,
446 ..
447 } => {
448 write!(f, "read at offset {} {{ ", offset.with_ctx(ctx))?;
449 for (range, child) in children {
450 if range.start() == range.end() {
451 write!(f, "{}", range.start())?;
452 } else {
453 write!(f, "{}..={}", range.start(), range.end())?;
454 }
455 write!(f, " => {}, ", child.with_ctx(ctx))?;
456 }
457 write!(f, "_ => {} }}", fallback.with_ctx(ctx))
458 }
459 }
460 }
461}
462
463impl<C: AstFormatter> FmtWithCtx<C> for DynPredicate {
464 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465 let params = &self.binder.params;
466 let ctx = &ctx.push_binder(Cow::Borrowed(params));
467 let GenericParams {
468 regions,
469 types,
470 const_generics,
471 trait_clauses,
472 regions_outlive,
473 types_outlive,
474 trait_type_constraints,
475 } = params;
476 assert!(regions.is_empty());
477 assert!(const_generics.is_empty());
478 assert!(regions_outlive.is_empty());
479 assert_eq!(types.len(), 1);
480
481 let mut cstrs_per_clause: IndexVec<TraitClauseId, Vec<String>> =
483 trait_clauses.map_ref(|_| vec![]);
484 for cstr in trait_type_constraints {
485 let mut tgt_clause = None;
486 let (_, cstr) = cstr.fmt_split_with(ctx, |ctx, cstr| {
487 let mut path = vec![];
488 let mut tref = &cstr.trait_ref;
489 loop {
490 match &tref.kind {
491 TraitRefKind::ParentClause(parent_trait_ref, clause_id) => {
492 path.push(*clause_id);
493 tref = parent_trait_ref;
494 }
495 &TraitRefKind::Clause(DeBruijnVar::Bound(_, clause_id)) => {
496 tgt_clause = Some(clause_id);
497 break;
498 }
499 _ => unreachable!(),
500 }
501 }
502 let ty = cstr.ty.with_ctx(ctx);
503 let path_fmt = path.iter().map(|id| id.format_as_implied()).format("::");
504 std::fmt::from_fn(|f| {
505 write!(f, "{path_fmt}")?;
506 if !path.is_empty() {
507 write!(f, "::")?;
508 }
509 ctx.format_assoc_type_name(f, cstr.trait_ref.trait_id(), cstr.type_id)?;
510 write!(f, " = {ty}")?;
511 Ok(())
512 })
513 .to_string()
514 });
515 if let Some(cstrs) = cstrs_per_clause.get_mut(tgt_clause.unwrap()) {
516 cstrs.push(cstr);
517 }
518 }
519 let trait_clauses = trait_clauses.iter().map(|clause| {
520 let cstrs = &cstrs_per_clause[clause.clause_id];
521 clause.trait_.fmt_as_for_with(ctx, |ctx, pred| {
522 let (_, pred) = pred.split_self();
523 let trait_id = pred.id.with_ctx(ctx);
524 let generics = if pred.generics.has_explicits() || !cstrs.is_empty() {
525 let xs = pred
526 .generics
527 .fmt_explicits(ctx)
528 .map(Either::Left)
529 .chain(cstrs.iter().map(Either::Right))
530 .format(", ");
531 format!("<{}>", xs)
532 } else {
533 String::new()
534 };
535 format!("{trait_id}{generics}")
536 })
537 });
538
539 let types_outlive = types_outlive
540 .iter()
541 .filter(|x| !x.skip_binder.1.is_erased())
542 .map(|x| {
543 x.fmt_as_for_with(ctx, |ctx, types_outlive| {
544 types_outlive.1.to_string_with_ctx(ctx)
545 })
546 });
547 let clauses = trait_clauses.chain(types_outlive).format(" + ");
548 write!(f, "{clauses}")
549 }
550}
551
552impl_display_via_ctx!(Field);
553impl<C: AstFormatter> FmtWithCtx<C> for Field {
554 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 write!(f, "{}: {}", self.name, self.ty.with_ctx(ctx))
556 }
557}
558
559impl Display for FileName {
560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
561 match self {
562 FileName::Virtual(path_buf) | FileName::Local(path_buf) => {
563 write!(f, "{}", path_buf.display())
564 }
565 FileName::NotReal(name) => write!(f, "{}", name),
566 }
567 }
568}
569
570impl Display for FloatTy {
571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
572 match self {
573 FloatTy::F16 => write!(f, "f16"),
574 FloatTy::F32 => write!(f, "f32"),
575 FloatTy::F64 => write!(f, "f64"),
576 FloatTy::F128 => write!(f, "f128"),
577 }
578 }
579}
580
581impl Display for FloatValue {
582 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
583 let v = &self.value;
584 let ty = self.ty;
585 write!(f, "{v}{ty}")
586 }
587}
588
589impl<C: AstFormatter> FmtWithCtx<C> for FnOperand {
590 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591 match self {
592 FnOperand::Regular(func) => write!(f, "{}", func.with_ctx(ctx)),
593 FnOperand::Dynamic(op) => write!(f, "({})", op.with_ctx(ctx)),
594 }
595 }
596}
597
598impl<C: AstFormatter> FmtWithCtx<C> for FnPtr {
599 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 match self.kind.as_ref() {
601 FnPtrKind::Fun(def_id) => write!(f, "{}", def_id.with_ctx(ctx))?,
602 FnPtrKind::Trait(trait_ref, method_id) => {
603 write!(f, "{}::", trait_ref.with_ctx(ctx))?;
604 ctx.format_method_name(f, trait_ref.trait_id(), *method_id)?;
605 }
606 };
607 write!(f, "{}", self.generics.with_ctx(ctx))
608 }
609}
610
611impl<C: AstFormatter> FmtWithCtx<C> for FunDecl {
612 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 let mut keyword = String::new();
614 if self.signature.is_unsafe {
615 keyword.push_str("unsafe ");
616 }
617 if !self.signature.abi.is_rust() {
618 keyword.push_str(&format!("extern \"{}\" ", self.signature.abi.with_ctx(ctx)));
619 }
620 keyword.push_str("fn");
621 self.item_meta
622 .fmt_item_intro(f, ctx, &keyword, self.def_id)?;
623
624 let ctx = &ctx.set_generics(&self.generics);
626
627 let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
629 write!(f, "{params}")?;
630
631 let n_args = self.signature.inputs.len();
633 let args_of_locals = |l: &Locals| {
634 let ctx = ctx.set_locals(l);
635 l.locals
636 .iter()
637 .skip(1)
638 .take(n_args)
639 .map(|l| format!("{}", l.index.with_ctx(&ctx)))
640 .collect::<Vec<String>>()
641 };
642
643 let arg_names = match &self.body {
644 Body::Unstructured(body) => args_of_locals(&body.locals),
645 Body::Structured(body) => args_of_locals(&body.locals),
646 Body::Intrinsic { arg_names, .. } => arg_names
647 .iter()
648 .enumerate()
649 .map(|(i, name)| {
650 let id = LocalId::new(i + 1);
651 match name {
652 Some(name) => format!("{name}_{id}"),
653 None => format!("_{id}"),
654 }
655 })
656 .collect(),
657 Body::Error(..)
658 | Body::Extern(..)
659 | Body::Missing
660 | Body::Opaque
661 | Body::TargetDispatch(..) => (0..n_args)
662 .map(|i| format!("{}", LocalId::new(i + 1).with_ctx(ctx)))
663 .collect(),
664 };
665 let mut args: Vec<String> = Vec::new();
666 for (ty, name) in self.signature.inputs.iter().zip(arg_names) {
667 args.push(format!("{}: {}", name, ty.with_ctx(ctx)));
668 }
669 let args = args.join(", ");
670 if self.signature.is_variadic {
671 if args.is_empty() {
672 write!(f, "(...)")?;
673 } else {
674 write!(f, "({args}, ...)")?;
675 }
676 } else {
677 write!(f, "({args})")?;
678 }
679
680 if !self.signature.output.is_unit() {
682 write!(f, " -> {}", self.signature.output.with_ctx(ctx))?;
683 };
684 write!(f, "{preds}")?;
685 write!(f, "{}", self.body.with_ctx(ctx))?;
686
687 Ok(())
688 }
689}
690
691impl<C: AstFormatter> FmtWithCtx<C> for FunDeclId {
692 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 ItemId::from(*self).fmt_with_ctx(ctx, f)
694 }
695}
696
697impl<C: AstFormatter> FmtWithCtx<C> for FunDeclRef {
698 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 let id = self.id.with_ctx(ctx);
700 let generics = self.generics.with_ctx(ctx);
701 write!(f, "{id}{generics}")
702 }
703}
704
705impl<C: AstFormatter> FmtWithCtx<C> for RegionBinder<FunSig> {
706 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707 let ctx = &ctx.push_bound_regions(&self.regions);
709 let FunSig {
710 is_unsafe,
711 abi,
712 is_variadic,
713 inputs,
714 output,
715 } = &self.skip_binder;
716
717 if *is_unsafe {
718 write!(f, "unsafe ")?;
719 }
720
721 if !abi.is_rust() {
722 write!(f, "extern \"{}\" ", abi.with_ctx(ctx))?;
723 }
724
725 write!(f, "fn")?;
726 if !self.regions.is_empty() {
727 write!(
728 f,
729 "<{}>",
730 self.regions.iter().map(|r| r.with_ctx(ctx)).format(", ")
731 )?;
732 }
733 let is_empty = inputs.is_empty();
734 let inputs = inputs.iter().map(|x| x.with_ctx(ctx)).format(", ");
735 if *is_variadic {
736 if is_empty {
737 write!(f, "(...)")?;
738 } else {
739 write!(f, "({inputs}, ...)")?;
740 }
741 } else {
742 write!(f, "({inputs})")?;
743 }
744 if !output.is_unit() {
745 let output = output.with_ctx(ctx);
746 write!(f, " -> {output}")?;
747 }
748 Ok(())
749 }
750}
751
752impl<Id: Copy, C: AstFormatter> FmtWithCtx<C> for GDeclarationGroup<Id>
753where
754 Id: FmtWithCtx<C>,
755{
756 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 use GDeclarationGroup::*;
758 match self {
759 NonRec(id) => write!(f, "Non rec: {}", id.with_ctx(ctx)),
760 Rec(ids) => {
761 let ids = ids.iter().map(|id| id.with_ctx(ctx)).format(", ");
762 write!(f, "Rec: {}", ids)
763 }
764 }
765 }
766}
767
768impl GenericArgs {
769 pub(crate) fn fmt_explicits<'a, C: AstFormatter>(
770 &'a self,
771 ctx: &'a C,
772 ) -> impl Iterator<Item = impl Display + 'a> {
773 let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
774 let types = self.types.iter().map(|x| x.with_ctx(ctx));
775 let const_generics = self.const_generics.iter().map(|x| x.with_ctx(ctx));
776 regions.map(Either::Left).chain(
777 types
778 .map(Either::Left)
779 .chain(const_generics.map(Either::Right))
780 .map(Either::Right),
781 )
782 }
783
784 pub(crate) fn fmt_implicits<'a, C: AstFormatter>(
785 &'a self,
786 ctx: &'a C,
787 ) -> impl Iterator<Item = impl Display + 'a> {
788 self.trait_refs.iter().map(|x| x.with_ctx(ctx))
789 }
790}
791
792impl_display_via_ctx!(GenericArgs);
793impl_debug_via_display!(GenericArgs);
794impl<C: AstFormatter> FmtWithCtx<C> for GenericArgs {
795 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796 if self.has_explicits() {
797 write!(f, "<{}>", self.fmt_explicits(ctx).format(", "))?;
798 }
799 if self.has_implicits() {
800 write!(f, "[{}]", self.fmt_implicits(ctx).format(", "))?;
801 }
802 Ok(())
803 }
804}
805
806impl GenericParams {
807 fn formatted_params<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
808 where
809 C: AstFormatter,
810 {
811 let regions = self.regions.iter().map(|x| x.with_ctx(ctx));
812 let types = self.types.iter().map(|x| x.with_ctx(ctx));
813 let const_generics = self.const_generics.iter().map(|x| x.with_ctx(ctx));
814 regions.map(Either::Left).chain(
815 types
816 .map(Either::Left)
817 .chain(const_generics.map(Either::Right))
818 .map(Either::Right),
819 )
820 }
821
822 fn formatted_clauses<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = impl Display + 'a>
823 where
824 C: AstFormatter,
825 {
826 let trait_clauses = self.trait_clauses.iter().map(|x| x.to_string_with_ctx(ctx));
827 let types_outlive = self
828 .types_outlive
829 .iter()
830 .enumerate()
831 .map(|(i, x)| format!("TypeOutlives{i}: {}", x.fmt_as_for(ctx)));
832 let regions_outlive = self
833 .regions_outlive
834 .iter()
835 .enumerate()
836 .map(|(i, x)| format!("RegionOutlives{i}: {}", x.fmt_as_for(ctx)));
837 let type_constraints = self
838 .trait_type_constraints
839 .iter_enumerated()
840 .map(|(i, x)| format!("TypeConstraint{i}: {}", x.fmt_as_for(ctx)));
841 trait_clauses.map(Either::Left).chain(
842 types_outlive
843 .chain(regions_outlive)
844 .chain(type_constraints)
845 .map(Either::Right),
846 )
847 }
848
849 pub fn fmt_with_ctx_with_trait_clauses<C>(&self, ctx: &C) -> (String, String)
850 where
851 C: AstFormatter,
852 {
853 let tab = ctx.indent();
854 let params = if self.has_explicits() {
855 let params = self.formatted_params(ctx).format(", ");
856 format!("<{}>", params)
857 } else {
858 String::new()
859 };
860 let clauses = if self.has_predicates() {
861 let clauses = self
862 .formatted_clauses(ctx)
863 .map(|x| format!("\n{tab}{TAB_INCR}{x},"))
864 .format("");
865 format!("\n{tab}where{clauses}")
866 } else {
867 String::new()
868 };
869 (params, clauses)
870 }
871
872 pub fn fmt_with_ctx_single_line<C>(&self, ctx: &C) -> String
873 where
874 C: AstFormatter,
875 {
876 if self.is_empty() {
877 String::new()
878 } else {
879 let params = self
880 .formatted_params(ctx)
881 .map(Either::Left)
882 .chain(self.formatted_clauses(ctx).map(Either::Right))
883 .format(", ");
884 format!("<{}>", params)
885 }
886 }
887}
888
889impl_debug_via_display!(GenericParams);
890impl Display for GenericParams {
891 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
892 write!(f, "{}", self.fmt_with_ctx_single_line(&FmtCtx::new()))
893 }
894}
895
896impl<C: AstFormatter> FmtWithCtx<C> for GenericsSource {
897 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898 match self {
899 GenericsSource::Item(id) => write!(f, "{}", id.with_ctx(ctx)),
900 GenericsSource::Method(id, name) => write!(f, "{}::{name}", id.with_ctx(ctx)),
901 GenericsSource::TraitType(id, name) => {
902 write!(f, "{}::", id.with_ctx(ctx))?;
903 ctx.format_assoc_type_name(f, *id, *name)
904 }
905 GenericsSource::Builtin => write!(f, "<builtin>"),
906 GenericsSource::Other => write!(f, "<unknown>"),
907 }
908 }
909}
910
911impl<T> GExprBody<T> {
912 fn fmt_with_ctx_and_callback<C: AstFormatter>(
913 &self,
914 ctx: &C,
915 f: &mut fmt::Formatter<'_>,
916 fmt_body: impl FnOnce(
917 &mut fmt::Formatter<'_>,
918 &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
919 &T,
920 ) -> fmt::Result,
921 ) -> fmt::Result {
922 let ctx = &ctx.set_locals(&self.locals);
924 let ctx = &ctx.increase_indent();
925 let tab = ctx.indent();
926
927 for v in &self.locals.locals {
929 write!(f, "{tab}")?;
930 write!(f, "let {}: {};", v.index.with_ctx(ctx), v.ty.with_ctx(ctx))?;
931
932 write!(f, " // ")?;
933 if v.index.is_zero() {
934 write!(f, "return")?;
935 } else if self.locals.is_return_or_arg(v.index) {
936 write!(f, "arg #{}", v.index.index())?
937 } else {
938 match &v.name {
939 Some(_) => write!(f, "local")?,
940 None => write!(f, "anonymous local")?,
941 }
942 }
943 writeln!(f)?;
944 }
945
946 fmt_body(f, ctx, &self.body)?;
947
948 Ok(())
949 }
950}
951
952impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<llbc_ast::Block> {
953 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 fn fmt_body<C: AstFormatter>(
956 f: &mut fmt::Formatter<'_>,
957 ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
958 body: &Block,
959 ) -> Result<(), fmt::Error> {
960 writeln!(f)?;
961 body.fmt_with_ctx(ctx, f)?;
962 Ok(())
963 }
964 self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
965 }
966}
967impl<C: AstFormatter> FmtWithCtx<C> for GExprBody<ullbc_ast::BodyContents> {
968 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
969 fn fmt_body<C: AstFormatter>(
971 f: &mut fmt::Formatter<'_>,
972 ctx: &<<C as AstFormatter>::Reborrow<'_> as AstFormatter>::Reborrow<'_>,
973 body: &IndexVec<ullbc::BlockId, BlockData>,
974 ) -> Result<(), fmt::Error> {
975 let tab = ctx.indent();
976 let ctx = &ctx.increase_indent();
977 for (bid, block) in body.iter_enumerated() {
978 writeln!(f)?;
979 writeln!(f, "{tab}bb{}: {{", bid.index())?;
980 writeln!(f, "{}", block.with_ctx(ctx))?;
981 writeln!(f, "{tab}}}")?;
982 }
983 Ok(())
984 }
985 self.fmt_with_ctx_and_callback(ctx, f, fmt_body::<C>)
986 }
987}
988
989impl<C> FmtWithCtx<C> for GlobalDecl
990where
991 C: AstFormatter,
992{
993 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994 let keyword = match self.global_kind {
995 GlobalKind::Static => "static",
996 GlobalKind::ThreadLocal => "thread_local",
997 GlobalKind::AnonConst | GlobalKind::NamedConst => "const",
998 };
999 self.item_meta
1000 .fmt_item_intro(f, ctx, keyword, self.def_id)?;
1001
1002 let ctx = &ctx.set_generics(&self.generics);
1004
1005 let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
1007
1008 let ty = self.ty.with_ctx(ctx);
1010 write!(f, "{params}: {ty}")?;
1011
1012 write!(f, "{preds}")?;
1014 if self.generics.has_predicates() {
1015 writeln!(f)?;
1016 }
1017 write!(f, " ")?;
1018
1019 let value = self.value.with_ctx(ctx);
1021 write!(f, "= {value}")?;
1022
1023 Ok(())
1024 }
1025}
1026
1027impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclId {
1028 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1029 ItemId::from(*self).fmt_with_ctx(ctx, f)
1030 }
1031}
1032
1033impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclRef {
1034 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1035 let id = self.id.with_ctx(ctx);
1036 let generics = self.generics.with_ctx(ctx);
1037 write!(f, "{id}{generics}")
1038 }
1039}
1040
1041impl<C: AstFormatter> FmtWithCtx<C> for ImplElem {
1042 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043 write!(f, "{{")?;
1044 match self {
1045 ImplElem::Ty(bound_ty) => {
1046 let ctx = ctx.set_generics(&bound_ty.params);
1048 bound_ty.skip_binder.fmt_with_ctx(&ctx, f)?
1049 }
1050 ImplElem::Trait(impl_id) => {
1051 match ctx.get_crate().and_then(|tr| tr.trait_impls.get(*impl_id)) {
1052 None => write!(f, "impl#{impl_id}")?,
1053 Some(timpl) => {
1054 let ctx = &ctx.set_generics(&timpl.generics);
1057 let mut impl_trait = timpl.impl_trait.clone();
1058 match impl_trait
1059 .generics
1060 .types
1061 .remove_and_shift_ids(TypeVarId::ZERO)
1062 {
1063 Some(self_ty) => {
1064 let self_ty = self_ty.with_ctx(ctx);
1065 let impl_trait = impl_trait.with_ctx(ctx);
1066 write!(f, "impl {impl_trait} for {self_ty}")?;
1067 }
1068 None => {
1070 let impl_trait = impl_trait.with_ctx(ctx);
1071 write!(f, "impl {impl_trait}")?;
1072 }
1073 }
1074 }
1075 }
1076 }
1077 }
1078 write!(f, "}}")
1079 }
1080}
1081
1082impl Display for IntTy {
1083 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1084 match self {
1085 IntTy::Isize => write!(f, "isize"),
1086 IntTy::I8 => write!(f, "i8"),
1087 IntTy::I16 => write!(f, "i16"),
1088 IntTy::I32 => write!(f, "i32"),
1089 IntTy::I64 => write!(f, "i64"),
1090 IntTy::I128 => write!(f, "i128"),
1091 }
1092 }
1093}
1094
1095impl Display for UIntTy {
1096 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1097 match self {
1098 UIntTy::Usize => write!(f, "usize"),
1099 UIntTy::U8 => write!(f, "u8"),
1100 UIntTy::U16 => write!(f, "u16"),
1101 UIntTy::U32 => write!(f, "u32"),
1102 UIntTy::U64 => write!(f, "u64"),
1103 UIntTy::U128 => write!(f, "u128"),
1104 }
1105 }
1106}
1107
1108impl Display for IntegerTy {
1109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1110 match self {
1111 IntegerTy::Signed(int_ty) => write!(f, "{int_ty}"),
1112 IntegerTy::Unsigned(uint_ty) => write!(f, "{uint_ty}"),
1113 }
1114 }
1115}
1116
1117fn trait_impl_short_name<C: AstFormatter>(ctx: &C, impl_id: TraitImplId) -> Option<&Name> {
1118 ctx.get_crate()
1119 .and_then(|tr| tr.short_names.get(&ItemId::TraitImpl(impl_id)))
1120 .filter(|name| matches!(name.name.first(), Some(PathElem::Ident(..))))
1121}
1122
1123impl ItemMeta {
1124 pub fn fmt_item_intro<C: AstFormatter>(
1126 &self,
1127 f: &mut fmt::Formatter<'_>,
1128 ctx: &C,
1129 keyword: &str,
1130 id: impl Into<ItemId>,
1131 ) -> fmt::Result {
1132 let tab = ctx.indent();
1133 let id = id.into();
1134 let mut name = &self.name;
1135 let mut name_is_full = true;
1136 if let Some(tr) = ctx.get_crate()
1137 && let Some(short_name) = tr.short_names.get(&id)
1138 {
1139 name = short_name;
1140 name_is_full = false;
1141 } else if self
1142 .name
1143 .name
1144 .iter()
1145 .filter_map(|ne| ne.as_impl()?.as_trait())
1146 .any(|impl_id| trait_impl_short_name(ctx, *impl_id).is_some())
1147 {
1148 name_is_full = false;
1149 };
1150 if !name_is_full {
1151 writeln!(f, "// Full name: {}", self.name.full_name(ctx))?;
1152 }
1153
1154 for attr in &self.attr_info.attributes {
1155 if attr.is_doc_comment() {
1157 continue;
1158 }
1159 writeln!(f, "{tab}{}", attr.with_ctx(ctx))?;
1160 }
1161 if let Some(id) = &self.lang_item {
1162 writeln!(f, "{tab}#[lang_item({id:?})]")?;
1163 }
1164 if let Some(id) = &self.diagnostic_item {
1165 writeln!(f, "{tab}#[diagnostic_item(\"{id}\")]")?;
1166 }
1167 write!(f, "{tab}")?;
1168 if self.attr_info.public {
1169 write!(f, "pub ")?;
1170 }
1171 write!(f, "{keyword} {}", name.with_ctx(ctx))
1172 }
1173}
1174
1175impl_display_via_ctx!(InhabitedPredicate);
1176impl<C: AstFormatter> FmtWithCtx<C> for InhabitedPredicate {
1177 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1178 match self.kind() {
1179 InhabitedPredicateKind::True => write!(f, "true"),
1180 InhabitedPredicateKind::False => write!(f, "false"),
1181 InhabitedPredicateKind::ConstIsZero(value) => {
1182 write!(f, "{} == 0", value.with_ctx(ctx))
1183 }
1184 InhabitedPredicateKind::GenericType(ty) => {
1185 write!(f, "if_inhabited({})", ty.with_ctx(ctx))
1186 }
1187 InhabitedPredicateKind::And(predicates) => {
1188 write!(
1189 f,
1190 "({})",
1191 predicates.iter().map(|p| p.with_ctx(ctx)).format(" && ")
1192 )
1193 }
1194 InhabitedPredicateKind::Or(predicates) => {
1195 write!(
1196 f,
1197 "({})",
1198 predicates.iter().map(|p| p.with_ctx(ctx)).format(" || ")
1199 )
1200 }
1201 }
1202 }
1203}
1204
1205impl_display_via_ctx!(Layout);
1206impl<C: AstFormatter> FmtWithCtx<C> for Layout {
1207 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1208 let tab = ctx.indent();
1209 writeln!(f, "{tab}size: {},", self.size.with_ctx(ctx))?;
1210 writeln!(f, "{tab}align: {},", self.align.with_ctx(ctx))?;
1211 match &self.discriminator {
1212 Some(discriminator) => {
1213 writeln!(f, "{tab}discriminator: {},", discriminator.with_ctx(ctx))?
1214 }
1215 None => writeln!(f, "{tab}discriminator: none,")?,
1216 }
1217 writeln!(f, "{tab}inhabited: {},", self.inhabited.with_ctx(ctx))?;
1218 writeln!(f, "{tab}variants: [")?;
1219 let ctx1 = &ctx.increase_indent();
1220 let tab1 = ctx1.indent();
1221 for (variant_id, layout) in self.variant_layouts.iter_enumerated() {
1222 write!(f, "{tab1}")?;
1223 ctx1.format_current_variant_name(f, variant_id)?;
1224 write!(f, ": ")?;
1225 match layout {
1226 Some(layout) => writeln!(f, "{},", layout.with_ctx(&(ctx1, variant_id)))?,
1227 None => writeln!(f, "none,")?,
1228 }
1229 }
1230 writeln!(f, "{tab}],")?;
1231 write!(f, "{tab}{},", self.repr)
1232 }
1233}
1234
1235impl Display for ScalarTy {
1236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1237 match self {
1238 ScalarTy::Integer(ty) => write!(f, "{ty}"),
1239 ScalarTy::Float(ty) => write!(f, "{ty}"),
1240 ScalarTy::Char => write!(f, "char"),
1241 ScalarTy::Bool => write!(f, "bool"),
1242 }
1243 }
1244}
1245
1246impl Display for Loc {
1247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1248 write!(f, "{}:{}", self.line, self.col)
1249 }
1250}
1251
1252impl Display for Local {
1253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1254 if let Some(name) = &self.name {
1257 write!(f, "{name}")?
1258 }
1259 write!(f, "_{}", self.index)?;
1260 Ok(())
1261 }
1262}
1263
1264impl<C: AstFormatter> FmtWithCtx<C> for LocalId {
1265 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1266 ctx.format_local_id(f, *self)
1267 }
1268}
1269
1270impl Display for MetadataValue {
1271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1272 let name = match self {
1273 MetadataValue::DynSize => "dyn_size",
1274 MetadataValue::DynAlign => "dyn_align",
1275 MetadataValue::SliceLength => "slice_length",
1276 };
1277 write!(f, "{name}")
1278 }
1279}
1280
1281impl<C: AstFormatter> FmtWithCtx<C> for Name {
1282 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1283 let ctx = &ctx.no_generics();
1286 let name = self.name.iter().map(|x| x.with_ctx(ctx)).format("::");
1287 write!(f, "{}", name)
1288 }
1289}
1290
1291impl Name {
1292 fn full_name<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
1295 std::fmt::from_fn(move |f| {
1296 let ctx = &ctx.no_generics();
1297 let name = self
1298 .name
1299 .iter()
1300 .map(|elem| match elem {
1301 PathElem::Impl(impl_elem) => Either::Left(impl_elem.with_ctx(ctx)),
1302 _ => Either::Right(elem.with_ctx(ctx)),
1303 })
1304 .format("::");
1305 write!(f, "{name}")
1306 })
1307 }
1308}
1309
1310impl<C: AstFormatter> FmtWithCtx<C> for NullOp {
1311 fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1312 let op = match self {
1313 NullOp::UbChecks => "ub_checks",
1314 NullOp::OverflowChecks => "overflow_checks",
1315 NullOp::ContractChecks => "contract_checks",
1316 };
1317 write!(f, "{op}")
1318 }
1319}
1320
1321impl_display_via_ctx!(Operand);
1322impl<C: AstFormatter> FmtWithCtx<C> for Operand {
1323 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1324 match self {
1325 Operand::Copy(p) => write!(f, "copy {}", p.with_ctx(ctx)),
1326 Operand::Move(p) => write!(f, "move {}", p.with_ctx(ctx)),
1327 Operand::Const(c) => write!(f, "const {}", c.with_ctx(ctx)),
1328 }
1329 }
1330}
1331
1332impl<C: AstFormatter> FmtWithCtx<C> for OffsetExpr {
1333 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1334 match self.chosen {
1335 Some(chosen) => write!(f, "{chosen}")?,
1336 None => write!(f, "?")?,
1337 }
1338 if let Some(guarantee) = &self.guarantee {
1339 write!(f, " (guaranteed: {})", guarantee.with_ctx(ctx))?;
1340 }
1341 Ok(())
1342 }
1343}
1344
1345impl<C: AstFormatter> FmtWithCtx<C> for OffsetGuarantee {
1346 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1347 match self {
1348 OffsetGuarantee::AtOffsetZero => write!(f, "zero"),
1349 OffsetGuarantee::GuaranteedAlignment(align) => {
1350 write!(f, "aligned({})", align.with_ctx(ctx))
1351 }
1352 OffsetGuarantee::ReprCField { predecessor } => match predecessor {
1353 Some(predecessor) => write!(f, "repr_c_after({predecessor})"),
1354 None => write!(f, "repr_c_after_tag"),
1355 },
1356 }
1357 }
1358}
1359
1360impl<C: AstFormatter, T, U> FmtWithCtx<C> for OutlivesPred<T, U>
1361where
1362 T: FmtWithCtx<C>,
1363 U: FmtWithCtx<C>,
1364{
1365 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1366 write!(f, "{}: {}", self.0.with_ctx(ctx), self.1.with_ctx(ctx))
1367 }
1368}
1369
1370impl<C: AstFormatter> FmtWithCtx<C> for PathElem {
1371 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1372 match self {
1373 PathElem::Ident(s, d) => {
1374 write!(f, "{s}")?;
1375 if !d.is_zero() {
1376 write!(f, "#{}", d)?;
1377 }
1378 Ok(())
1379 }
1380 PathElem::Impl(impl_elem) => {
1381 if let ImplElem::Trait(impl_id) = impl_elem
1382 && let Some(short_name) = trait_impl_short_name(ctx, *impl_id)
1383 {
1384 return write!(f, "{}", short_name.with_ctx(ctx));
1385 }
1386 write!(f, "{}", impl_elem.with_ctx(ctx))
1387 }
1388 PathElem::Builtin(BuiltinPathElem::Tuple(n), _) => {
1389 let fields = std::iter::repeat_n("_", *n).format(", ");
1390 let trailing_comma = if *n == 1 { "," } else { "" };
1391 write!(f, "({fields}{trailing_comma})")
1392 }
1393 PathElem::Builtin(elem, d) => {
1394 if !elem.is_rust_name() {
1395 write!(f, "{{")?;
1396 }
1397 write!(f, "{}", elem.ident())?;
1398 if !d.is_zero() {
1399 write!(f, "#{d}")?;
1400 }
1401 if !elem.is_rust_name() {
1402 write!(f, "}}")?;
1403 }
1404 Ok(())
1405 }
1406 PathElem::Instantiated(binder) => {
1407 let underscore = "_".to_string();
1409 let params = GenericParams {
1410 regions: binder.params.regions.map_ref(|x| RegionParam {
1411 name: Some(underscore.clone()),
1412 ..*x
1413 }),
1414 types: binder.params.types.map_ref(|x| TypeParam {
1415 name: underscore.clone(),
1416 ..*x
1417 }),
1418 const_generics: binder.params.const_generics.map_ref(|x| ConstGenericParam {
1419 name: underscore.clone(),
1420 ty: x.ty.clone(),
1421 index: x.index,
1422 }),
1423 trait_clauses: binder.params.trait_clauses.clone(),
1424 ..GenericParams::empty()
1425 };
1426 let ctx = &ctx.push_binder(Cow::Owned(params));
1427 write!(
1428 f,
1429 "<{}>",
1430 binder.skip_binder.fmt_explicits(ctx).format(", ")
1431 )
1432 }
1433 PathElem::Target(target) => write!(f, "{target}"),
1434 }
1435 }
1436}
1437
1438impl_display_via_ctx!(Place);
1439impl<C: AstFormatter> FmtWithCtx<C> for Place {
1440 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1441 match &self.kind {
1442 PlaceKind::Local(var_id) => write!(f, "{}", var_id.with_ctx(ctx)),
1443 PlaceKind::Global(global_ref) => global_ref.fmt_with_ctx(ctx, f),
1444 PlaceKind::Projection(subplace, projection) => {
1445 let sub = subplace.with_ctx(ctx);
1446 match projection {
1447 ProjectionElem::Deref => write!(f, "(*{sub})"),
1448 ProjectionElem::Field(variant_id, field_id) => {
1449 let tref = subplace.ty().as_adt().unwrap();
1450 match variant_id {
1451 None => write!(f, "{sub}.")?,
1452 Some(variant_id) => {
1453 write!(f, "({sub} as variant ")?;
1454 ctx.format_enum_variant(f, tref.id, *variant_id)?;
1455 write!(f, ").")?;
1456 }
1457 }
1458 ctx.format_field_name(f, tref.id, *variant_id, *field_id)
1459 }
1460 ProjectionElem::PtrMetadata => write!(f, "{sub}.metadata"),
1461 ProjectionElem::Index {
1462 offset,
1463 from_end: true,
1464 ..
1465 } => write!(f, "{sub}[-{}]", offset.with_ctx(ctx)),
1466 ProjectionElem::Index {
1467 offset,
1468 from_end: false,
1469 ..
1470 } => write!(f, "{sub}[{}]", offset.with_ctx(ctx)),
1471 ProjectionElem::Subslice {
1472 from,
1473 to,
1474 from_end: true,
1475 ..
1476 } => write!(f, "{sub}[{}..-{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1477 ProjectionElem::Subslice {
1478 from,
1479 to,
1480 from_end: false,
1481 ..
1482 } => write!(f, "{sub}[{}..{}]", from.with_ctx(ctx), to.with_ctx(ctx)),
1483 }
1484 }
1485 }
1486 }
1487}
1488
1489impl<C: AstFormatter> FmtWithCtx<C> for PolyTraitDeclRef {
1490 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1491 write!(f, "{}", self.fmt_as_for(ctx))
1492 }
1493}
1494
1495impl PolyTraitDeclRef {
1496 fn fmt_trait_proof<'a, C: AstFormatter + 'a>(
1497 &'a self,
1498 id: TraitClauseId,
1499 value: Option<&'a TraitRef>,
1500 ctx: &'a C,
1501 ) -> impl Display + 'a {
1502 std::fmt::from_fn(move |f| {
1503 write!(
1504 f,
1505 "proof {}: {}",
1506 id.format_as_implied(),
1507 self.format_as_pred(ctx)
1508 )?;
1509 if let Some(value) = value {
1510 write!(f, " = {}", value.with_ctx(ctx))?;
1511 }
1512 Ok(())
1513 })
1514 }
1515
1516 fn format_as_pred<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
1517 std::fmt::from_fn(move |f| {
1518 let ctx = &ctx.push_bound_regions(&self.regions);
1519 if !self.regions.is_empty() {
1520 let regions = self.regions.iter().map(|r| r.with_ctx(ctx));
1521 write!(f, "for<{}> ", regions.format(", "))?;
1522 }
1523 write!(f, "({})", self.skip_binder.format_as_pred(ctx))
1524 })
1525 }
1526}
1527
1528impl<C: AstFormatter> FmtWithCtx<C> for Attribute {
1529 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1530 let mut attr = String::new();
1531 self.fmt_unindented(ctx, &mut attr)?;
1532 let sep = format!("\n{}", ctx.indent());
1533 write!(f, "{}", attr.lines().format(sep.as_str()))
1534 }
1535}
1536
1537impl Attribute {
1538 fn fmt_unindented<C: AstFormatter>(&self, ctx: &C, f: &mut impl fmt::Write) -> fmt::Result {
1539 match self {
1540 Attribute::Opaque => write!(f, "#[charon::opaque]"),
1541 Attribute::Exclude => write!(f, "#[charon::exclude]"),
1542 Attribute::Rename(name) => write!(f, "#[charon::rename(\"{name}\")]"),
1543 Attribute::VariantsPrefix(prefix) => {
1544 write!(f, "#[charon::variants_prefix(\"{prefix}\")]")
1545 }
1546 Attribute::VariantsSuffix(suffix) => {
1547 write!(f, "#[charon::variants_suffix(\"{suffix}\")]")
1548 }
1549 Attribute::Transparent => write!(f, "#[charon::transparent]"),
1550 Attribute::IsContract { kind, target } => {
1551 let target = target.with_ctx(ctx).to_string();
1552 write!(f, "#[charon::contract(kind = {kind:?}, for = {target:?})]")
1553 }
1554 Attribute::HasContract { kind, contract } => {
1555 let contract = ItemId::Fun(*contract);
1556 write!(
1557 f,
1558 "#[charon::has_contract(kind = {kind:?}, contract = {})]",
1559 contract.with_ctx(ctx)
1560 )
1561 }
1562 Attribute::DocComment(comment) => {
1563 write!(
1564 f,
1565 "{}",
1566 comment
1567 .lines()
1568 .map(|line| format!("///{line}"))
1569 .format("\n")
1570 )
1571 }
1572 Attribute::Builtin(kind) => write!(f, "#[{kind}]"),
1573 Attribute::Unknown(attr) => write!(f, "#[{attr}]"),
1574 }
1575 }
1576}
1577
1578impl Display for from_rustc::AttributeKind {
1580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1581 use from_rustc::AttributeKind;
1582 match self {
1583 AttributeKind::AutomaticallyDerived => write!(f, "automatically_derived"),
1584 AttributeKind::Cold => write!(f, "cold"),
1585 AttributeKind::Deprecated { deprecation, .. } => {
1586 write!(f, "deprecated")?;
1587 let since = match &deprecation.since {
1588 from_rustc::DeprecatedSince::RustcVersion(v) => {
1589 Some(format!("{}.{}.{}", v.major, v.minor, v.patch))
1590 }
1591 from_rustc::DeprecatedSince::Future => Some("future".to_owned()),
1592 from_rustc::DeprecatedSince::NonStandard(since) => Some(since.to_string()),
1593 from_rustc::DeprecatedSince::Unspecified | from_rustc::DeprecatedSince::Err => {
1594 None
1595 }
1596 };
1597 let since = since.map(|since| format!("since = \"{since}\""));
1598 let note = deprecation
1599 .note
1600 .as_ref()
1601 .map(|note| format!("note = \"{}\"", note.name));
1602 let args = since.into_iter().chain(note).format(", ").to_string();
1603 if !args.is_empty() {
1604 write!(f, "({args})")?;
1605 }
1606 Ok(())
1607 }
1608 AttributeKind::Fundamental => write!(f, "fundamental"),
1609 AttributeKind::Ignore { reason, .. } => {
1610 write!(f, "ignore")?;
1611 if let Some(reason) = reason {
1612 write!(f, " = \"{reason}\"")?;
1613 }
1614 Ok(())
1615 }
1616 AttributeKind::Inline(inline, _) => match inline {
1617 from_rustc::InlineAttr::None => write!(f, "inline"),
1618 from_rustc::InlineAttr::Hint => write!(f, "inline(hint)"),
1619 from_rustc::InlineAttr::Always => write!(f, "inline(always)"),
1620 from_rustc::InlineAttr::Never => write!(f, "inline(never)"),
1621 from_rustc::InlineAttr::Force { .. } => write!(f, "rustc_force_inline"),
1622 },
1623 AttributeKind::MayDangle(_) => write!(f, "may_dangle"),
1624 AttributeKind::Naked(_) => write!(f, "naked"),
1625 AttributeKind::NoLink => write!(f, "no_link"),
1626 AttributeKind::NoMangle(_) => write!(f, "no_mangle"),
1627 AttributeKind::NonExhaustive(_) => write!(f, "non_exhaustive"),
1628 AttributeKind::Optimize(optimize, _) => match optimize {
1629 from_rustc::OptimizeAttr::Default => write!(f, "optimize(default)"),
1630 from_rustc::OptimizeAttr::DoNotOptimize => write!(f, "optimize(none)"),
1631 from_rustc::OptimizeAttr::Speed => write!(f, "optimize(speed)"),
1632 from_rustc::OptimizeAttr::Size => write!(f, "optimize(size)"),
1633 },
1634 AttributeKind::RustcAlign { align, .. } => write!(f, "rustc_align({align})"),
1635 AttributeKind::RustcIntrinsic => write!(f, "rustc_intrinsic"),
1636 AttributeKind::RustcTestEntrypointMarker => write!(f, "rustc_test_entrypoint_marker"),
1637 AttributeKind::ShouldPanic { reason } => {
1638 write!(f, "should_panic")?;
1639 if let Some(reason) = reason {
1640 write!(f, "(expected = \"{reason}\")")?;
1641 }
1642 Ok(())
1643 }
1644 AttributeKind::TargetFeature { features, .. } => {
1645 let features = features.iter().map(|(feature, _)| feature).format(",");
1646 write!(f, "target_feature(enable = \"{features}\")")
1647 }
1648 AttributeKind::TrackCaller(_) => write!(f, "track_caller"),
1649 }
1650 }
1651}
1652
1653impl Display for RawAttribute {
1654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
1655 write!(f, "{}", self.path)?;
1656 if let Some(args) = &self.args {
1657 write!(f, "({args})")?;
1658 }
1659 Ok(())
1660 }
1661}
1662
1663impl<C: AstFormatter> FmtWithCtx<C> for Byte {
1664 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1665 match self {
1666 Byte::Value(x) => write!(f, "{:#04x}", x),
1667 Byte::Uninit => write!(f, "--"),
1668 Byte::Provenance(p, ofs) => write!(f, "{}[{}]", p.with_ctx(ctx), ofs),
1669 }
1670 }
1671}
1672
1673impl<C: AstFormatter> FmtWithCtx<C> for Provenance {
1674 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1675 match self {
1676 Provenance::Global(g) => write!(f, "&{}", g.with_ctx(ctx)),
1677 Provenance::Function(func) => write!(f, "&{}", func.with_ctx(ctx)),
1678 Provenance::Unknown => write!(f, "&?"),
1679 }
1680 }
1681}
1682
1683impl ConstantExpr {
1684 fn format_as_match_pattern<'a, C: AstFormatter + 'a>(
1685 &'a self,
1686 ctx: &'a C,
1687 ) -> impl Display + 'a {
1688 std::fmt::from_fn(move |f| match self.kind() {
1689 ConstantExprKind::Discriminant(type_ref, variant_id) => {
1690 ctx.format_enum_variant(f, type_ref.id, *variant_id)
1691 }
1692 _ => self.fmt_with_ctx(ctx, f),
1693 })
1694 }
1695}
1696
1697impl_display_via_ctx!(ConstantExpr);
1698impl<C: AstFormatter> FmtWithCtx<C> for ConstantExpr {
1699 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1700 match self.kind() {
1701 ConstantExprKind::Integer(v) => write!(f, "{v}"),
1702 ConstantExprKind::Float(v) => write!(f, "{v}"),
1703 ConstantExprKind::Bool(v) => write!(f, "{v}"),
1704 ConstantExprKind::Char(v) => write!(f, "'{}'", v.escape_debug()),
1705 ConstantExprKind::Str(v) => {
1706 write!(f, "\"{}\"", v.replace("\\", "\\\\").replace("\n", "\\n"))
1707 }
1708 ConstantExprKind::ByteStr(v) => write!(f, "{v:?}"),
1709 ConstantExprKind::Adt(variant_id, values) => {
1710 let values = values.iter().map(|v| v.with_ctx(ctx));
1711 let ty_ref = self.ty().as_adt().unwrap();
1712 if ty_ref.is_tuple() {
1713 let trailing_comma = if values.len() == 1 { "," } else { "" };
1714 let values = values.format(", ");
1715 write!(f, "({values}{trailing_comma})")
1716 } else {
1717 match variant_id {
1718 None => ty_ref.id.fmt_with_ctx(ctx, f)?,
1719 Some(variant_id) => ctx.format_enum_variant(f, ty_ref.id, *variant_id)?,
1720 }
1721 write!(f, " {{ ")?;
1722 for (comma, (i, val)) in repeat_except_first(", ").zip(values.enumerate()) {
1723 write!(f, "{}", comma.unwrap_or_default())?;
1724 let field_id = FieldId::new(i);
1725 ctx.format_field_name(f, ty_ref.id, *variant_id, field_id)?;
1726 write!(f, ": {}", val)?;
1727 }
1728 write!(f, " }}")
1729 }
1730 }
1731 ConstantExprKind::Array(values) => {
1732 let values = values.iter().map(|v| v.with_ctx(ctx)).format(", ");
1733 write!(f, "[{}]", values)
1734 }
1735 ConstantExprKind::Global(global_ref) => {
1736 write!(f, "{}", global_ref.with_ctx(ctx))
1737 }
1738 ConstantExprKind::TraitConst(trait_ref, const_id) => {
1739 write!(f, "{}::", trait_ref.with_ctx(ctx),)?;
1740 ctx.format_assoc_const_name(f, trait_ref.trait_id(), *const_id)?;
1741 Ok(())
1742 }
1743 ConstantExprKind::VTableRef(trait_ref) => {
1744 write!(f, "&vtable_of({})", trait_ref.with_ctx(ctx),)
1745 }
1746 ConstantExprKind::Discriminant(type_ref, variant_id) => {
1747 write!(f, "discriminant_of(")?;
1748 ctx.format_enum_variant(f, type_ref.id, *variant_id)?;
1749 write!(f, ")")
1750 }
1751 ConstantExprKind::Ref(cv, meta) => {
1752 if let Some(meta) = meta {
1753 write!(
1754 f,
1755 "&{} with_metadata({})",
1756 cv.with_ctx(ctx),
1757 meta.with_ctx(ctx)
1758 )
1759 } else {
1760 write!(f, "&{}", cv.with_ctx(ctx))
1761 }
1762 }
1763 ConstantExprKind::Ptr(rk, cv, meta) => {
1764 let rk = match rk {
1765 RefKind::Mut => "&raw mut",
1766 RefKind::Shared => "&raw const",
1767 };
1768 if let Some(meta) = meta {
1769 write!(
1770 f,
1771 "{} {} with_metadata({})",
1772 rk,
1773 cv.with_ctx(ctx),
1774 meta.with_ctx(ctx)
1775 )
1776 } else {
1777 write!(f, "{} {}", rk, cv.with_ctx(ctx))
1778 }
1779 }
1780 ConstantExprKind::Var(id) => write!(f, "{}", id.with_ctx(ctx)),
1781 ConstantExprKind::Call(fp, args) => {
1782 let args = args.iter().map(|arg| arg.with_ctx(ctx)).format(", ");
1783 write!(f, "{}({args})", fp.with_ctx(ctx))
1784 }
1785 ConstantExprKind::FnDef(fp) => {
1786 write!(f, "{}", fp.with_ctx(ctx))
1787 }
1788 ConstantExprKind::FnPtr(fp) => {
1789 write!(f, "fnptr({})", fp.with_ctx(ctx))
1790 }
1791 ConstantExprKind::TypeId(ty) => {
1792 write!(f, "TypeId({})", ty.with_ctx(ctx))
1793 }
1794 ConstantExprKind::SizeOf(ty) => {
1795 write!(f, "size_of::<{}>()", ty.with_ctx(ctx))
1796 }
1797 ConstantExprKind::AlignOf(ty) => {
1798 write!(f, "align_of::<{}>()", ty.with_ctx(ctx))
1799 }
1800 &ConstantExprKind::OffsetOf(ref ty, variant, field) => {
1801 write!(f, "offset_of({}.", ty.with_ctx(ctx))?;
1802 if let Some(variant) = variant {
1803 ctx.format_enum_variant_name(f, ty.id, variant)?;
1804 write!(f, ".")?;
1805 }
1806 ctx.format_field_name(f, ty.id, variant, field)?;
1807 write!(f, ")")
1808 }
1809 ConstantExprKind::PtrNoProvenance(v) => write!(f, "no-provenance {v}"),
1810 ConstantExprKind::RawMemory(bytes) => {
1811 let bytes = bytes.iter().map(|v| v.with_ctx(ctx)).format(", ");
1812 write!(f, "RawMemory({})", bytes)
1813 }
1814 ConstantExprKind::Opaque(cause) => write!(f, "Opaque({cause})"),
1815 }
1816 }
1817}
1818
1819impl Display for ReprOptions {
1820 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1821 let algorithm = match self.repr_algo {
1822 ReprAlgorithm::Rust => "Rust",
1823 ReprAlgorithm::C => "C",
1824 };
1825 write!(f, "repr({algorithm}")?;
1826 if let Some(modifier) = &self.align_modif {
1827 match modifier {
1828 AlignmentModifier::Align(align) => write!(f, ", align({align})")?,
1829 AlignmentModifier::Pack(pack) => write!(f, ", packed({pack})")?,
1830 }
1831 }
1832 if self.transparent {
1833 write!(f, ", transparent")?;
1834 }
1835 if let Some(int_ty) = self.explicit_discr_type {
1836 write!(f, ", discriminant {int_ty}")?;
1837 }
1838 write!(f, ")")
1839 }
1840}
1841
1842impl<C: AstFormatter> FmtWithCtx<C> for Size {
1843 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1844 match &self.chosen {
1845 Some(chosen) => write!(f, "{}", chosen.with_ctx(ctx))?,
1846 None => write!(f, "?")?,
1847 }
1848 if let Some(guarantee) = &self.guarantee {
1849 write!(f, " (guaranteed: {})", guarantee.with_ctx(ctx))?;
1850 }
1851 Ok(())
1852 }
1853}
1854
1855impl_display_via_ctx!(SizeExpr);
1856impl<C: AstFormatter> FmtWithCtx<C> for SizeExpr {
1857 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1858 match self.kind() {
1859 SizeExprKind::Constant(constant) => write!(f, "{}", constant.with_ctx(ctx)),
1860 SizeExprKind::FromMetadata(metadata) => write!(f, "{metadata}"),
1861 SizeExprKind::Max(values) => write!(
1862 f,
1863 "max({})",
1864 values.iter().map(|value| value.with_ctx(ctx)).format(", ")
1865 ),
1866 SizeExprKind::Min(values) => write!(
1867 f,
1868 "min({})",
1869 values.iter().map(|value| value.with_ctx(ctx)).format(", ")
1870 ),
1871 SizeExprKind::Plus(left, right) => {
1872 write!(f, "({} + {})", left.with_ctx(ctx), right.with_ctx(ctx))
1873 }
1874 SizeExprKind::Scale(base, multiplier) => {
1875 write!(f, "({} * {})", base.with_ctx(ctx), multiplier.with_ctx(ctx))
1876 }
1877 SizeExprKind::AtLeast(value) => write!(f, "at_least({})", value.with_ctx(ctx)),
1878 SizeExprKind::AlignTo { base, target_align } => write!(
1879 f,
1880 "align_to({}, {})",
1881 base.with_ctx(ctx),
1882 target_align.with_ctx(ctx)
1883 ),
1884 SizeExprKind::IfInhabited {
1885 ty,
1886 then_size,
1887 else_size,
1888 } => write!(
1889 f,
1890 "if_inhabited({}, {}, {})",
1891 ty.with_ctx(ctx),
1892 then_size.with_ctx(ctx),
1893 else_size.with_ctx(ctx)
1894 ),
1895 }
1896 }
1897}
1898
1899impl<C: AstFormatter> FmtWithCtx<C> for Region {
1900 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1901 match self {
1902 Region::Static => write!(f, "'static"),
1903 Region::Var(var) => write!(f, "{}", var.with_ctx(ctx)),
1904 Region::Body(id) => write!(f, "'{}", id),
1905 Region::Erased => write!(f, "'_"),
1906 }
1907 }
1908}
1909
1910impl<T> RegionBinder<T> {
1911 fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
1913 where
1914 C: AstFormatter,
1915 T: FmtWithCtx<C::Reborrow<'a>>,
1916 {
1917 self.fmt_split_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
1918 }
1919 fn fmt_split_with<'a, C>(
1921 &'a self,
1922 ctx: &'a C,
1923 fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
1924 ) -> (String, String)
1925 where
1926 C: AstFormatter,
1927 {
1928 let ctx = &ctx.push_bound_regions(&self.regions);
1929 (
1930 self.regions
1931 .iter()
1932 .map(|r| r.with_ctx(ctx))
1933 .format(", ")
1934 .to_string(),
1935 fmt_inner(ctx, &self.skip_binder),
1936 )
1937 }
1938
1939 fn fmt_as_for<'a, C>(&'a self, ctx: &'a C) -> String
1941 where
1942 C: AstFormatter,
1943 T: FmtWithCtx<C::Reborrow<'a>>,
1944 {
1945 self.fmt_as_for_with(ctx, |ctx, x| x.to_string_with_ctx(ctx))
1946 }
1947 fn fmt_as_for_with<'a, C>(
1949 &'a self,
1950 ctx: &'a C,
1951 fmt_inner: impl FnOnce(&C::Reborrow<'a>, &T) -> String,
1952 ) -> String
1953 where
1954 C: AstFormatter,
1955 T: FmtWithCtx<C::Reborrow<'a>>,
1956 {
1957 let (regions, value) = self.fmt_split_with(ctx, fmt_inner);
1958 let regions = if regions.is_empty() {
1959 "".to_string()
1960 } else {
1961 format!("for<{regions}> ",)
1962 };
1963 format!("{regions}{value}",)
1964 }
1965}
1966
1967impl<C: AstFormatter> FmtWithCtx<C> for RegionDbVar {
1968 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1969 ctx.format_bound_var(f, *self, "'_", |v| {
1970 v.name.as_ref().map(|name| name.to_string())
1971 })
1972 }
1973}
1974
1975impl<C: AstFormatter> FmtWithCtx<C> for RegionParam {
1976 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1977 if self.mutability.is_mutable() {
1978 write!(f, "mut ")?;
1979 }
1980 match &self.name {
1981 Some(name) => write!(f, "{name}"),
1982 None => {
1983 write!(f, "'_{}", self.index)?;
1984 if let Some(d @ 1..) = ctx.binder_depth().checked_sub(1) {
1985 write!(f, "_{d}")?;
1986 }
1987 Ok(())
1988 }
1989 }
1990 }
1991}
1992
1993impl_display_via_ctx!(Rvalue);
1994impl<C: AstFormatter> FmtWithCtx<C> for Rvalue {
1995 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1996 match self {
1997 Rvalue::Use(x, _) => write!(f, "{}", x.with_ctx(ctx)),
1998 Rvalue::Ref {
1999 place,
2000 kind: borrow_kind,
2001 ptr_metadata,
2002 } => {
2003 let borrow_kind = match borrow_kind {
2004 BorrowKind::Shared => "&",
2005 BorrowKind::Mut => "&mut ",
2006 BorrowKind::TwoPhaseMut => "&two-phase-mut ",
2007 BorrowKind::UniqueImmutable => "&uniq ",
2008 BorrowKind::Shallow => "&shallow ",
2009 };
2010 if ptr_metadata.ty().is_unit() {
2011 write!(f, "{borrow_kind}{}", place.with_ctx(ctx))?;
2013 } else {
2014 write!(
2015 f,
2016 "{borrow_kind}{} with_metadata({})",
2017 place.with_ctx(ctx),
2018 ptr_metadata.with_ctx(ctx)
2019 )?;
2020 }
2021 Ok(())
2022 }
2023 Rvalue::RawPtr {
2024 place,
2025 kind: mutability,
2026 ptr_metadata,
2027 } => {
2028 let ptr_kind = match mutability {
2029 RefKind::Shared => "&raw const ",
2030 RefKind::Mut => "&raw mut ",
2031 };
2032 if ptr_metadata.ty().is_unit() {
2033 write!(f, "{ptr_kind}{}", place.with_ctx(ctx))?;
2035 } else {
2036 write!(
2037 f,
2038 "{ptr_kind}{} with_metadata({})",
2039 place.with_ctx(ctx),
2040 ptr_metadata.with_ctx(ctx)
2041 )?;
2042 }
2043 Ok(())
2044 }
2045
2046 Rvalue::BinaryOp(binop, x, y) => {
2047 write!(f, "{} {} {}", x.with_ctx(ctx), binop, y.with_ctx(ctx))
2048 }
2049 Rvalue::UnaryOp(unop, x) => {
2050 write!(f, "{}({})", unop.with_ctx(ctx), x.with_ctx(ctx))
2051 }
2052 Rvalue::NullaryOp(op) => op.fmt_with_ctx(ctx, f),
2053 Rvalue::Discriminant(p) => {
2054 write!(f, "@discriminant({})", p.with_ctx(ctx),)
2055 }
2056 Rvalue::Aggregate(kind, ops) => {
2057 let ops_s = ops.iter().map(|op| op.with_ctx(ctx)).format(", ");
2058 match kind {
2059 AggregateKind::Adt(ty_ref, variant_id, field_id) => {
2060 if ty_ref.is_tuple() {
2061 let trailing_comma = if ops.len() == 1 { "," } else { "" };
2062 write!(f, "({ops_s}{trailing_comma})")
2063 } else {
2064 match variant_id {
2065 None => ty_ref.id.fmt_with_ctx(ctx, f)?,
2066 Some(variant_id) => {
2067 ctx.format_enum_variant(f, ty_ref.id, *variant_id)?
2068 }
2069 }
2070 write!(f, " {{ ")?;
2071 for (comma, (i, op)) in
2072 repeat_except_first(", ").zip(ops.iter().enumerate())
2073 {
2074 write!(f, "{}", comma.unwrap_or_default())?;
2075 let field_id = match *field_id {
2076 None => FieldId::new(i),
2077 Some(field_id) => {
2078 assert_eq!(i, 0); field_id
2080 }
2081 };
2082 ctx.format_field_name(f, ty_ref.id, *variant_id, field_id)?;
2083 write!(f, ": {}", op.with_ctx(ctx))?;
2084 }
2085 write!(f, " }}")
2086 }
2087 }
2088 AggregateKind::Array(..) => {
2089 write!(f, "[{}]", ops_s)
2090 }
2091 AggregateKind::RawPtr(_, rmut) => {
2092 let mutability = match rmut {
2093 RefKind::Shared => "const",
2094 RefKind::Mut => "mut ",
2095 };
2096 write!(f, "*{} ({})", mutability, ops_s)
2097 }
2098 }
2099 }
2100 Rvalue::Len(place, ..) => write!(f, "len({})", place.with_ctx(ctx)),
2101 Rvalue::Repeat(operand, _, len, _) => {
2102 write!(f, "[{}; {}]", operand.with_ctx(ctx), len.with_ctx(ctx))
2103 }
2104 }
2105 }
2106}
2107
2108impl Display for IntegerValue {
2109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
2110 match self {
2111 IntegerValue::Signed(ty, v) => write!(f, "{v}{ty}"),
2112 IntegerValue::Unsigned(ty, v) => write!(f, "{v}{ty}"),
2113 }
2114 }
2115}
2116
2117impl<C: AstFormatter> FmtWithCtx<C> for BorrowckStatement {
2118 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2119 match self {
2120 BorrowckStatement::FakeRead(place) => {
2121 write!(f, "fake_read({})", place.with_ctx(ctx))
2122 }
2123 BorrowckStatement::SetType {
2124 place,
2125 ty,
2126 variance,
2127 } => {
2128 let relation = match variance {
2129 Variance::Covariant => "<=",
2130 Variance::Contravariant => ">=",
2131 Variance::Invariant => "==",
2132 Variance::Bivariant => panic!("bivariant SetType statement"),
2133 Variance::Unknown => panic!("SetType statement with unknown variance"),
2134 };
2135 write!(
2136 f,
2137 "set_type(typeof({}) {relation} {})",
2138 place.with_ctx(ctx),
2139 ty.with_ctx(ctx)
2140 )
2141 }
2142 BorrowckStatement::SetOutlives(ty, region) => write!(
2143 f,
2144 "set_outlives({}, {})",
2145 ty.with_ctx(ctx),
2146 region.with_ctx(ctx)
2147 ),
2148 BorrowckStatement::PredicateHolds(predicate) => {
2149 write!(f, "predicate_holds({})", predicate.with_ctx(ctx))
2150 }
2151 }
2152 }
2153}
2154
2155impl<C: AstFormatter> FmtWithCtx<C> for ullbc::Statement {
2156 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2157 let tab = ctx.indent();
2158 use ullbc::StatementKind;
2159 if ctx.hide_storage_statements()
2160 && (self.kind.is_storage_live() || self.kind.is_storage_dead())
2161 {
2162 return Ok(());
2163 }
2164 for line in &self.comments_before {
2165 writeln!(f, "{tab}// {line}")?;
2166 }
2167 match &self.kind {
2168 StatementKind::Assign(place, rvalue) => {
2169 write!(f, "{tab}{} = {}", place.with_ctx(ctx), rvalue.with_ctx(ctx),)
2170 }
2171 StatementKind::Borrowck(statement) => {
2172 write!(f, "{tab}{}", statement.with_ctx(ctx))
2173 }
2174 StatementKind::SetDiscriminant(place, variant_id) => write!(
2175 f,
2176 "{tab}@discriminant({}) = {}",
2177 place.with_ctx(ctx),
2178 variant_id
2179 ),
2180 StatementKind::StorageLive(var_id) => {
2181 write!(f, "{tab}storage_live({})", var_id.with_ctx(ctx))
2182 }
2183 StatementKind::StorageDead(var_id) => {
2184 write!(f, "{tab}storage_dead({})", var_id.with_ctx(ctx))
2185 }
2186 StatementKind::PlaceMention(place) => {
2187 write!(f, "{tab}_ = {}", place.with_ctx(ctx))
2188 }
2189 StatementKind::Assert { assert, on_failure } => {
2190 write!(
2191 f,
2192 "{tab}{} else {}",
2193 assert.with_ctx(ctx),
2194 on_failure.with_ctx(ctx)
2195 )
2196 }
2197 StatementKind::Nop => write!(f, "{tab}nop"),
2198 }?;
2199 writeln!(f, ";")
2200 }
2201}
2202
2203impl<C: AstFormatter> FmtWithCtx<C> for llbc::Statement {
2204 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2205 let tab = ctx.indent();
2206 use llbc::StatementKind;
2207 if ctx.hide_storage_statements()
2208 && (self.kind.is_storage_live() || self.kind.is_storage_dead())
2209 {
2210 return Ok(());
2211 }
2212 for line in &self.comments_before {
2213 writeln!(f, "{tab}// {line}")?;
2214 }
2215 if self.kind.is_nop() {
2216 return Ok(());
2217 }
2218 write!(f, "{tab}")?;
2219 match &self.kind {
2220 StatementKind::Assign(place, rvalue) => {
2221 write!(f, "{} = {}", place.with_ctx(ctx), rvalue.with_ctx(ctx),)
2222 }
2223 StatementKind::Borrowck(statement) => write!(f, "{}", statement.with_ctx(ctx)),
2224 StatementKind::SetDiscriminant(place, variant_id) => {
2225 write!(f, "@discriminant({}) = {}", place.with_ctx(ctx), variant_id)
2226 }
2227 StatementKind::StorageLive(var_id) => {
2228 write!(f, "storage_live({})", var_id.with_ctx(ctx))
2229 }
2230 StatementKind::StorageDead(var_id) => {
2231 write!(f, "storage_dead({})", var_id.with_ctx(ctx))
2232 }
2233 StatementKind::PlaceMention(place) => {
2234 write!(f, "_ = {}", place.with_ctx(ctx))
2235 }
2236 StatementKind::Drop {
2237 place,
2238 fn_ptr,
2239 kind,
2240 on_unwind,
2241 } => {
2242 let kind = match kind {
2243 DropKind::Precise => "drop",
2244 DropKind::Conditional => "conditional_drop",
2245 };
2246 write!(
2247 f,
2248 "{kind}[{}] {}",
2249 fn_ptr.with_ctx(ctx),
2250 place.with_ctx(ctx),
2251 )?;
2252 fmt_llbc_unwind_block(ctx, f, on_unwind)
2253 }
2254 StatementKind::Assert {
2255 assert,
2256 on_failure,
2257 on_unwind,
2258 } => {
2259 write!(
2260 f,
2261 "{} else {}",
2262 assert.with_ctx(ctx),
2263 on_failure.with_ctx(ctx)
2264 )?;
2265 fmt_llbc_unwind_block(ctx, f, on_unwind)
2266 }
2267 StatementKind::InlineAsm {
2268 asm,
2269 targets,
2270 on_unwind,
2271 } => {
2272 write!(f, "asm!({asm:?})")?;
2273 if !targets.is_empty() {
2274 write!(f, " {{")?;
2275 let ctx1 = &ctx.increase_indent();
2276 for (i, target) in targets.iter().enumerate() {
2277 let tab = ctx1.indent();
2278 let ctx = &ctx1.increase_indent();
2279 write!(
2280 f,
2281 "\n{tab}target {i} => {{\n{}{tab}}}",
2282 target.with_ctx(ctx)
2283 )?;
2284 }
2285 write!(f, "\n{tab}}}")?;
2286 }
2287 fmt_llbc_unwind_block(ctx, f, on_unwind)?;
2288 Ok(())
2289 }
2290 StatementKind::Call { call, on_unwind } => {
2291 write!(f, "{}", call.with_ctx(ctx))?;
2292 fmt_llbc_unwind_block(ctx, f, on_unwind)
2293 }
2294 StatementKind::Abort(kind) => {
2295 write!(f, "{}", kind.with_ctx(ctx))
2296 }
2297 StatementKind::Return => write!(f, "return"),
2298 StatementKind::UnwindResume => write!(f, "unwind_continue"),
2299 StatementKind::Break(index) => write!(f, "break {index}"),
2300 StatementKind::Continue(index) => write!(f, "continue {index}"),
2301 StatementKind::Switch { data, branches } => match &data.scrutinee {
2302 SwitchScrutinee::Value(discr)
2303 if let Some((then_branch, else_branch)) = data.as_if() =>
2304 {
2305 let true_st = &branches[then_branch];
2306 let false_st = &branches[else_branch];
2307 let ctx = &ctx.increase_indent();
2308 write!(
2309 f,
2310 "if {} {{\n{}{tab}}} else {{\n{}{tab}}}",
2311 discr.with_ctx(ctx),
2312 true_st.with_ctx(ctx),
2313 false_st.with_ctx(ctx),
2314 )
2315 }
2316 SwitchScrutinee::Value(discr) => {
2317 writeln!(f, "switch {} {{", discr.with_ctx(ctx))?;
2318 let ctx1 = &ctx.increase_indent();
2319 let inner_tab1 = ctx1.indent();
2320 let ctx2 = &ctx1.increase_indent();
2321 let cases_by_branch = data.group_by_branch();
2322 for (branch_id, st) in branches.iter_enumerated() {
2323 let cases = &cases_by_branch[branch_id];
2324 let cases = if cases.is_empty() && data.fallback != Some(branch_id) {
2325 "_".to_owned()
2326 } else {
2327 cases
2328 .iter()
2329 .map(|value| value.to_string_with_ctx(ctx))
2330 .chain((data.fallback == Some(branch_id)).then_some("_".to_owned()))
2331 .format(" | ")
2332 .to_string()
2333 };
2334 writeln!(
2335 f,
2336 "{inner_tab1}{} => {{\n{}{inner_tab1}}},",
2337 cases,
2338 st.with_ctx(ctx2),
2339 )?;
2340 }
2341 write!(f, "{tab}}}")
2342 }
2343 SwitchScrutinee::Discriminant(discr) => {
2344 writeln!(f, "match {} {{", discr.with_ctx(ctx))?;
2345 let ctx1 = &ctx.increase_indent();
2346 let inner_tab1 = ctx1.indent();
2347 let ctx2 = &ctx1.increase_indent();
2348 let cases_by_branch = data.group_by_branch();
2349 for (branch_id, st) in branches.iter_enumerated() {
2350 let cases = &cases_by_branch[branch_id];
2351 let cases = if cases.is_empty() && data.fallback != Some(branch_id) {
2352 "_".to_owned()
2353 } else {
2354 cases
2355 .iter()
2356 .map(|value| value.format_as_match_pattern(ctx).to_string())
2357 .chain((data.fallback == Some(branch_id)).then_some("_".to_owned()))
2358 .format(" | ")
2359 .to_string()
2360 };
2361 writeln!(
2362 f,
2363 "{inner_tab1}{cases} => {{\n{}{inner_tab1}}},",
2364 st.with_ctx(ctx2),
2365 )?;
2366 }
2367 write!(f, "{tab}}}")
2368 }
2369 },
2370 StatementKind::Loop(body) => {
2371 let ctx = &ctx.increase_indent();
2372 write!(f, "loop {{\n{}{tab}}}", body.with_ctx(ctx))
2373 }
2374 StatementKind::Error(s) => write!(f, "@ERROR({})", s),
2375 StatementKind::Nop => unreachable!(),
2376 }?;
2377 writeln!(f)
2378 }
2379}
2380
2381impl<C: AstFormatter> FmtWithCtx<C> for SwitchScrutinee {
2382 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2383 match self {
2384 SwitchScrutinee::Value(operand) => operand.fmt_with_ctx(ctx, f),
2385 SwitchScrutinee::Discriminant(place) => place.fmt_with_ctx(ctx, f),
2386 }
2387 }
2388}
2389
2390impl<C: AstFormatter> FmtWithCtx<C> for Terminator {
2391 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2392 let tab = ctx.indent();
2393 for line in &self.comments_before {
2394 writeln!(f, "{tab}// {line}")?;
2395 }
2396 write!(f, "{tab}")?;
2397 match &self.kind {
2398 TerminatorKind::Goto { target } => write!(f, "goto bb{target}"),
2399 TerminatorKind::Switch { data, branches } => {
2400 if let Some((then_branch, else_branch)) = data.as_if() {
2401 let true_block = branches[then_branch];
2402 let false_block = branches[else_branch];
2403 write!(
2404 f,
2405 "if {} -> bb{} else -> bb{}",
2406 data.scrutinee.with_ctx(ctx),
2407 true_block,
2408 false_block
2409 )
2410 } else {
2411 let maps = data
2412 .branches
2413 .iter()
2414 .map(|(value, branch_id)| {
2415 format!(
2416 "{}: bb{}",
2417 value.format_as_match_pattern(ctx),
2418 branches[*branch_id]
2419 )
2420 })
2421 .chain(
2422 data.fallback
2423 .map(|branch_id| format!("otherwise: bb{}", branches[branch_id])),
2424 )
2425 .format(", ");
2426 match &data.scrutinee {
2427 SwitchScrutinee::Value(discr) => {
2428 write!(f, "switch {} -> {}", discr.with_ctx(ctx), maps)
2429 }
2430 SwitchScrutinee::Discriminant(place) => {
2431 write!(f, "match {} -> {}", place.with_ctx(ctx), maps)
2432 }
2433 }
2434 }
2435 }
2436 TerminatorKind::Call {
2437 call,
2438 target,
2439 on_unwind,
2440 } => {
2441 let call = call.with_ctx(ctx);
2442 write!(f, "{call} -> bb{target} (unwind: bb{on_unwind})",)
2443 }
2444 TerminatorKind::Drop {
2445 kind,
2446 place,
2447 fn_ptr,
2448 target,
2449 on_unwind,
2450 } => {
2451 let kind = match kind {
2452 DropKind::Precise => "drop",
2453 DropKind::Conditional => "conditional_drop",
2454 };
2455 write!(
2456 f,
2457 "{kind}[{}] {} -> bb{target} (unwind: bb{on_unwind})",
2458 fn_ptr.with_ctx(ctx),
2459 place.with_ctx(ctx),
2460 )
2461 }
2462 TerminatorKind::Assert {
2463 assert,
2464 target,
2465 on_unwind,
2466 } => {
2467 write!(
2468 f,
2469 "assert {} -> bb{target} (unwind: bb{on_unwind})",
2470 assert.with_ctx(ctx),
2471 )
2472 }
2473 TerminatorKind::InlineAsm {
2474 asm,
2475 targets,
2476 on_unwind,
2477 } => {
2478 let targets = targets
2479 .iter()
2480 .enumerate()
2481 .map(|(i, target)| format!("target {i}: bb{target}"))
2482 .chain([format!("unwind: bb{on_unwind}")])
2483 .format(", ");
2484 write!(f, "asm!({asm:?}) -> {targets}")
2485 }
2486 TerminatorKind::Abort(kind) => write!(f, "{}", kind.with_ctx(ctx)),
2487 TerminatorKind::Return => write!(f, "return"),
2488 TerminatorKind::UnwindResume => write!(f, "unwind_continue"),
2489 }
2490 }
2491}
2492
2493impl<C: AstFormatter> FmtWithCtx<C> for TraitParam {
2494 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2495 write!(f, "{}", self.clause_id.format_as_required())?;
2496 if let Some(d @ 1..) = ctx.binder_depth().checked_sub(1) {
2497 write!(f, "_{d}")?;
2498 }
2499 write!(f, ": {}", self.trait_.format_as_pred(ctx))
2500 }
2501}
2502
2503impl TraitClauseId {
2504 pub(crate) fn format_as_implied(self) -> impl Display {
2505 std::fmt::from_fn(move |f| write!(f, "ImpliedClause{self}"))
2506 }
2507
2508 pub(crate) fn format_as_required(self) -> impl Display {
2509 std::fmt::from_fn(move |f| write!(f, "TraitClause{self}"))
2510 }
2511}
2512
2513impl<C: AstFormatter> FmtWithCtx<C> for TraitDecl {
2514 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2515 let ctx = &ctx.set_generics(&self.generics);
2517
2518 self.item_meta
2519 .fmt_item_intro(f, ctx, "trait", self.def_id)?;
2520
2521 let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2522 write!(f, "{generics}{clauses}")?;
2523
2524 let any_item = !self.implied_clauses.is_empty()
2525 || !self.consts.is_empty()
2526 || !self.types.is_empty()
2527 || !self.methods.is_empty();
2528 if any_item {
2529 write!(f, "\n{{\n")?;
2530 for c in &self.implied_clauses {
2531 writeln!(
2532 f,
2533 "{TAB_INCR}{}",
2534 c.trait_.fmt_trait_proof(c.clause_id, None, ctx)
2535 )?;
2536 }
2537 for assoc_const in &self.consts {
2538 let name = &assoc_const.name;
2539 let ty = assoc_const.ty.with_ctx(ctx);
2540 writeln!(f, "{TAB_INCR}const {name} : {ty}")?;
2541 }
2542 for assoc_ty in &self.types {
2543 let name = assoc_ty.name();
2544 let ctx = &ctx.push_binder(Cow::Borrowed(&assoc_ty.params));
2545 let clauses = assoc_ty
2546 .params
2547 .formatted_clauses(ctx)
2548 .map(|x| x.to_string())
2549 .chain(assoc_ty.skip_binder.implied_clauses.iter().map(|clause| {
2550 clause
2551 .trait_
2552 .fmt_trait_proof(clause.clause_id, None, ctx)
2553 .to_string()
2554 }));
2555 let params = if assoc_ty.params.has_explicits() {
2556 format!("<{}>", assoc_ty.params.formatted_params(ctx).format(", "))
2557 } else {
2558 String::new()
2559 };
2560 write!(f, "{TAB_INCR}type {name}{params}")?;
2561 if let Some(default) = &assoc_ty.skip_binder.default {
2562 write!(f, " = {}", default.value.with_ctx(ctx))?;
2563 }
2564 write!(f, "{}", fmt_where_clauses(clauses, TAB_INCR))?;
2565 writeln!(f)?;
2566 }
2567 for method in self.methods() {
2568 for attr in &method.skip_binder.item_meta.attr_info.attributes {
2569 if !attr.is_doc_comment() {
2570 writeln!(f, "{TAB_INCR}{}", attr.with_ctx(ctx))?;
2571 }
2572 }
2573 let name = method.name();
2574 let (params, method) =
2575 method.fmt_split_with(ctx, |ctx, method| match &method.default {
2576 Some(fn_ref) => format!(" = {}", fn_ref.to_string_with_ctx(ctx)),
2577 None => format!(";"),
2578 });
2579 writeln!(f, "{TAB_INCR}fn {name}{params}{method}")?;
2580 }
2581 if let Some(vtb_ref) = &self.vtable {
2582 writeln!(f, "{TAB_INCR}vtable: {}", vtb_ref.with_ctx(ctx))?;
2583 } else {
2584 writeln!(f, "{TAB_INCR}non-dyn-compatible")?;
2585 }
2586 write!(f, "}}")?;
2587 }
2588 Ok(())
2589 }
2590}
2591
2592impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclId {
2593 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2594 ItemId::from(*self).fmt_with_ctx(ctx, f)
2595 }
2596}
2597
2598impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclRef {
2599 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2600 let trait_id = self.id.with_ctx(ctx);
2601 let generics = self.generics.with_ctx(ctx);
2602 write!(f, "{trait_id}{generics}")
2603 }
2604}
2605
2606impl TraitDeclRef {
2607 pub fn split_self(&self) -> (Option<Ty>, Self) {
2610 let mut pred = self.clone();
2611 let self_ty = pred.generics.types.remove_and_shift_ids(TypeVarId::ZERO);
2612 (self_ty, pred)
2613 }
2614
2615 fn format_as_pred<'a, C: AstFormatter + 'a>(&'a self, ctx: &'a C) -> impl Display + 'a {
2616 std::fmt::from_fn(move |f| {
2617 let (self_ty, pred) = self.split_self();
2618 match self_ty {
2619 Some(self_ty) => write!(f, "{}: {}", self_ty.with_ctx(ctx), pred.with_ctx(ctx)),
2620 None => write!(f, "{}", pred.with_ctx(ctx)),
2622 }
2623 })
2624 }
2625
2626 fn format_as_impl<'a, C: AstFormatter>(&'a self, ctx: &'a C) -> impl Display + 'a {
2627 std::fmt::from_fn(move |f| {
2628 let (self_ty, pred) = self.split_self();
2629 match self_ty {
2630 Some(self_ty) => write!(f, "{} for {}", pred.with_ctx(ctx), self_ty.with_ctx(ctx)),
2631 None => write!(f, "{}", pred.with_ctx(ctx)),
2633 }
2634 })
2635 }
2636}
2637
2638impl<C: AstFormatter> FmtWithCtx<C> for TraitImpl {
2639 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2640 let trait_id = self.impl_trait.id;
2641 writeln!(f, "// Full name: {}", self.item_meta.name.full_name(ctx))?;
2642
2643 let ctx = &ctx.set_generics(&self.generics);
2645
2646 let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2647 let impl_trait = self.impl_trait.format_as_impl(ctx);
2648 write!(f, "impl{generics}")?;
2649 if let Some(short_name) = trait_impl_short_name(ctx, self.def_id) {
2650 write!(f, " \"{}\"", short_name.with_ctx(ctx))?;
2651 }
2652 write!(f, " {impl_trait}{clauses}",)?;
2653
2654 let newline = if clauses.is_empty() {
2655 " ".to_string()
2656 } else {
2657 "\n".to_string()
2658 };
2659 writeln!(f, "{newline}{{")?;
2660
2661 let any_item = !self.implied_trait_refs.is_empty()
2662 || !self.consts.is_empty()
2663 || !self.types.is_empty()
2664 || !self.methods.is_empty();
2665 if any_item {
2666 for (id, trait_ref) in self.implied_trait_refs.iter_enumerated() {
2667 writeln!(
2668 f,
2669 "{TAB_INCR}{}",
2670 trait_ref
2671 .trait_decl_ref
2672 .fmt_trait_proof(id, Some(trait_ref), ctx)
2673 )?;
2674 }
2675 for (const_id, global) in self.consts.iter_enumerated() {
2676 write!(f, "{TAB_INCR}const ")?;
2677 ctx.format_assoc_const_name(f, trait_id, const_id)?;
2678 writeln!(f, " = {}", global.with_ctx(ctx))?;
2679 }
2680 for (type_id, assoc_ty) in self.types.iter_enumerated() {
2681 let ctx = &ctx.push_binder(Cow::Borrowed(&assoc_ty.params));
2682 let params = if assoc_ty.params.has_explicits() {
2683 format!("<{}>", assoc_ty.params.formatted_params(ctx).format(", "))
2684 } else {
2685 String::new()
2686 };
2687 let ty = assoc_ty.skip_binder.value.with_ctx(ctx);
2688 let clauses = assoc_ty
2689 .params
2690 .formatted_clauses(ctx)
2691 .map(|x| x.to_string())
2692 .chain(
2693 assoc_ty
2694 .skip_binder
2695 .implied_trait_refs
2696 .iter_enumerated()
2697 .map(|(id, trait_ref)| {
2698 trait_ref
2699 .trait_decl_ref
2700 .fmt_trait_proof(id, Some(trait_ref), ctx)
2701 .to_string()
2702 }),
2703 );
2704 write!(f, "{TAB_INCR}type ")?;
2705 ctx.format_assoc_type_name(f, trait_id, type_id)?;
2706 write!(f, "{params} = {ty}")?;
2707 write!(f, "{}", fmt_where_clauses(clauses, TAB_INCR))?;
2708 writeln!(f)?;
2709 }
2710 for (method_id, bound_fn) in self.methods.iter_enumerated() {
2711 let (params, fn_ref) = bound_fn.fmt_split(ctx);
2712 write!(f, "{TAB_INCR}fn ")?;
2713 ctx.format_method_name(f, trait_id, method_id)?;
2714 writeln!(f, "{params} = {fn_ref}")?;
2715 }
2716 }
2717 if let Some(vtb_ref) = &self.vtable {
2718 writeln!(f, "{TAB_INCR}vtable: {}", vtb_ref.with_ctx(ctx))?;
2719 } else {
2720 writeln!(f, "{TAB_INCR}non-dyn-compatible")?;
2721 }
2722 write!(f, "}}")?;
2723 Ok(())
2724 }
2725}
2726
2727impl<C: AstFormatter> FmtWithCtx<C> for TraitImplId {
2728 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2729 ItemId::from(*self).fmt_with_ctx(ctx, f)
2730 }
2731}
2732
2733impl<C: AstFormatter> FmtWithCtx<C> for TraitImplRef {
2734 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2735 let id = self.id.with_ctx(ctx);
2736 let generics = self.generics.with_ctx(ctx);
2737 write!(f, "{id}{generics}")
2738 }
2739}
2740
2741impl Display for TraitItemName {
2742 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
2743 write!(f, "{}", self.0)
2744 }
2745}
2746
2747impl<C: AstFormatter> FmtWithCtx<C> for TraitRef {
2748 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2749 match &self.kind {
2750 TraitRefKind::SelfId => write!(f, "Self"),
2751 TraitRefKind::ParentClause(sub, clause_id) => {
2752 let sub = sub.with_ctx(ctx);
2753 write!(f, "{sub}::{}", clause_id.format_as_implied())
2754 }
2755 TraitRefKind::ItemClause(sub, type_id, clause_id) => {
2756 write!(f, "{}::", sub.with_ctx(ctx))?;
2757 ctx.format_assoc_type_name(f, sub.trait_id(), *type_id)?;
2758 write!(f, "::{}", clause_id.format_as_implied())
2759 }
2760 TraitRefKind::TraitImpl(impl_ref) => {
2761 write!(f, "{}", impl_ref.with_ctx(ctx))
2762 }
2763 TraitRefKind::Clause(id) => write!(f, "{}", id.with_ctx(ctx)),
2764 TraitRefKind::BuiltinOrAuto { types, .. } => {
2765 let bound_ctx = &ctx.push_bound_regions(&self.trait_decl_ref.regions);
2766 let impl_trait = self.trait_decl_ref.skip_binder.format_as_impl(bound_ctx);
2767 write!(f, "{{built_in impl {impl_trait}")?;
2768 if !types.is_empty() {
2769 let trait_id = self.trait_decl_ref.skip_binder.id;
2770 let types = types
2771 .iter_indexed()
2772 .map(|(type_id, assoc_ty)| {
2773 std::fmt::from_fn(move |f| {
2774 ctx.format_assoc_type_name(f, trait_id, type_id)?;
2775 let ty = assoc_ty.value.with_ctx(ctx);
2776 write!(f, " = {ty}")
2777 })
2778 })
2779 .join(", ");
2780 write!(f, " where {types}")?;
2781 }
2782 write!(f, "}}")?;
2783 Ok(())
2784 }
2785 TraitRefKind::Dyn => write!(f, "{}", self.trait_decl_ref.with_ctx(ctx)),
2786 TraitRefKind::Unknown(msg) => write!(f, "UNKNOWN({msg})"),
2787 }
2788 }
2789}
2790
2791impl<C: AstFormatter> FmtWithCtx<C> for TraitTypeConstraint {
2792 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2793 let trait_ref = self.trait_ref.with_ctx(ctx);
2794 let ty = self.ty.with_ctx(ctx);
2795 write!(f, "{trait_ref}::")?;
2796 ctx.format_assoc_type_name(f, self.trait_ref.trait_id(), self.type_id)?;
2797 write!(f, " = {ty}")
2798 }
2799}
2800
2801impl<C: AstFormatter> FmtWithCtx<C> for Ty {
2802 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2803 match self.kind() {
2804 TyKind::Adt(tref)
2806 if tref.is_tuple()
2807 && let Some(krate) = ctx.get_crate() =>
2808 {
2809 let fields = self.as_tuple_fields(krate);
2810 let trailing_comma = if fields.len() == 1 { "," } else { "" };
2811 let fields = fields.iter().map(|ty| ty.with_ctx(ctx)).format(", ");
2812 write!(f, "({fields}{trailing_comma})",)
2813 }
2814 TyKind::Adt(tref) if tref.is_str() => write!(f, "str"),
2815 TyKind::Adt(tref) => write!(f, "{}", tref.with_ctx(ctx)),
2816 TyKind::TypeVar(id) => write!(f, "{}", id.with_ctx(ctx)),
2817 TyKind::Scalar(kind) => write!(f, "{kind}"),
2818 TyKind::Never => write!(f, "!"),
2819 TyKind::Pattern(ty, pat) => write!(f, "{} is {}", ty.with_ctx(ctx), pat.with_ctx(ctx)),
2820 TyKind::Ref(r, ty, kind) => {
2821 write!(f, "&{} ", r.with_ctx(ctx))?;
2822 if let RefKind::Mut = kind {
2823 write!(f, "mut ")?;
2824 }
2825 write!(f, "{}", ty.with_ctx(ctx))
2826 }
2827 TyKind::RawPtr(ty, kind) => {
2828 write!(f, "*")?;
2829 match kind {
2830 RefKind::Shared => write!(f, "const")?,
2831 RefKind::Mut => write!(f, "mut")?,
2832 }
2833 write!(f, " {}", ty.with_ctx(ctx))
2834 }
2835 TyKind::Array(ty, len, _) => {
2836 write!(f, "[{}; {}]", ty.with_ctx(ctx), len.with_ctx(ctx))
2837 }
2838 TyKind::Slice(ty, _) => {
2839 write!(f, "[{}]", ty.with_ctx(ctx))
2840 }
2841 TyKind::TraitType(trait_ref, type_id, generics) => {
2842 write!(f, "{}::", trait_ref.with_ctx(ctx))?;
2843 ctx.format_assoc_type_name(f, trait_ref.trait_id(), *type_id)?;
2844 write!(f, "{}", generics.with_ctx(ctx))
2845 }
2846 TyKind::DynTrait(pred) => {
2847 write!(f, "(dyn {})", pred.with_ctx(ctx))
2848 }
2849 TyKind::FnPtr(io) => {
2850 write!(f, "{}", io.with_ctx(ctx))
2851 }
2852 TyKind::FnDef(binder) => {
2853 let (regions, value) = binder.fmt_split(ctx);
2854 if !regions.is_empty() {
2855 write!(f, "for<{regions}> ",)?
2856 };
2857 write!(f, "{value}",)
2858 }
2859 TyKind::PtrMetadata(ty) => {
2860 write!(f, "PtrMetadata<{}>", ty.with_ctx(ctx))
2861 }
2862 TyKind::Error(msg) => write!(f, "type_error(\"{msg}\")"),
2863 }
2864 }
2865}
2866
2867impl<C: AstFormatter> FmtWithCtx<C> for TypePattern {
2868 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2869 match self {
2870 TypePattern::Range(start, end) => {
2871 write!(f, "{}..={}", start.with_ctx(ctx), end.with_ctx(ctx))
2872 }
2873 TypePattern::OrPattern(patterns) => {
2874 write!(
2875 f,
2876 "({})",
2877 patterns.iter().map(|pat| pat.with_ctx(ctx)).format(" | ")
2878 )
2879 }
2880 TypePattern::NotNull => write!(f, "!null"),
2881 }
2882 }
2883}
2884
2885impl<C: AstFormatter> FmtWithCtx<C> for TypeDbVar {
2886 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2887 ctx.format_bound_var(f, *self, "@Type", |v| Some(v.name.clone()))
2888 }
2889}
2890
2891impl<C: AstFormatter> FmtWithCtx<C> for TypeDecl {
2892 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2893 let keyword = match &self.kind {
2894 TypeDeclKind::Struct(..) => "struct",
2895 TypeDeclKind::Union(..) => "union",
2896 TypeDeclKind::Enum(..) => "enum",
2897 TypeDeclKind::Alias(..) => "type",
2898 TypeDeclKind::Opaque | TypeDeclKind::Error(..) => "opaque type",
2899 };
2900 self.item_meta
2901 .fmt_item_intro(f, ctx, keyword, self.def_id)?;
2902
2903 let ctx = &ctx.set_generics(&self.generics);
2904 let ctx = &ctx.set_current_type(self.def_id);
2905 let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx);
2906 write!(f, "{params}{preds}")?;
2907
2908 let nl_or_space = if !self.generics.has_predicates() {
2909 " ".to_string()
2910 } else {
2911 "\n".to_string()
2912 };
2913 match &self.kind {
2914 TypeDeclKind::Struct(fields) => {
2915 write!(f, "{nl_or_space}{{")?;
2916 if !fields.is_empty() {
2917 writeln!(f)?;
2918 for field in fields {
2919 writeln!(f, " {},", field.with_ctx(ctx))?;
2920 }
2921 }
2922 write!(f, "}}")
2923 }
2924 TypeDeclKind::Union(fields) => {
2925 write!(f, "{nl_or_space}{{")?;
2926 writeln!(f)?;
2927 for field in fields {
2928 writeln!(f, " {},", field.with_ctx(ctx))?;
2929 }
2930 write!(f, "}}")
2931 }
2932 TypeDeclKind::Enum(variants) => {
2933 write!(f, "{nl_or_space}{{")?;
2934 writeln!(f)?;
2935 for variant in variants {
2936 writeln!(f, " {},", variant.with_ctx(ctx))?;
2937 }
2938 write!(f, "}}")
2939 }
2940 TypeDeclKind::Alias(ty) => write!(f, " = {}", ty.with_ctx(ctx)),
2941 TypeDeclKind::Opaque => write!(f, ""),
2942 TypeDeclKind::Error(msg) => write!(f, " = ERROR({msg})"),
2943 }?;
2944
2945 if ctx.include_layouts() {
2946 let layout_type_id = match &self.kind {
2947 TypeDeclKind::Alias(ty) => ty.as_adt().map(|tref| tref.id).unwrap_or(self.def_id),
2948 _ => self.def_id,
2949 };
2950 let ctx = &ctx.set_current_type(layout_type_id);
2951 let fmt_layout =
2952 |f: &mut fmt::Formatter<'_>, heading: &str, layout: &Layout| -> fmt::Result {
2953 write!(f, "// {heading}:")?;
2954 let ctx = &ctx.increase_indent();
2955 for line in layout.to_string_with_ctx(ctx).lines() {
2956 write!(f, "\n// {line}")?;
2957 }
2958 Ok(())
2959 };
2960 match self.layout.len() {
2961 0 => write!(f, "\n// layout: none")?,
2962 1 => {
2963 let layout = self.layout.values().next().unwrap();
2964 writeln!(f)?;
2965 fmt_layout(f, "layout", layout)?;
2966 }
2967 _ => {
2968 let mut separator = "\n";
2969 for (target, layout) in &self.layout {
2970 write!(f, "{separator}")?;
2971 fmt_layout(f, &format!("layout for target `{target}`"), layout)?;
2972 separator = "\n\n";
2973 }
2974 }
2975 }
2976 }
2977
2978 Ok(())
2979 }
2980}
2981
2982impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclId {
2983 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2984 ItemId::from(*self).fmt_with_ctx(ctx, f)
2985 }
2986}
2987
2988impl<C: AstFormatter> FmtWithCtx<C> for TypeDeclRef {
2989 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2990 let id = self.id.with_ctx(ctx);
2991 let generics = self.generics.with_ctx(ctx);
2992 write!(f, "{id}{generics}")
2993 }
2994}
2995
2996impl<C: AstFormatter> FmtWithCtx<C> for TypeParam {
2997 fn fmt_with_ctx(&self, _ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2998 write!(f, "{}", self.name)
2999 }
3000}
3001
3002impl<C: AstFormatter> FmtWithCtx<C> for UnOp {
3003 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3004 match self {
3005 UnOp::Not => write!(f, "~"),
3006 UnOp::Neg(mode) => write!(f, "{}.-", mode),
3007 UnOp::Cast(kind) => write!(f, "{}", kind.with_ctx(ctx)),
3008 }
3009 }
3010}
3011
3012impl_display_via_ctx!(Variant);
3013impl<C: AstFormatter> FmtWithCtx<C> for Variant {
3014 fn fmt_with_ctx(&self, ctx: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3015 write!(f, "{}", self.name)?;
3016 if !self.fields.is_empty() {
3017 let fields = self.fields.iter().map(|f| f.with_ctx(ctx)).format(", ");
3018 write!(f, " {{ {} }}", fields)?;
3019 }
3020 Ok(())
3021 }
3022}
3023
3024impl<C: AstFormatter> FmtWithCtx<(&C, VariantId)> for VariantLayout {
3025 fn fmt_with_ctx(
3026 &self,
3027 &(ctx, variant_id): &(&C, VariantId),
3028 f: &mut fmt::Formatter<'_>,
3029 ) -> fmt::Result {
3030 writeln!(f, "{{")?;
3031 let tab = ctx.indent();
3032 let ctx1 = &ctx.increase_indent();
3033 let tab1 = ctx1.indent();
3034 for (field_id, offset) in self.field_offsets.iter_enumerated() {
3035 write!(f, "{tab1}offset of ")?;
3036 ctx1.format_current_field_name(f, variant_id, field_id)?;
3037 writeln!(f, ": {},", offset.with_ctx(ctx1))?;
3038 }
3039 let tagger = self
3040 .tagger
3041 .iter()
3042 .map(|(offset, value)| format!("{offset} := {value}"))
3043 .format(", ");
3044 writeln!(f, "{tab1}inhabited: {},", self.inhabited.with_ctx(ctx1))?;
3045 writeln!(f, "{tab1}tagger: [{tagger}],")?;
3046 write!(f, "{tab}}}")
3047 }
3048}