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