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