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