1use crate::{
3 common::TAB_INCR,
4 formatter::*,
5 gast,
6 ids::Vector,
7 llbc_ast::{self as llbc, *},
8 reorder_decls::*,
9 ullbc_ast::{self as ullbc, *},
10};
11use itertools::Itertools;
12use std::{
13 borrow::Cow,
14 fmt::{self, Debug, Display, Write},
15};
16
17pub trait FmtWithCtx<C> {
19 fn fmt_with_ctx(&self, ctx: &C) -> String {
20 self.fmt_with_ctx_and_indent("", ctx)
22 }
23
24 fn fmt_with_ctx_and_indent(&self, _tab: &str, _ctx: &C) -> String {
25 panic!("This type does not know how to be formatted with indent")
26 }
27
28 fn with_ctx<'a>(&'a self, ctx: &'a C) -> impl std::fmt::Display + 'a {
33 pub struct WithCtx<'a, C, T: ?Sized> {
34 val: &'a T,
35 ctx: &'a C,
36 }
37
38 impl<'a, C, T: ?Sized> std::fmt::Display for WithCtx<'a, C, T>
39 where
40 T: FmtWithCtx<C>,
41 {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 let s = self.val.fmt_with_ctx(self.ctx);
44 f.write_str(&s)
45 }
46 }
47
48 WithCtx { val: self, ctx }
49 }
50}
51
52impl<C: AstFormatter> FmtWithCtx<C> for AbortKind {
53 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
54 match self {
55 AbortKind::Panic(name) => {
56 let name = if let Some(name) = name {
57 format!("({})", name.fmt_with_ctx(ctx))
58 } else {
59 format!("")
60 };
61 format!("{tab}panic{name}")
62 }
63 AbortKind::UndefinedBehavior => format!("{tab}undefined_behavior"),
64 }
65 }
66}
67
68impl<C: AstFormatter> FmtWithCtx<C> for AnyTransItem<'_> {
69 fn fmt_with_ctx(&self, ctx: &C) -> String {
70 match self {
71 AnyTransItem::Type(d) => d.fmt_with_ctx(ctx),
72 AnyTransItem::Fun(d) => d.fmt_with_ctx(ctx),
73 AnyTransItem::Global(d) => d.fmt_with_ctx(ctx),
74 AnyTransItem::TraitDecl(d) => d.fmt_with_ctx(ctx),
75 AnyTransItem::TraitImpl(d) => d.fmt_with_ctx(ctx),
76 }
77 }
78}
79
80impl<C: AstFormatter> FmtWithCtx<C> for Assert {
81 fn fmt_with_ctx(&self, ctx: &C) -> String {
82 format!(
83 "assert({} == {})",
84 self.cond.fmt_with_ctx(ctx),
85 self.expected,
86 )
87 }
88}
89
90impl<T> Binder<T> {
91 fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
94 where
95 C: AstFormatter,
96 T: FmtWithCtx<<C as PushBinder<'a>>::C>,
97 {
98 let ctx = &ctx.push_binder(Cow::Borrowed(&self.params));
99 (
100 self.params.fmt_with_ctx_single_line(ctx),
101 self.skip_binder.fmt_with_ctx(ctx),
102 )
103 }
104}
105
106impl<C: AstFormatter> FmtWithCtx<C> for llbc::Block {
107 fn fmt_with_ctx(&self, ctx: &C) -> String {
108 self.fmt_with_ctx_and_indent(TAB_INCR, ctx)
110 }
111
112 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
113 self.statements
114 .iter()
115 .map(|st| st.fmt_with_ctx_and_indent(tab, ctx))
116 .map(|st| format!("{st}\n"))
117 .join("")
118 }
119}
120
121impl<C: AstFormatter> FmtWithCtx<C> for ullbc::BlockData {
122 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
123 let mut out: Vec<String> = Vec::new();
124
125 for statement in &self.statements {
127 out.push(format!("{};\n", statement.fmt_with_ctx_and_indent(tab, ctx)).to_string());
128 }
129
130 out.push(format!(
132 "{};",
133 self.terminator.fmt_with_ctx_and_indent(tab, ctx)
134 ));
135
136 out.join("")
138 }
139}
140
141impl<C: AstFormatter> FmtWithCtx<C> for gast::Body {
142 fn fmt_with_ctx(&self, ctx: &C) -> String {
143 match self {
144 Body::Unstructured(b) => b.fmt_with_ctx(ctx),
145 Body::Structured(b) => b.fmt_with_ctx(ctx),
146 }
147 }
148
149 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
150 match self {
151 Body::Unstructured(b) => b.fmt_with_ctx_and_indent(tab, ctx),
152 Body::Structured(b) => b.fmt_with_ctx_and_indent(tab, ctx),
153 }
154 }
155}
156
157impl<C: AstFormatter> FmtWithCtx<C> for CastKind {
158 fn fmt_with_ctx(&self, ctx: &C) -> String {
159 match self {
160 CastKind::Scalar(src, tgt) => format!("cast<{src}, {tgt}>"),
161 CastKind::FnPtr(src, tgt) | CastKind::RawPtr(src, tgt) => {
162 format!("cast<{}, {}>", src.fmt_with_ctx(ctx), tgt.fmt_with_ctx(ctx))
163 }
164 CastKind::Unsize(src, tgt) => {
165 format!(
166 "unsize_cast<{}, {}>",
167 src.fmt_with_ctx(ctx),
168 tgt.fmt_with_ctx(ctx)
169 )
170 }
171 CastKind::Transmute(src, tgt) => {
172 format!(
173 "transmute<{}, {}>",
174 src.fmt_with_ctx(ctx),
175 tgt.fmt_with_ctx(ctx)
176 )
177 }
178 }
179 }
180}
181
182impl<C: AstFormatter> FmtWithCtx<C> for ConstantExpr {
183 fn fmt_with_ctx(&self, ctx: &C) -> String {
184 self.value.fmt_with_ctx(ctx)
185 }
186}
187
188impl<C: AstFormatter> FmtWithCtx<C> for ConstGeneric {
189 fn fmt_with_ctx(&self, ctx: &C) -> String {
190 match self {
191 ConstGeneric::Var(id) => ctx.format_object(*id),
192 ConstGeneric::Value(v) => v.to_string(),
193 ConstGeneric::Global(id) => ctx.format_object(*id),
194 }
195 }
196}
197
198impl<C: AstFormatter> FmtWithCtx<C> for ConstGenericVar {
199 fn fmt_with_ctx(&self, ctx: &C) -> String {
200 let ty = self.ty.fmt_with_ctx(ctx);
201 format!("const {} : {}", self.name, ty)
202 }
203}
204
205impl<C: AstFormatter> FmtWithCtx<C> for DeclarationGroup {
206 fn fmt_with_ctx(&self, ctx: &C) -> String {
207 use DeclarationGroup::*;
208 match self {
209 Type(g) => format!("Type decls group: {}", g.fmt_with_ctx(ctx)),
210 Fun(g) => format!("Fun decls group: {}", g.fmt_with_ctx(ctx)),
211 Global(g) => format!("Global decls group: {}", g.fmt_with_ctx(ctx)),
212 TraitDecl(g) => format!("Trait decls group: {}", g.fmt_with_ctx(ctx)),
213 TraitImpl(g) => format!("Trait impls group: {}", g.fmt_with_ctx(ctx)),
214 Mixed(g) => format!("Mixed group: {}", g.fmt_with_ctx(ctx)),
215 }
216 }
217}
218
219impl<C: AstFormatter> FmtWithCtx<C> for ExistentialPredicate {
220 fn fmt_with_ctx(&self, _ctx: &C) -> String {
221 format!("exists(TODO)")
222 }
223}
224
225impl<C: AstFormatter> FmtWithCtx<C> for Field {
226 fn fmt_with_ctx(&self, ctx: &C) -> String {
227 match &self.name {
228 Some(name) => format!("{}: {}", name, self.ty.fmt_with_ctx(ctx)),
229 None => self.ty.fmt_with_ctx(ctx),
230 }
231 }
232}
233
234impl<C: AstFormatter> FmtWithCtx<C> for FnOperand {
235 fn fmt_with_ctx(&self, ctx: &C) -> String {
236 match self {
237 FnOperand::Regular(func) => func.fmt_with_ctx(ctx),
238 FnOperand::Move(p) => format!("(move {})", p.fmt_with_ctx(ctx)),
239 }
240 }
241}
242
243impl<C: AstFormatter> FmtWithCtx<C> for FnPtr {
244 fn fmt_with_ctx(&self, ctx: &C) -> String {
245 let generics = self.generics.fmt_with_ctx(ctx);
246 let f = match &self.func {
247 FunIdOrTraitMethodRef::Fun(FunId::Regular(def_id)) => {
248 format!("{}", ctx.format_object(*def_id),)
249 }
250 FunIdOrTraitMethodRef::Fun(FunId::Builtin(builtin)) => {
251 format!("@{}", builtin)
252 }
253 FunIdOrTraitMethodRef::Trait(trait_ref, method_id, _) => {
254 format!("{}::{}", trait_ref.fmt_with_ctx(ctx), &method_id.0)
255 }
256 };
257 format!("{}{}", f, generics)
258 }
259}
260
261impl<C: AstFormatter> FmtWithCtx<C> for FunSig {
262 fn fmt_with_ctx(&self, ctx: &C) -> String {
263 let ctx = &ctx.set_generics(&self.generics);
264
265 let unsafe_kw = if self.is_unsafe {
267 "unsafe ".to_string()
268 } else {
269 "".to_string()
270 };
271
272 let (params, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx, "");
274
275 let mut args: Vec<String> = Vec::new();
277 for ty in &self.inputs {
278 args.push(ty.fmt_with_ctx(ctx).to_string());
279 }
280 let args = args.join(", ");
281
282 let ret_ty = &self.output;
284 let ret_ty = if ret_ty.is_unit() {
285 "".to_string()
286 } else {
287 format!(" -> {}", ret_ty.fmt_with_ctx(ctx))
288 };
289
290 format!("{unsafe_kw}fn{params}({args}){ret_ty}{clauses}",)
292 }
293}
294
295impl<Id: Copy, C: AstFormatter + Formatter<Id>> FmtWithCtx<C> for GDeclarationGroup<Id> {
296 fn fmt_with_ctx(&self, ctx: &C) -> String {
297 use GDeclarationGroup::*;
298 match self {
299 NonRec(id) => format!("Non rec: {}", ctx.format_object(*id)),
300 Rec(ids) => {
301 let ids = ids
302 .iter()
303 .map(|id| ctx.format_object(*id))
304 .collect::<Vec<String>>()
305 .join(", ");
306 format!("Rec: {}", ids)
307 }
308 }
309 }
310}
311
312impl GenericArgs {
313 pub(crate) fn fmt_with_ctx_no_brackets<C>(&self, ctx: &C) -> String
314 where
315 C: AstFormatter,
316 {
317 assert!(self.trait_refs.is_empty());
318 let mut params = Vec::new();
319 let GenericArgs {
320 regions,
321 types,
322 const_generics,
323 trait_refs: _,
324 target: _,
325 } = self;
326 for x in regions {
327 params.push(x.fmt_with_ctx(ctx));
328 }
329 for x in types {
330 params.push(x.fmt_with_ctx(ctx));
331 }
332 for x in const_generics {
333 params.push(x.fmt_with_ctx(ctx));
334 }
335 params.join(", ")
336 }
337
338 pub fn fmt_with_ctx_split_trait_refs<C>(&self, ctx: &C) -> String
339 where
340 C: AstFormatter,
341 {
342 let mut params = Vec::new();
343 let GenericArgs {
344 regions,
345 types,
346 const_generics,
347 trait_refs,
348 target: _,
349 } = self;
350 for x in regions {
351 params.push(x.fmt_with_ctx(ctx));
352 }
353 for x in types {
354 params.push(x.fmt_with_ctx(ctx));
355 }
356 for x in const_generics {
357 params.push(x.fmt_with_ctx(ctx));
358 }
359 let params = if params.is_empty() {
360 "".to_string()
361 } else {
362 format!("<{}>", params.join(", "))
363 };
364
365 let mut clauses = Vec::new();
366 for x in trait_refs {
367 clauses.push(x.fmt_with_ctx(ctx));
368 }
369 let clauses = if clauses.is_empty() {
370 "".to_string()
371 } else {
372 format!("[{}]", clauses.join(", "))
373 };
374 format!("{params}{clauses}")
375 }
376}
377
378impl<C: AstFormatter> FmtWithCtx<C> for GenericArgs {
379 fn fmt_with_ctx(&self, ctx: &C) -> String {
380 self.fmt_with_ctx_split_trait_refs(ctx)
381 }
382}
383
384impl GenericParams {
385 fn format_params<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = String> + use<'a, C>
386 where
387 C: AstFormatter,
388 {
389 let regions = self.regions.iter().map(|x| x.fmt_with_ctx(ctx));
390 let types = self.types.iter().map(|x| x.fmt_with_ctx(ctx));
391 let const_generics = self.const_generics.iter().map(|x| x.fmt_with_ctx(ctx));
392 regions.chain(types).chain(const_generics)
393 }
394
395 fn format_clauses<'a, C>(&'a self, ctx: &'a C) -> impl Iterator<Item = String> + use<'a, C>
396 where
397 C: AstFormatter,
398 {
399 let trait_clauses = self.trait_clauses.iter().map(|x| x.fmt_with_ctx(ctx));
400 let types_outlive = self.types_outlive.iter().map(|x| x.fmt_as_for(ctx));
401 let regions_outlive = self.regions_outlive.iter().map(|x| x.fmt_as_for(ctx));
402 let type_constraints = self
403 .trait_type_constraints
404 .iter()
405 .map(|x| x.fmt_as_for(ctx));
406 trait_clauses
407 .chain(types_outlive)
408 .chain(regions_outlive)
409 .chain(type_constraints)
410 }
411
412 pub fn fmt_with_ctx_with_trait_clauses<C>(&self, ctx: &C, tab: &str) -> (String, String)
413 where
414 C: AstFormatter,
415 {
416 let params = self.format_params(ctx).join(", ");
417 let params = if params.is_empty() {
418 String::new()
419 } else {
420 format!("<{}>", params)
421 };
422 let clauses = self
423 .format_clauses(ctx)
424 .map(|x| format!("\n{tab}{TAB_INCR}{x},"))
425 .join("");
426 let clauses = if clauses.is_empty() {
427 String::new()
428 } else {
429 format!("\n{tab}where{clauses}")
430 };
431 (params, clauses)
432 }
433
434 pub fn fmt_with_ctx_single_line<C>(&self, ctx: &C) -> String
435 where
436 C: AstFormatter,
437 {
438 let params = self
439 .format_params(ctx)
440 .chain(self.format_clauses(ctx))
441 .join(", ");
442 if params.is_empty() {
443 String::new()
444 } else {
445 format!("<{}>", params)
446 }
447 }
448}
449
450impl<T, C> FmtWithCtx<C> for GExprBody<T>
451where
452 C: for<'a> SetLocals<'a>,
453 for<'a> <C as SetLocals<'a>>::C: AstFormatter,
454 for<'a, 'b> <C as SetLocals<'a>>::C: AstFormatter + Formatter<&'b T>,
455{
456 fn fmt_with_ctx(&self, ctx: &C) -> String {
457 self.fmt_with_ctx_and_indent(TAB_INCR, ctx)
459 }
460
461 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
462 let ctx = &ctx.set_locals(&self.locals);
464
465 let mut locals: Vec<String> = Vec::new();
467 for v in &self.locals.locals {
468 let index = v.index.index();
469 let comment = if index == 0 {
470 "// return".to_string()
471 } else if index <= self.locals.arg_count {
472 format!("// arg #{index}").to_string()
473 } else {
474 match &v.name {
475 Some(_) => "// local".to_string(),
476 None => "// anonymous local".to_string(),
477 }
478 };
479
480 let var_id = v.index.to_pretty_string();
481 let var_name = match &v.name {
482 Some(name) => format!("{name}{var_id}"),
483 None => var_id,
484 };
485
486 locals.push(
487 format!(
488 "{tab}let {var_name}: {}; {comment}\n",
489 v.ty.fmt_with_ctx(ctx),
490 )
491 .to_string(),
492 );
493 }
494
495 let mut locals = locals.join("");
496 locals.push('\n');
497
498 let body = ctx.format_object(&self.body);
501
502 let mut out = locals;
504 out.push_str(&body);
505 out
506 }
507}
508
509impl<C> FmtWithCtx<C> for FunDecl
510where
511 C: AstFormatter,
512 C: for<'a> SetGenerics<'a>,
514 for<'a> <C as SetGenerics<'a>>::C: AstFormatter,
515 for<'a, 'b> <C as SetGenerics<'a>>::C: SetLocals<'b>,
517 for<'a, 'b> <<C as SetGenerics<'a>>::C as SetLocals<'b>>::C: AstFormatter,
518{
519 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
520 let keyword = if self.signature.is_unsafe {
521 "unsafe fn"
522 } else {
523 "fn"
524 };
525 let intro = self.item_meta.fmt_item_intro(ctx, tab, keyword);
526
527 let ctx = &ctx.set_generics(&self.signature.generics);
529
530 let (params, preds) = self
532 .signature
533 .generics
534 .fmt_with_ctx_with_trait_clauses(ctx, tab);
535
536 let mut args: Vec<String> = Vec::new();
538 for i in 0..self.signature.inputs.len() {
539 let id = LocalId::new(i + 1);
541 let arg_ty = &self.signature.inputs.get(i).unwrap();
542 args.push(
543 format!("{}: {}", id.to_pretty_string(), arg_ty.fmt_with_ctx(ctx)).to_string(),
544 );
545 }
546 let args = args.join(", ");
547
548 let ret_ty = &self.signature.output;
550 let ret_ty = if ret_ty.is_unit() {
551 "".to_string()
552 } else {
553 format!(" -> {}", ret_ty.fmt_with_ctx(ctx))
554 };
555
556 let body = match &self.body {
558 Ok(body) => {
559 let body = body.fmt_with_ctx(ctx);
560 format!("\n{tab}{{\n{body}{tab}}}")
561 }
562 Err(Opaque) => String::new(),
563 };
564
565 format!("{intro}{params}({args}){ret_ty}{preds}{body}",)
567 }
568}
569
570impl<C: AstFormatter> FmtWithCtx<C> for FunDeclRef {
571 fn fmt_with_ctx(&self, ctx: &C) -> String {
572 let id = ctx.format_object(self.id);
573 let generics = self.generics.fmt_with_ctx(ctx);
574 format!("{id}{generics}")
575 }
576}
577
578impl<C> FmtWithCtx<C> for GlobalDecl
579where
580 C: AstFormatter,
581 C: for<'a> SetLocals<'a>,
582 for<'a> <C as SetGenerics<'a>>::C: AstFormatter,
583 for<'a, 'b> <<C as SetGenerics<'a>>::C as SetLocals<'b>>::C: AstFormatter,
584 for<'a, 'b, 'c> <<C as SetGenerics<'a>>::C as SetLocals<'b>>::C: AstFormatter,
585{
586 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
587 let keyword = match self.global_kind {
588 GlobalKind::Static => "static",
589 GlobalKind::AnonConst | GlobalKind::NamedConst => "const",
590 };
591 let intro = self.item_meta.fmt_item_intro(ctx, tab, keyword);
592
593 let ctx = &ctx.set_generics(&self.generics);
595
596 let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx, " ");
598 let ty = self.ty.fmt_with_ctx(ctx);
600 let eq_space = if !self.generics.has_predicates() {
602 " ".to_string()
603 } else {
604 "\n ".to_string()
605 };
606
607 let initializer = ctx.format_object(self.init);
609
610 format!("{intro}{params}: {ty}{preds}{eq_space}= {initializer}()")
612 }
613}
614
615impl<C: AstFormatter> FmtWithCtx<C> for GlobalDeclRef {
616 fn fmt_with_ctx(&self, ctx: &C) -> String {
617 let id = ctx.format_object(self.id);
618 let generics = self.generics.fmt_with_ctx(ctx);
619 format!("{id}{generics}")
620 }
621}
622
623impl<C: AstFormatter> FmtWithCtx<C> for ImplElem {
624 fn fmt_with_ctx(&self, ctx: &C) -> String {
625 ctx.format_object(self)
626 }
627}
628
629impl ItemMeta {
630 pub fn fmt_item_intro<C>(&self, ctx: &C, tab: &str, keyword: &str) -> String
632 where
633 C: AstFormatter,
634 {
635 let name = self.name.fmt_with_ctx(ctx);
636 let vis = if self.attr_info.public { "pub " } else { "" };
637 let lang_item = self
638 .lang_item
639 .as_ref()
640 .map(|id| format!("{tab}#[lang_item(\"{id}\")]\n"))
641 .unwrap_or_default();
642 format!("{lang_item}{tab}{vis}{keyword} {name}")
643 }
644}
645
646impl<C: AstFormatter> FmtWithCtx<C> for LiteralTy {
647 fn fmt_with_ctx(&self, _ctx: &C) -> String {
648 match self {
649 LiteralTy::Integer(ty) => ty.to_string(),
650 LiteralTy::Float(ty) => ty.to_string(),
651 LiteralTy::Char => "char".to_owned(),
652 LiteralTy::Bool => "bool".to_owned(),
653 }
654 }
655}
656
657impl<C: AstFormatter> FmtWithCtx<C> for Name {
658 fn fmt_with_ctx(&self, ctx: &C) -> String {
659 let name = self
660 .name
661 .iter()
662 .map(|x| x.fmt_with_ctx(ctx))
663 .collect::<Vec<String>>();
664 name.join("::")
665 }
666}
667
668impl<C: AstFormatter> FmtWithCtx<C> for NullOp {
669 fn fmt_with_ctx(&self, _ctx: &C) -> String {
670 match self {
671 NullOp::SizeOf => "size_of".to_string(),
672 NullOp::AlignOf => "align_of".to_string(),
673 NullOp::OffsetOf(_) => "offset_of(?)".to_string(),
674 NullOp::UbChecks => "ub_checks".to_string(),
675 }
676 }
677}
678
679impl<C: AstFormatter> FmtWithCtx<C> for Operand {
680 fn fmt_with_ctx(&self, ctx: &C) -> String {
681 match self {
682 Operand::Copy(p) => format!("copy ({})", p.fmt_with_ctx(ctx)),
683 Operand::Move(p) => format!("move ({})", p.fmt_with_ctx(ctx)),
684 Operand::Const(c) => format!("const ({})", c.fmt_with_ctx(ctx)),
685 }
686 }
687}
688
689impl<C: AstFormatter, T, U> FmtWithCtx<C> for OutlivesPred<T, U>
690where
691 T: FmtWithCtx<C>,
692 U: FmtWithCtx<C>,
693{
694 fn fmt_with_ctx(&self, ctx: &C) -> String {
695 format!(
696 "{} : {}",
697 self.0.fmt_with_ctx(ctx),
698 self.1.fmt_with_ctx(ctx)
699 )
700 }
701}
702
703impl<C: AstFormatter> FmtWithCtx<C> for PathElem {
704 fn fmt_with_ctx(&self, ctx: &C) -> String {
705 match self {
706 PathElem::Ident(s, d) => {
707 let d = if d.is_zero() {
708 "".to_string()
709 } else {
710 format!("#{}", d)
711 };
712 format!("{s}{d}")
713 }
714 PathElem::Impl(impl_elem, d) => {
715 let impl_elem = impl_elem.fmt_with_ctx(ctx);
716 let d = if d.is_zero() {
717 "".to_string()
718 } else {
719 format!("#{}", d)
720 };
721 format!("{impl_elem}{d}")
722 }
723 }
724 }
725}
726
727impl<C: AstFormatter> FmtWithCtx<C> for Place {
728 fn fmt_with_ctx(&self, ctx: &C) -> String {
729 match &self.kind {
730 PlaceKind::Local(var_id) => ctx.format_object(*var_id),
731 PlaceKind::Projection(subplace, projection) => {
732 let sub = subplace.fmt_with_ctx(ctx);
733 match projection {
734 ProjectionElem::Deref => {
735 format!("*({sub})")
736 }
737 ProjectionElem::Field(proj_kind, field_id) => match proj_kind {
738 FieldProjKind::Adt(adt_id, opt_variant_id) => {
739 let field_name =
740 ctx.format_object((*adt_id, *opt_variant_id, *field_id));
741 let downcast = match opt_variant_id {
742 None => "".to_string(),
743 Some(variant_id) => format!(" as variant @{variant_id}"),
744 };
745 format!("({sub}{downcast}).{field_name}")
746 }
747 FieldProjKind::Tuple(_) => {
748 format!("({sub}).{field_id}")
749 }
750 FieldProjKind::ClosureState => {
751 format!("({sub}).@closure_state_field_{field_id}")
752 }
753 },
754 ProjectionElem::Index {
755 offset,
756 from_end: true,
757 ..
758 } => format!("({sub})[-{}]", offset.fmt_with_ctx(ctx)),
759 ProjectionElem::Index {
760 offset,
761 from_end: false,
762 ..
763 } => format!("({sub})[{}]", offset.fmt_with_ctx(ctx)),
764 ProjectionElem::Subslice {
765 from,
766 to,
767 from_end: true,
768 ..
769 } => format!(
770 "({sub})[{}..-{}]",
771 from.fmt_with_ctx(ctx),
772 to.fmt_with_ctx(ctx)
773 ),
774 ProjectionElem::Subslice {
775 from,
776 to,
777 from_end: false,
778 ..
779 } => format!(
780 "({sub})[{}..{}]",
781 from.fmt_with_ctx(ctx),
782 to.fmt_with_ctx(ctx)
783 ),
784 }
785 }
786 }
787 }
788}
789
790impl<C: AstFormatter> FmtWithCtx<C> for PolyTraitDeclRef {
791 fn fmt_with_ctx(&self, ctx: &C) -> String {
792 self.fmt_as_for(ctx)
793 }
794}
795
796impl<C: AstFormatter> FmtWithCtx<C> for RawConstantExpr {
797 fn fmt_with_ctx(&self, ctx: &C) -> String {
798 match self {
799 RawConstantExpr::Literal(c) => c.to_string(),
800 RawConstantExpr::Adt(variant_id, values) => {
801 let variant_id = match variant_id {
805 Some(id) => format!("Some({id})"),
806 None => "None".to_string(),
807 };
808 let values: Vec<String> = values.iter().map(|v| v.fmt_with_ctx(ctx)).collect();
809 format!("ConstAdt {} [{}]", variant_id, values.join(", "))
810 }
811 RawConstantExpr::Array(values) => {
812 let values = values.iter().map(|v| v.fmt_with_ctx(ctx)).format(", ");
813 format!("[{}]", values)
814 }
815 RawConstantExpr::Global(global_ref) => global_ref.fmt_with_ctx(ctx),
816 RawConstantExpr::TraitConst(trait_ref, name) => {
817 format!("{}::{name}", trait_ref.fmt_with_ctx(ctx),)
818 }
819 RawConstantExpr::Ref(cv) => {
820 format!("&{}", cv.fmt_with_ctx(ctx))
821 }
822 RawConstantExpr::MutPtr(cv) => {
823 format!("&raw mut {}", cv.fmt_with_ctx(ctx))
824 }
825 RawConstantExpr::Var(id) => format!("{}", ctx.format_object(*id)),
826 RawConstantExpr::FnPtr(f) => {
827 format!("{}", f.fmt_with_ctx(ctx))
828 }
829 RawConstantExpr::RawMemory(bytes) => format!("RawMemory({bytes:?})"),
830 RawConstantExpr::Opaque(cause) => format!("Opaque({cause})"),
831 }
832 }
833}
834
835impl<C: AstFormatter> FmtWithCtx<C> for Region {
836 fn fmt_with_ctx(&self, ctx: &C) -> String {
837 match self {
838 Region::Static => "'static".to_string(),
839 Region::Var(var) => ctx.format_object(*var),
840 Region::Erased => "'_".to_string(),
841 }
842 }
843}
844
845impl Region {
846 pub fn fmt_without_ctx(&self) -> String {
847 match self {
848 Region::Static => "'static".to_string(),
849 Region::Var(var) => format!("'_{var}"),
850 Region::Erased => "'_".to_string(),
851 }
852 }
853}
854
855impl<T> RegionBinder<T> {
856 fn fmt_split<'a, C>(&'a self, ctx: &'a C) -> (String, String)
858 where
859 C: AstFormatter,
860 T: FmtWithCtx<<C as PushBinder<'a>>::C>,
861 {
862 let ctx = &ctx.push_bound_regions(&self.regions);
863 (
864 self.regions.iter().map(|r| ctx.format_object(r)).join(", "),
865 self.skip_binder.fmt_with_ctx(ctx),
866 )
867 }
868
869 fn fmt_as_for<'a, C>(&'a self, ctx: &'a C) -> String
871 where
872 C: AstFormatter,
873 T: FmtWithCtx<<C as PushBinder<'a>>::C>,
874 {
875 let (regions, value) = self.fmt_split(ctx);
876 let regions = if regions.is_empty() {
877 "".to_string()
878 } else {
879 format!("for<{regions}> ",)
880 };
881 format!("{regions}{value}",)
882 }
883}
884
885impl<C: AstFormatter> FmtWithCtx<C> for RegionVar {
886 fn fmt_with_ctx(&self, ctx: &C) -> String {
887 ctx.format_object(self)
888 }
889}
890
891impl<C: AstFormatter> FmtWithCtx<C> for Rvalue {
892 fn fmt_with_ctx(&self, ctx: &C) -> String {
893 match self {
894 Rvalue::Use(x) => x.fmt_with_ctx(ctx),
895 Rvalue::Ref(place, borrow_kind) => {
896 let borrow_kind = match borrow_kind {
897 BorrowKind::Shared => "&",
898 BorrowKind::Mut => "&mut ",
899 BorrowKind::TwoPhaseMut => "&two-phase-mut ",
900 BorrowKind::UniqueImmutable => "&uniq ",
901 BorrowKind::Shallow => "&shallow ",
902 };
903 format!("{borrow_kind}{}", place.fmt_with_ctx(ctx))
904 }
905 Rvalue::RawPtr(place, mutability) => {
906 let ptr_kind = match mutability {
907 RefKind::Shared => "&raw const ",
908 RefKind::Mut => "&raw mut ",
909 };
910 format!("{ptr_kind}{}", place.fmt_with_ctx(ctx))
911 }
912
913 Rvalue::BinaryOp(binop, x, y) => {
914 format!("{} {} {}", x.fmt_with_ctx(ctx), binop, y.fmt_with_ctx(ctx))
915 }
916 Rvalue::UnaryOp(unop, x) => {
917 format!("{}({})", unop.fmt_with_ctx(ctx), x.fmt_with_ctx(ctx))
918 }
919 Rvalue::NullaryOp(op, ty) => {
920 format!("{}<{}>", op.fmt_with_ctx(ctx), ty.fmt_with_ctx(ctx))
921 }
922 Rvalue::Discriminant(p, _) => {
923 format!("@discriminant({})", p.fmt_with_ctx(ctx),)
924 }
925 Rvalue::Aggregate(kind, ops) => {
926 let ops_s: Vec<String> = ops.iter().map(|op| op.fmt_with_ctx(ctx)).collect();
927 match kind {
928 AggregateKind::Adt(def_id, variant_id, field_id, _) => {
929 match def_id {
930 TypeId::Tuple => format!("({})", ops_s.join(", ")),
931 TypeId::Builtin(_) => unreachable!(),
932 TypeId::Adt(def_id) => {
933 let mut fields = vec![];
935 for (i, op) in ops.iter().enumerate() {
936 let field_id = match *field_id {
937 None => FieldId::new(i),
938 Some(field_id) => {
939 assert_eq!(i, 0); field_id
941 }
942 };
943 let field_name =
944 ctx.format_object((*def_id, *variant_id, field_id));
945 fields.push(format!(
946 "{}: {}",
947 field_name,
948 op.fmt_with_ctx(ctx)
949 ));
950 }
951
952 let variant = match variant_id {
953 None => ctx.format_object(*def_id),
954 Some(variant_id) => ctx.format_object((*def_id, *variant_id)),
955 };
956 format!("{} {{ {} }}", variant, fields.join(", "))
957 }
958 }
959 }
960 AggregateKind::Array(..) => {
961 format!("[{}]", ops_s.join(", "))
962 }
963 AggregateKind::Closure(fn_id, generics) => {
964 format!(
965 "{{{}{}}} {{{}}}",
966 ctx.format_object(*fn_id),
967 generics.fmt_with_ctx(ctx),
968 ops_s.join(", ")
969 )
970 }
971 AggregateKind::RawPtr(_, rmut) => {
972 let mutability = match rmut {
973 RefKind::Shared => "const",
974 RefKind::Mut => "mut ",
975 };
976 format!("*{} ({})", mutability, ops_s.join(", "))
977 }
978 }
979 }
980 Rvalue::Global(global_ref) => global_ref.fmt_with_ctx(ctx),
981 Rvalue::GlobalRef(global_ref, RefKind::Shared) => {
982 format!("&{}", global_ref.fmt_with_ctx(ctx))
983 }
984 Rvalue::GlobalRef(global_ref, RefKind::Mut) => {
985 format!("&raw mut {}", global_ref.fmt_with_ctx(ctx))
986 }
987 Rvalue::Len(place, ..) => format!("len({})", place.fmt_with_ctx(ctx)),
988 Rvalue::Repeat(op, _ty, cg) => {
989 format!("[{}; {}]", op.fmt_with_ctx(ctx), cg.fmt_with_ctx(ctx))
990 }
991 Rvalue::ShallowInitBox(op, ty) => {
992 format!(
993 "shallow_init_box::<{}>({})",
994 ty.fmt_with_ctx(ctx),
995 op.fmt_with_ctx(ctx)
996 )
997 }
998 }
999 }
1000}
1001
1002impl<C: AstFormatter> FmtWithCtx<C> for ullbc::Statement {
1003 fn fmt_with_ctx(&self, ctx: &C) -> String {
1004 self.fmt_with_ctx_and_indent(TAB_INCR, ctx)
1006 }
1007
1008 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
1009 use ullbc::RawStatement;
1010 let mut out = String::new();
1011 for line in &self.comments_before {
1012 let _ = writeln!(&mut out, "{tab}// {line}");
1013 }
1014 let _ = match &self.content {
1015 RawStatement::Assign(place, rvalue) => write!(
1016 &mut out,
1017 "{tab}{} := {}",
1018 place.fmt_with_ctx(ctx),
1019 rvalue.fmt_with_ctx(ctx),
1020 ),
1021 RawStatement::Call(call) => {
1022 let (call_s, _) = fmt_call(ctx, call);
1023 write!(&mut out, "{tab}{} := {call_s}", call.dest.fmt_with_ctx(ctx))
1024 }
1025 RawStatement::SetDiscriminant(place, variant_id) => write!(
1026 &mut out,
1027 "{tab}@discriminant({}) := {}",
1028 place.fmt_with_ctx(ctx),
1029 variant_id
1030 ),
1031 RawStatement::StorageLive(var_id) => {
1032 write!(
1033 &mut out,
1034 "{tab}storage_live({})",
1035 ctx.format_object(*var_id)
1036 )
1037 }
1038 RawStatement::StorageDead(var_id) => {
1039 write!(
1040 &mut out,
1041 "{tab}storage_dead({})",
1042 ctx.format_object(*var_id)
1043 )
1044 }
1045 RawStatement::Deinit(place) => {
1046 write!(&mut out, "{tab}deinit({})", place.fmt_with_ctx(ctx))
1047 }
1048 RawStatement::Drop(place) => {
1049 write!(&mut out, "{tab}drop {}", place.fmt_with_ctx(ctx))
1050 }
1051 RawStatement::Assert(assert) => write!(&mut out, "{tab}{}", assert.fmt_with_ctx(ctx)),
1052 RawStatement::Nop => write!(&mut out, "{tab}nop"),
1053 RawStatement::Error(s) => write!(&mut out, "{tab}@Error({})", s),
1054 };
1055 out
1056 }
1057}
1058
1059impl<C: AstFormatter> FmtWithCtx<C> for llbc::Statement {
1060 fn fmt_with_ctx(&self, ctx: &C) -> String {
1061 self.fmt_with_ctx_and_indent(TAB_INCR, ctx)
1063 }
1064
1065 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
1066 use llbc::RawStatement;
1067 let mut out = String::new();
1068 for line in &self.comments_before {
1069 let _ = writeln!(&mut out, "{tab}// {line}");
1070 }
1071 let _ = match &self.content {
1072 RawStatement::Assign(place, rvalue) => write!(
1073 &mut out,
1074 "{}{} := {}",
1075 tab,
1076 place.fmt_with_ctx(ctx),
1077 rvalue.fmt_with_ctx(ctx),
1078 ),
1079 RawStatement::SetDiscriminant(place, variant_id) => write!(
1080 &mut out,
1081 "{}@discriminant({}) := {}",
1082 tab,
1083 place.fmt_with_ctx(ctx),
1084 variant_id
1085 ),
1086 RawStatement::StorageLive(var_id) => {
1087 write!(
1088 &mut out,
1089 "{tab}storage_live({})",
1090 ctx.format_object(*var_id)
1091 )
1092 }
1093 RawStatement::StorageDead(var_id) => {
1094 write!(
1095 &mut out,
1096 "{tab}storage_dead({})",
1097 ctx.format_object(*var_id)
1098 )
1099 }
1100 RawStatement::Deinit(place) => {
1101 write!(&mut out, "{tab}deinit({})", place.fmt_with_ctx(ctx))
1102 }
1103 RawStatement::Drop(place) => {
1104 write!(&mut out, "{tab}drop {}", place.fmt_with_ctx(ctx))
1105 }
1106 RawStatement::Assert(assert) => {
1107 write!(&mut out, "{tab}{}", assert.fmt_with_ctx(ctx),)
1108 }
1109 RawStatement::Call(call) => {
1110 let (call_s, _) = fmt_call(ctx, call);
1111 write!(&mut out, "{tab}{} := {call_s}", call.dest.fmt_with_ctx(ctx),)
1112 }
1113 RawStatement::Abort(kind) => {
1114 write!(&mut out, "{}", kind.fmt_with_ctx_and_indent(tab, ctx))
1115 }
1116 RawStatement::Return => write!(&mut out, "{tab}return"),
1117 RawStatement::Break(index) => write!(&mut out, "{tab}break {index}"),
1118 RawStatement::Continue(index) => write!(&mut out, "{tab}continue {index}"),
1119 RawStatement::Nop => write!(&mut out, "{tab}nop"),
1120 RawStatement::Switch(switch) => match switch {
1121 Switch::If(discr, true_st, false_st) => {
1122 let inner_tab = format!("{tab}{TAB_INCR}");
1123 write!(
1124 &mut out,
1125 "{tab}if {} {{\n{}{tab}}}\n{tab}else {{\n{}{tab}}}",
1126 discr.fmt_with_ctx(ctx),
1127 true_st.fmt_with_ctx_and_indent(&inner_tab, ctx),
1128 false_st.fmt_with_ctx_and_indent(&inner_tab, ctx),
1129 )
1130 }
1131 Switch::SwitchInt(discr, _ty, maps, otherwise) => {
1132 let inner_tab1 = format!("{tab}{TAB_INCR}");
1133 let inner_tab2 = format!("{inner_tab1}{TAB_INCR}");
1134 let mut maps: Vec<String> = maps
1135 .iter()
1136 .map(|(pvl, st)| {
1137 let pvl: Vec<String> = pvl.iter().map(|v| v.to_string()).collect();
1139 format!(
1140 "{inner_tab1}{} => {{\n{}{inner_tab1}}},\n",
1141 pvl.join(" | "),
1142 st.fmt_with_ctx_and_indent(&inner_tab2, ctx),
1143 )
1144 })
1145 .collect();
1146 maps.push(format!(
1147 "{inner_tab1}_ => {{\n{}{inner_tab1}}},\n",
1148 otherwise.fmt_with_ctx_and_indent(&inner_tab2, ctx),
1149 ));
1150
1151 write!(
1152 &mut out,
1153 "{tab}switch {} {{\n{}{tab}}}",
1154 discr.fmt_with_ctx(ctx),
1155 maps.iter().format(""),
1156 )
1157 }
1158 Switch::Match(discr, maps, otherwise) => {
1159 let inner_tab1 = format!("{tab}{TAB_INCR}");
1160 let inner_tab2 = format!("{inner_tab1}{TAB_INCR}");
1161 let mut maps: Vec<String> = maps
1162 .iter()
1163 .map(|(pvl, st)| {
1164 let pvl: Vec<String> = pvl.iter().map(|v| v.to_string()).collect();
1166 format!(
1167 "{inner_tab1}{} => {{\n{}{inner_tab1}}},\n",
1168 pvl.join(" | "),
1169 st.fmt_with_ctx_and_indent(&inner_tab2, ctx),
1170 )
1171 })
1172 .collect();
1173 if let Some(otherwise) = otherwise {
1174 maps.push(format!(
1175 "{inner_tab1}_ => {{\n{}{inner_tab1}}},\n",
1176 otherwise.fmt_with_ctx_and_indent(&inner_tab2, ctx),
1177 ));
1178 };
1179
1180 write!(
1181 &mut out,
1182 "{tab}match {} {{\n{}{tab}}}",
1183 discr.fmt_with_ctx(ctx),
1184 maps.iter().format(""),
1185 )
1186 }
1187 },
1188 RawStatement::Loop(body) => {
1189 let inner_tab = format!("{tab}{TAB_INCR}");
1190 write!(
1191 &mut out,
1192 "{tab}loop {{\n{}{tab}}}",
1193 body.fmt_with_ctx_and_indent(&inner_tab, ctx),
1194 )
1195 }
1196 RawStatement::Error(s) => write!(&mut out, "{tab}@ERROR({})", s),
1197 };
1198 out
1199 }
1200}
1201
1202impl<C: AstFormatter> FmtWithCtx<C> for Terminator {
1203 fn fmt_with_ctx(&self, ctx: &C) -> String {
1204 self.fmt_with_ctx_and_indent(TAB_INCR, ctx)
1206 }
1207
1208 fn fmt_with_ctx_and_indent(&self, tab: &str, ctx: &C) -> String {
1209 let mut out = String::new();
1210 for line in &self.comments_before {
1211 let _ = writeln!(&mut out, "{tab}// {line}");
1212 }
1213 let _ = match &self.content {
1214 RawTerminator::Goto { target } => write!(&mut out, "{tab}goto bb{target}"),
1215 RawTerminator::Switch { discr, targets } => match targets {
1216 SwitchTargets::If(true_block, false_block) => write!(
1217 &mut out,
1218 "{tab}if {} -> bb{} else -> bb{}",
1219 discr.fmt_with_ctx(ctx),
1220 true_block,
1221 false_block
1222 ),
1223 SwitchTargets::SwitchInt(_ty, maps, otherwise) => {
1224 let mut maps: Vec<String> = maps
1225 .iter()
1226 .map(|(v, bid)| format!("{}: bb{}", v.to_string(), bid))
1227 .collect();
1228 maps.push(format!("otherwise: bb{otherwise}"));
1229 let maps = maps.join(", ");
1230
1231 write!(
1232 &mut out,
1233 "{tab}switch {} -> {}",
1234 discr.fmt_with_ctx(ctx),
1235 maps
1236 )
1237 }
1238 },
1239 RawTerminator::Abort(kind) => write!(&mut out, "{tab}{}", kind.fmt_with_ctx(ctx)),
1240 RawTerminator::Return => write!(&mut out, "{tab}return"),
1241 };
1242 out
1243 }
1244}
1245
1246impl<C: AstFormatter> FmtWithCtx<C> for TraitClause {
1247 fn fmt_with_ctx(&self, ctx: &C) -> String {
1248 let clause_id = self.clause_id.to_pretty_string();
1249 let trait_ = self.trait_.fmt_with_ctx(ctx);
1250 format!("[{clause_id}]: {trait_}")
1251 }
1252}
1253
1254impl<C: AstFormatter> FmtWithCtx<C> for TraitDecl {
1255 fn fmt_with_ctx(&self, ctx: &C) -> String {
1256 let intro = self.item_meta.fmt_item_intro(ctx, "", "trait");
1257
1258 let ctx = &ctx.set_generics(&self.generics);
1260
1261 let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx, "");
1262
1263 let items = {
1264 let items = self
1265 .parent_clauses
1266 .iter()
1267 .map(|c| {
1268 format!(
1269 "{TAB_INCR}parent_clause{} : {}\n",
1270 c.clause_id,
1271 c.fmt_with_ctx(ctx)
1272 )
1273 })
1274 .chain(self.type_clauses.iter().map(|(name, clauses)| {
1275 clauses
1276 .iter()
1277 .map(|c| {
1278 format!(
1279 "{TAB_INCR}item_clause_{name}_{} : {}\n",
1280 c.clause_id.to_string(),
1281 c.fmt_with_ctx(ctx)
1282 )
1283 })
1284 .collect()
1285 }))
1286 .chain(self.consts.iter().map(|(name, ty)| {
1287 let ty = ty.fmt_with_ctx(ctx);
1288 format!("{TAB_INCR}const {name} : {ty}\n")
1289 }))
1290 .chain(
1291 self.types
1292 .iter()
1293 .map(|name| format!("{TAB_INCR}type {name}\n")),
1294 )
1295 .chain(self.methods().map(|(name, bound_fn)| {
1296 let (params, fn_ref) = bound_fn.fmt_split(ctx);
1297 format!("{TAB_INCR}fn {name}{params} = {fn_ref}\n",)
1298 }))
1299 .collect::<Vec<String>>();
1300 if items.is_empty() {
1301 "".to_string()
1302 } else {
1303 format!("\n{{\n{}}}", items.join(""))
1304 }
1305 };
1306
1307 format!("{intro}{generics}{clauses}{items}")
1308 }
1309}
1310
1311impl<C: AstFormatter> FmtWithCtx<C> for TraitDeclRef {
1312 fn fmt_with_ctx(&self, ctx: &C) -> String {
1313 let trait_id = ctx.format_object(self.trait_id);
1314 let generics = self.generics.fmt_with_ctx(ctx);
1315 format!("{trait_id}{generics}")
1316 }
1317}
1318
1319impl<C: AstFormatter> FmtWithCtx<C> for TraitImpl {
1320 fn fmt_with_ctx(&self, ctx: &C) -> String {
1321 let intro = self.item_meta.fmt_item_intro(ctx, "", "impl");
1322
1323 let ctx = &ctx.set_generics(&self.generics);
1325
1326 let (generics, clauses) = self.generics.fmt_with_ctx_with_trait_clauses(ctx, "");
1327
1328 let items = {
1329 let items = self
1330 .parent_trait_refs
1331 .iter()
1332 .enumerate()
1333 .map(|(i, clause)| {
1334 let i = TraitClauseId::new(i);
1335 format!(
1336 "{TAB_INCR}parent_clause{i} = {}\n",
1337 clause.fmt_with_ctx(ctx)
1338 )
1339 })
1340 .chain(self.type_clauses.iter().map(|(name, clauses)| {
1341 clauses
1342 .iter()
1343 .enumerate()
1344 .map(|(i, c)| {
1345 let i = TraitClauseId::new(i);
1346 format!(
1347 "{TAB_INCR}item_clause_{name}_{i} = {}\n",
1348 c.fmt_with_ctx(ctx)
1349 )
1350 })
1351 .collect()
1352 }))
1353 .chain(self.consts.iter().map(|(name, global)| {
1354 format!("{TAB_INCR}const {name} = {}\n", global.fmt_with_ctx(ctx))
1355 }))
1356 .chain(self.types.iter().map(|(name, ty)| {
1357 format!("{TAB_INCR}type {name} = {}\n", ty.fmt_with_ctx(ctx),)
1358 }))
1359 .chain(self.methods().map(|(name, bound_fn)| {
1360 let (params, fn_ref) = bound_fn.fmt_split(ctx);
1361 format!("{TAB_INCR}fn {name}{params} = {fn_ref}\n",)
1362 }))
1363 .collect::<Vec<String>>();
1364 if items.is_empty() {
1365 "".to_string()
1366 } else {
1367 format!("\n{{\n{}}}", items.join(""))
1368 }
1369 };
1370
1371 let impl_trait = self.impl_trait.fmt_with_ctx(ctx);
1372 format!("{intro}{generics} : {impl_trait}{clauses}{items}")
1373 }
1374}
1375
1376impl<C: AstFormatter> FmtWithCtx<C> for TraitRefKind {
1377 fn fmt_with_ctx(&self, ctx: &C) -> String {
1378 match self {
1379 TraitRefKind::SelfId => "Self".to_string(),
1380 TraitRefKind::ParentClause(id, _decl_id, clause_id) => {
1381 let id = id.fmt_with_ctx(ctx);
1382 format!("{id}::parent_clause{clause_id}")
1383 }
1384 TraitRefKind::ItemClause(id, _decl_id, type_name, clause_id) => {
1385 let id = id.fmt_with_ctx(ctx);
1386 let clause = clause_id.to_pretty_string();
1390 format!("({id}::{type_name}::[{clause}])")
1391 }
1392 TraitRefKind::TraitImpl(id, args) => {
1393 let impl_ = ctx.format_object(*id);
1394 let args = args.fmt_with_ctx(ctx);
1395 format!("{impl_}{args}")
1396 }
1397 TraitRefKind::Clause(id) => ctx.format_object(*id),
1398 TraitRefKind::BuiltinOrAuto {
1399 trait_decl_ref: tr,
1400 types,
1401 ..
1402 } => {
1403 let tr = tr.fmt_with_ctx(ctx);
1404 let types = if types.is_empty() {
1405 String::new()
1406 } else {
1407 let types = types
1408 .iter()
1409 .map(|(name, ty)| {
1410 let ty = ty.fmt_with_ctx(ctx);
1411 format!("{name} = {ty}")
1412 })
1413 .join(", ");
1414 format!(" where {types}")
1415 };
1416 format!("{tr}{types}")
1417 }
1418 TraitRefKind::Dyn(tr) => tr.fmt_with_ctx(ctx),
1419 TraitRefKind::Unknown(msg) => format!("UNKNOWN({msg})"),
1420 }
1421 }
1422}
1423
1424impl<C: AstFormatter> FmtWithCtx<C> for TraitRef {
1425 fn fmt_with_ctx(&self, ctx: &C) -> String {
1426 self.kind.fmt_with_ctx(ctx)
1427 }
1428}
1429
1430impl<C: AstFormatter> FmtWithCtx<C> for TraitTypeConstraint {
1431 fn fmt_with_ctx(&self, ctx: &C) -> String {
1432 let trait_ref = self.trait_ref.fmt_with_ctx(ctx);
1433 let ty = self.ty.fmt_with_ctx(ctx);
1434 format!("{}::{} = {}", trait_ref, self.type_name, ty)
1435 }
1436}
1437
1438impl<C: AstFormatter> FmtWithCtx<C> for Ty {
1439 fn fmt_with_ctx(&self, ctx: &C) -> String {
1440 match self.kind() {
1441 TyKind::Adt(id, generics) => {
1442 let adt_ident = id.fmt_with_ctx(ctx);
1443
1444 if id.is_tuple() {
1445 assert!(generics.trait_refs.is_empty());
1446 let generics = generics.fmt_with_ctx_no_brackets(ctx);
1447 format!("({generics})")
1448 } else {
1449 let generics = generics.fmt_with_ctx(ctx);
1450 format!("{adt_ident}{generics}")
1451 }
1452 }
1453 TyKind::TypeVar(id) => ctx.format_object(*id),
1454 TyKind::Literal(kind) => kind.to_string(),
1455 TyKind::Never => "!".to_string(),
1456 TyKind::Ref(r, ty, kind) => match kind {
1457 RefKind::Mut => {
1458 format!("&{} mut ({})", r.fmt_with_ctx(ctx), ty.fmt_with_ctx(ctx))
1459 }
1460 RefKind::Shared => {
1461 format!("&{} ({})", r.fmt_with_ctx(ctx), ty.fmt_with_ctx(ctx))
1462 }
1463 },
1464 TyKind::RawPtr(ty, kind) => match kind {
1465 RefKind::Shared => format!("*const {}", ty.fmt_with_ctx(ctx)),
1466 RefKind::Mut => format!("*mut {}", ty.fmt_with_ctx(ctx)),
1467 },
1468 TyKind::TraitType(trait_ref, name) => {
1469 format!("{}::{name}", trait_ref.fmt_with_ctx(ctx),)
1470 }
1471 TyKind::DynTrait(pred) => format!("dyn ({})", pred.with_ctx(ctx)),
1472 TyKind::Arrow(io) => {
1473 let ctx = &ctx.push_bound_regions(&io.regions);
1475
1476 let regions = if io.regions.is_empty() {
1477 "".to_string()
1478 } else {
1479 format!(
1480 "<{}>",
1481 io.regions.iter().map(|r| ctx.format_object(r)).join(", ")
1482 )
1483 };
1484 let (inputs, output) = &io.skip_binder;
1485 let inputs = inputs
1486 .iter()
1487 .map(|x| x.fmt_with_ctx(ctx))
1488 .collect::<Vec<String>>()
1489 .join(", ");
1490 if output.is_unit() {
1491 format!("fn{regions}({inputs})")
1492 } else {
1493 let output = output.fmt_with_ctx(ctx);
1494 format!("fn{regions}({inputs}) -> {output}")
1495 }
1496 }
1497 TyKind::Error(msg) => format!("type_error(\"{msg}\")"),
1498 }
1499 }
1500}
1501
1502impl<C: AstFormatter> FmtWithCtx<C> for TypeDecl {
1503 fn fmt_with_ctx(&self, ctx: &C) -> String {
1504 let keyword = match &self.kind {
1505 TypeDeclKind::Struct(..) => "struct",
1506 TypeDeclKind::Union(..) => "union",
1507 TypeDeclKind::Enum(..) => "enum",
1508 TypeDeclKind::Alias(..) => "type",
1509 TypeDeclKind::Opaque | TypeDeclKind::Error(..) => "opaque type",
1510 };
1511 let intro = self.item_meta.fmt_item_intro(ctx, "", keyword);
1512
1513 let ctx = &ctx.set_generics(&self.generics);
1514 let (params, preds) = self.generics.fmt_with_ctx_with_trait_clauses(ctx, " ");
1515 let nl_or_space = if !self.generics.has_predicates() {
1517 " ".to_string()
1518 } else {
1519 "\n ".to_string()
1520 };
1521
1522 let contents = match &self.kind {
1523 TypeDeclKind::Struct(fields) => {
1524 if !fields.is_empty() {
1525 let fields = fields
1526 .iter()
1527 .map(|f| format!("\n {},", f.fmt_with_ctx(ctx)))
1528 .format("");
1529 format!("{nl_or_space}=\n{{{fields}\n}}")
1530 } else {
1531 format!("{nl_or_space}= {{}}")
1532 }
1533 }
1534 TypeDeclKind::Union(fields) => {
1535 let fields = fields
1536 .iter()
1537 .map(|f| format!("\n {},", f.fmt_with_ctx(ctx)))
1538 .format("");
1539 format!("{nl_or_space}=\n{{{fields}\n}}")
1540 }
1541 TypeDeclKind::Enum(variants) => {
1542 let variants = variants
1543 .iter()
1544 .map(|v| format!("| {}", v.fmt_with_ctx(ctx)))
1545 .format("\n");
1546 format!("{nl_or_space}=\n{variants}\n")
1547 }
1548 TypeDeclKind::Alias(ty) => format!(" = {}", ty.fmt_with_ctx(ctx)),
1549 TypeDeclKind::Opaque => format!(""),
1550 TypeDeclKind::Error(msg) => format!(" = ERROR({msg})"),
1551 };
1552 format!("{intro}{params}{preds}{contents}")
1553 }
1554}
1555
1556impl<C: AstFormatter> FmtWithCtx<C> for TypeId {
1557 fn fmt_with_ctx(&self, ctx: &C) -> String {
1558 match self {
1559 TypeId::Tuple => "".to_string(),
1560 TypeId::Adt(def_id) => ctx.format_object(*def_id),
1561 TypeId::Builtin(aty) => aty.get_name().fmt_with_ctx(ctx),
1562 }
1563 }
1564}
1565
1566impl<C: AstFormatter> FmtWithCtx<C> for TypeVar {
1567 fn fmt_with_ctx(&self, _ctx: &C) -> String {
1568 self.name.to_string()
1569 }
1570}
1571
1572impl<C: AstFormatter> FmtWithCtx<C> for UnOp {
1573 fn fmt_with_ctx(&self, ctx: &C) -> String {
1574 match self {
1575 UnOp::Not => "~".to_string(),
1576 UnOp::Neg => "-".to_string(),
1577 UnOp::PtrMetadata => "ptr_metadata".to_string(),
1578 UnOp::Cast(kind) => kind.fmt_with_ctx(ctx),
1579 UnOp::ArrayToSlice(..) => "array_to_slice".to_string(),
1580 }
1581 }
1582}
1583
1584impl<C: AstFormatter> FmtWithCtx<C> for Variant {
1585 fn fmt_with_ctx(&self, ctx: &C) -> String {
1586 let fields: Vec<String> = self.fields.iter().map(|f| f.fmt_with_ctx(ctx)).collect();
1587 let fields = fields.join(", ");
1588 format!("{}({})", self.name, fields)
1589 }
1590}
1591
1592impl std::fmt::Display for AnyTransId {
1593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1594 let s = match self {
1595 AnyTransId::Type(x) => x.to_pretty_string(),
1596 AnyTransId::Fun(x) => x.to_pretty_string(),
1597 AnyTransId::Global(x) => x.to_pretty_string(),
1598 AnyTransId::TraitDecl(x) => x.to_pretty_string(),
1599 AnyTransId::TraitImpl(x) => x.to_pretty_string(),
1600 };
1601 f.write_str(&s)
1602 }
1603}
1604
1605impl std::fmt::Display for BinOp {
1606 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1607 match self {
1608 BinOp::BitXor => write!(f, "^"),
1609 BinOp::BitAnd => write!(f, "&"),
1610 BinOp::BitOr => write!(f, "|"),
1611 BinOp::Eq => write!(f, "=="),
1612 BinOp::Lt => write!(f, "<"),
1613 BinOp::Le => write!(f, "<="),
1614 BinOp::Ne => write!(f, "!="),
1615 BinOp::Ge => write!(f, ">="),
1616 BinOp::Gt => write!(f, ">"),
1617 BinOp::Div => write!(f, "/"),
1618 BinOp::Rem => write!(f, "%"),
1619 BinOp::Add => write!(f, "+"),
1620 BinOp::Sub => write!(f, "-"),
1621 BinOp::Mul => write!(f, "*"),
1622 BinOp::CheckedAdd => write!(f, "checked.+"),
1623 BinOp::CheckedSub => write!(f, "checked.-"),
1624 BinOp::CheckedMul => write!(f, "checked.*"),
1625 BinOp::Shl => write!(f, "<<"),
1626 BinOp::Shr => write!(f, ">>"),
1627 BinOp::Cmp => write!(f, "cmp"),
1628 BinOp::Offset => write!(f, "offset"),
1629 }
1630 }
1631}
1632
1633impl std::fmt::Display for BorrowKind {
1634 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1635 write!(f, "{self:?}")
1637 }
1638}
1639
1640impl std::fmt::Display for BuiltinFunId {
1641 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1642 let name = match *self {
1643 BuiltinFunId::BoxNew => "BoxNew",
1644 BuiltinFunId::ArrayToSliceShared => "ArrayToSliceShared",
1645 BuiltinFunId::ArrayToSliceMut => "ArrayToSliceMut",
1646 BuiltinFunId::ArrayRepeat => "ArrayRepeat",
1647 BuiltinFunId::Index(BuiltinIndexOp {
1648 is_array,
1649 mutability,
1650 is_range,
1651 }) => {
1652 let ty = if is_array { "Array" } else { "Slice" };
1653 let op = if is_range { "SubSlice" } else { "Index" };
1654 let mutability = mutability.variant_name();
1655 &format!("{ty}{op}{mutability}")
1656 }
1657 BuiltinFunId::PtrFromParts(mutability) => {
1658 let mutability = mutability.variant_name();
1659 &format!("PtrFromParts{mutability}")
1660 }
1661 };
1662 f.write_str(name)
1663 }
1664}
1665
1666impl std::fmt::Display for DeBruijnId {
1667 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1668 write!(f, "{}", self.index)
1669 }
1670}
1671
1672impl<Id> Display for DeBruijnVar<Id>
1673where
1674 Id: Display,
1675{
1676 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1677 match self {
1678 Self::Bound(dbid, varid) => write!(f, "{dbid}_{varid}"),
1679 Self::Free(varid) => write!(f, "{varid}"),
1680 }
1681 }
1682}
1683
1684impl std::fmt::Display for ConstantExpr {
1685 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1686 write!(f, "{}", self.fmt_with_ctx(&FmtCtx::new()))
1687 }
1688}
1689
1690impl std::fmt::Display for FileName {
1691 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1692 match self {
1693 FileName::Virtual(path_buf) | FileName::Local(path_buf) => {
1694 write!(f, "{}", path_buf.display())
1695 }
1696 FileName::NotReal(name) => write!(f, "{}", name),
1697 }
1698 }
1699}
1700
1701impl std::fmt::Display for FloatTy {
1702 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1703 match self {
1704 FloatTy::F16 => write!(f, "f16"),
1705 FloatTy::F32 => write!(f, "f32"),
1706 FloatTy::F64 => write!(f, "f64"),
1707 FloatTy::F128 => write!(f, "f128"),
1708 }
1709 }
1710}
1711
1712impl std::fmt::Display for IntegerTy {
1713 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1714 match self {
1715 IntegerTy::Isize => write!(f, "isize"),
1716 IntegerTy::I8 => write!(f, "i8"),
1717 IntegerTy::I16 => write!(f, "i16"),
1718 IntegerTy::I32 => write!(f, "i32"),
1719 IntegerTy::I64 => write!(f, "i64"),
1720 IntegerTy::I128 => write!(f, "i128"),
1721 IntegerTy::Usize => write!(f, "usize"),
1722 IntegerTy::U8 => write!(f, "u8"),
1723 IntegerTy::U16 => write!(f, "u16"),
1724 IntegerTy::U32 => write!(f, "u32"),
1725 IntegerTy::U64 => write!(f, "u64"),
1726 IntegerTy::U128 => write!(f, "u128"),
1727 }
1728 }
1729}
1730
1731impl std::fmt::Display for GenericParams {
1732 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1733 write!(f, "{}", self.fmt_with_ctx_single_line(&FmtCtx::new()))
1734 }
1735}
1736
1737impl std::fmt::Display for Literal {
1738 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1739 match self {
1740 Literal::Scalar(v) => write!(f, "{v}"),
1741 Literal::Float(v) => write!(f, "{v}"),
1742 Literal::Bool(v) => write!(f, "{v}"),
1743 Literal::Char(v) => write!(f, "{v}"),
1744 Literal::Str(v) => write!(f, "\"{}\"", v.replace("\\", "\\\\").replace("\n", "\\n")),
1745 Literal::ByteStr(v) => write!(f, "{v:?}"),
1746 }
1747 }
1748}
1749
1750impl std::fmt::Display for Loc {
1751 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1752 write!(f, "{}:{}", self.line, self.col)
1753 }
1754}
1755
1756impl std::fmt::Display for RawAttribute {
1757 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1758 write!(f, "{}", self.path)?;
1759 if let Some(args) = &self.args {
1760 write!(f, "({args})")?;
1761 }
1762 Ok(())
1763 }
1764}
1765
1766impl std::fmt::Display for ScalarValue {
1767 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1768 match self {
1769 ScalarValue::Isize(v) => write!(f, "{v} : isize"),
1770 ScalarValue::I8(v) => write!(f, "{v} : i8"),
1771 ScalarValue::I16(v) => write!(f, "{v} : i16"),
1772 ScalarValue::I32(v) => write!(f, "{v} : i32"),
1773 ScalarValue::I64(v) => write!(f, "{v} : i64"),
1774 ScalarValue::I128(v) => write!(f, "{v} : i128"),
1775 ScalarValue::Usize(v) => write!(f, "{v} : usize"),
1776 ScalarValue::U8(v) => write!(f, "{v} : u8"),
1777 ScalarValue::U16(v) => write!(f, "{v} : u16"),
1778 ScalarValue::U32(v) => write!(f, "{v} : u32"),
1779 ScalarValue::U64(v) => write!(f, "{v} : u64"),
1780 ScalarValue::U128(v) => write!(f, "{v} : u128"),
1781 }
1782 }
1783}
1784
1785impl std::fmt::Display for FloatValue {
1786 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1787 let v = &self.value;
1788 match self.ty {
1789 FloatTy::F16 => write!(f, "{v} : f16"),
1790 FloatTy::F32 => write!(f, "{v} : f32"),
1791 FloatTy::F64 => write!(f, "{v} : f64"),
1792 FloatTy::F128 => write!(f, "{v} : f128"),
1793 }
1794 }
1795}
1796
1797impl std::fmt::Display for TraitItemName {
1798 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1799 write!(f, "{}", self.0)
1800 }
1801}
1802
1803impl std::fmt::Display for TypeVar {
1804 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1805 write!(f, "{}", self.name)
1806 }
1807}
1808
1809impl std::string::ToString for Local {
1810 fn to_string(&self) -> String {
1811 let id = self.index.to_pretty_string();
1812 match &self.name {
1813 Some(name) => format!("{name}{id}"),
1816 None => id,
1817 }
1818 }
1819}
1820
1821macro_rules! impl_display_via_ctx {
1822 ($ty:ty) => {
1823 impl Display for $ty {
1824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1825 f.write_str(&self.fmt_with_ctx(&FmtCtx::new()))
1826 }
1827 }
1828 };
1829}
1830macro_rules! impl_debug_via_display {
1831 ($ty:ty) => {
1832 impl Debug for $ty {
1833 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1834 <_ as Display>::fmt(self, f)
1835 }
1836 }
1837 };
1838}
1839
1840impl_display_via_ctx!(Field);
1841impl_display_via_ctx!(GenericArgs);
1842impl_display_via_ctx!(LiteralTy);
1843impl_display_via_ctx!(Operand);
1844impl_display_via_ctx!(Place);
1845impl_display_via_ctx!(Rvalue);
1846impl_display_via_ctx!(Variant);
1847impl_debug_via_display!(GenericArgs);
1848impl_debug_via_display!(GenericParams);
1849
1850pub fn fmt_call<C>(ctx: &C, call: &Call) -> (String, Option<String>)
1853where
1854 C: AstFormatter,
1855{
1856 let args: Vec<String> = call.args.iter().map(|x| x.fmt_with_ctx(ctx)).collect();
1857 let args = args.join(", ");
1858 let f = call.func.fmt_with_ctx(ctx);
1859 (format!("{f}({args})"), None)
1860}
1861
1862pub(crate) fn fmt_body_blocks_with_ctx<C>(
1863 body: &Vector<BlockId, BlockData>,
1864 tab: &str,
1865 ctx: &C,
1866) -> String
1867where
1868 C: AstFormatter,
1869{
1870 let block_tab = format!("{tab}{TAB_INCR}");
1871 let mut blocks: Vec<String> = Vec::new();
1872 for (bid, block) in body.iter_indexed_values() {
1873 blocks.push(
1874 format!(
1875 "{tab}bb{}: {{\n{}\n{tab}}}\n",
1876 bid.index(),
1877 block.fmt_with_ctx_and_indent(&block_tab, ctx),
1878 )
1879 .to_string(),
1880 );
1881 }
1882 blocks.join("\n")
1883}