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