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