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