1use std::{fmt, rc::Rc};
4
5use flux_arc_interner::List;
6use flux_common::index::{Idx, IndexVec};
7use itertools::Itertools;
8pub use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
9use rustc_borrowck::consumers::{BodyWithBorrowckFacts, BorrowData, BorrowIndex};
10use rustc_data_structures::{
11 fx::FxIndexMap,
12 graph::{self, DirectedGraph, StartNode, dominators::Dominators},
13 unord::UnordMap,
14};
15use rustc_hir::def_id::DefId;
16use rustc_index::IndexSlice;
17use rustc_macros::{TyDecodable, TyEncodable};
18use rustc_middle::mir::{Promoted, VarDebugInfoContents};
19pub use rustc_middle::{
20 mir::{
21 BasicBlock, BorrowKind, FakeBorrowKind, FakeReadCause, Local, LocalKind, Location,
22 RETURN_PLACE, RawPtrKind, START_BLOCK, SourceInfo, SwitchTargets, UnOp, UnwindAction,
23 },
24 ty::{UserTypeAnnotationIndex, Variance},
25};
26use rustc_span::{Span, Symbol};
27
28use super::ty::{Const, GenericArg, GenericArgs, Region, Ty};
29use crate::{
30 def_id_to_string,
31 ty::{Binder, FnSig, region_to_string},
32};
33
34pub struct BodyRoot<'tcx> {
35 pub body: Body<'tcx>,
36 pub promoted: IndexVec<Promoted, Body<'tcx>>,
37 pub infcx: rustc_infer::infer::InferCtxt<'tcx>,
69 facts: Rc<BodyWithBorrowckFacts<'tcx>>,
75}
76
77impl<'tcx> BodyRoot<'tcx> {
78 pub fn body(&self) -> &Body<'tcx> {
79 &self.body
80 }
81
82 pub fn calculate_borrows_out_of_scope_at_location(
83 &self,
84 ) -> FxIndexMap<Location, Vec<BorrowIndex>> {
85 rustc_borrowck::consumers::calculate_borrows_out_of_scope_at_location(
86 self.body.rustc_body(),
87 &self.facts.region_inference_context,
88 &self.facts.borrow_set,
89 )
90 }
91
92 pub fn borrow_data(&self, idx: BorrowIndex) -> &BorrowData<'tcx> {
93 self.facts
94 .borrow_set
95 .location_map()
96 .get_index(idx.as_usize())
97 .unwrap()
98 .1
99 }
100}
101
102pub struct Body<'tcx> {
103 pub basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
104 pub local_decls: IndexVec<Local, LocalDecl>,
105 pub dominator_order_rank: IndexVec<BasicBlock, u32>,
106 fake_predecessors: IndexVec<BasicBlock, usize>,
108 pub local_names: UnordMap<Local, Symbol>,
109 facts: Rc<BodyWithBorrowckFacts<'tcx>>,
113 kind: BodyKind,
115}
116
117#[derive(Clone, Copy)]
119pub enum BodyKind {
120 Main,
122 Promoted(Promoted),
124}
125
126impl BodyKind {
127 pub fn select_body<'a, 'tcx>(
129 self,
130 facts: &'a BodyWithBorrowckFacts<'tcx>,
131 ) -> &'a rustc_middle::mir::Body<'tcx> {
132 match self {
133 BodyKind::Main => &facts.body,
134 BodyKind::Promoted(promoted) => &facts.promoted[promoted],
135 }
136 }
137}
138
139#[derive(Debug)]
140pub struct BasicBlockData<'tcx> {
141 pub statements: Vec<Statement<'tcx>>,
142 pub terminator: Option<Terminator<'tcx>>,
143 pub is_cleanup: bool,
144}
145
146pub type LocalDecls = IndexSlice<Local, LocalDecl>;
147
148#[derive(Clone, Debug)]
149pub struct LocalDecl {
150 pub ty: Ty,
151 pub source_info: SourceInfo,
152}
153
154pub struct Terminator<'tcx> {
155 pub kind: TerminatorKind<'tcx>,
156 pub source_info: SourceInfo,
157}
158
159#[derive(Debug)]
160pub struct CallArgs<'tcx> {
161 pub orig: rustc_middle::ty::GenericArgsRef<'tcx>,
162 pub lowered: List<GenericArg>,
163}
164
165#[derive(Debug)]
167pub struct Instance {
168 pub impl_f: DefId,
169 pub args: GenericArgs,
170}
171
172pub enum CallKind<'tcx> {
173 FnDef {
174 def_id: DefId,
175 generic_args: CallArgs<'tcx>,
176 resolved_id: DefId,
177 resolved_args: CallArgs<'tcx>,
178 },
179 FnPtr {
180 fn_sig: Binder<FnSig>,
181 operand: Operand<'tcx>,
182 },
183}
184
185#[derive(Debug)]
186pub enum TerminatorKind<'tcx> {
187 Return,
188 Call {
189 kind: CallKind<'tcx>,
190 args: Vec<Operand<'tcx>>,
191 destination: Place,
192 target: Option<BasicBlock>,
193 unwind: UnwindAction,
194 },
195 SwitchInt {
196 discr: Operand<'tcx>,
197 targets: SwitchTargets,
198 },
199 Goto {
200 target: BasicBlock,
201 },
202 Drop {
203 place: Place,
204 target: BasicBlock,
205 unwind: UnwindAction,
206 },
207 Assert {
208 cond: Operand<'tcx>,
209 expected: bool,
210 target: BasicBlock,
211 msg: AssertKind,
212 },
213 Unreachable,
214 FalseEdge {
215 real_target: BasicBlock,
216 imaginary_target: BasicBlock,
217 },
218 FalseUnwind {
219 real_target: BasicBlock,
220 unwind: UnwindAction,
221 },
222 Yield {
223 value: Operand<'tcx>,
224 resume: BasicBlock,
225 resume_arg: Place,
226 drop: Option<BasicBlock>,
227 },
228 CoroutineDrop,
229 UnwindResume,
230}
231
232#[derive(Debug)]
233pub enum AssertKind {
234 BoundsCheck,
235 RemainderByZero,
236 Overflow(BinOp),
237 DivisionByZero,
238 }
242
243pub struct Statement<'tcx> {
244 pub kind: StatementKind<'tcx>,
245 pub source_info: SourceInfo,
246}
247
248#[derive(Debug)]
249pub enum NonDivergingIntrinsic<'tcx> {
250 Assume(Operand<'tcx>),
251}
252
253#[derive(Debug)]
254pub enum StatementKind<'tcx> {
255 Assign(Place, Rvalue<'tcx>),
256 SetDiscriminant(Place, VariantIdx),
257 FakeRead(Box<(FakeReadCause, Place)>),
258 AscribeUserType(Place, Variance),
259 Intrinsic(NonDivergingIntrinsic<'tcx>),
260 PlaceMention(Place),
261 Nop,
262}
263
264pub enum Rvalue<'tcx> {
266 Use(Operand<'tcx>),
267 Repeat(Operand<'tcx>, Const),
268 Ref(Region, BorrowKind, Place),
269 RawPtr(RawPtrKind, Place),
270 Cast(CastKind, Operand<'tcx>, Ty),
271 BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>),
272 UnaryOp(UnOp, Operand<'tcx>),
273 Discriminant(Place),
274 Aggregate(AggregateKind, Vec<Operand<'tcx>>),
275 ShallowInitBox(Operand<'tcx>, Ty),
276}
277
278#[derive(Copy, Clone)]
279pub enum CastKind {
280 IntToInt,
281 FloatToInt,
282 IntToFloat,
283 FloatToFloat,
284 PtrToPtr,
285 PointerCoercion(PointerCast),
286 PointerExposeProvenance,
287 PointerWithExposedProvenance,
288}
289
290#[derive(Copy, Clone)]
291pub enum PointerCast {
292 MutToConstPointer,
293 Unsize,
294 ClosureFnPointer,
295 ReifyFnPointer,
296}
297
298#[derive(Debug)]
299pub enum AggregateKind {
300 Adt(DefId, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
301 Array(Ty),
302 Tuple,
303 Closure(DefId, GenericArgs),
304 Coroutine(DefId, GenericArgs),
305}
306
307#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
308pub enum BinOp {
309 Gt,
310 Ge,
311 Lt,
312 Le,
313 Eq,
314 Ne,
315 Add,
316 Sub,
317 Mul,
318 Div,
319 Rem,
320 BitAnd,
321 BitOr,
322 BitXor,
323 Shl,
324 Shr,
325}
326
327pub enum Operand<'tcx> {
328 Copy(Place),
329 Move(Place),
330 Constant(ConstOperand<'tcx>),
331}
332
333pub struct ConstOperand<'tcx> {
338 pub ty: Ty,
343 pub span: Span,
344 pub const_: rustc_middle::mir::Const<'tcx>,
345}
346
347#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
348pub struct Place {
349 pub local: Local,
351 pub projection: Vec<PlaceElem>,
353}
354
355impl Place {
356 pub const RETURN: &'static Place = &Place { local: RETURN_PLACE, projection: vec![] };
357
358 pub fn new(local: Local, projection: Vec<PlaceElem>) -> Place {
359 Place { local, projection }
360 }
361
362 pub fn as_ref(&self) -> PlaceRef<'_> {
363 PlaceRef { local: self.local, projection: &self.projection[..] }
364 }
365
366 pub fn deref(&self) -> Self {
367 let mut projection = self.projection.clone();
368 projection.push(PlaceElem::Deref);
369 Place { local: self.local, projection }
370 }
371
372 pub fn name(&self, local_names: &UnordMap<Local, Symbol>) -> Option<Symbol> {
374 if self.projection.is_empty() { local_names.get(&self.local).copied() } else { None }
375 }
376}
377
378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
379pub enum PlaceElem {
380 Deref,
381 Field(FieldIdx),
382 Downcast(Option<Symbol>, VariantIdx),
383 Index(Local),
384 ConstantIndex {
385 offset: u64,
387 min_length: u64,
390 from_end: bool,
393 },
394}
395
396#[derive(Clone, Copy, PartialEq, Eq)]
397pub struct PlaceRef<'a> {
398 pub local: Local,
399 pub projection: &'a [PlaceElem],
400}
401
402impl<'a> PlaceRef<'a> {
403 pub fn truncate(self, i: usize) -> PlaceRef<'a> {
404 Self { local: self.local, projection: &self.projection[..i] }
405 }
406
407 pub fn to_place(self) -> Place {
408 Place { local: self.local, projection: self.projection.to_vec() }
409 }
410
411 pub fn last_projection(self) -> Option<(PlaceRef<'a>, PlaceElem)> {
412 if let [base @ .., elem] = self.projection {
413 Some((PlaceRef { local: self.local, projection: base }, *elem))
414 } else {
415 None
416 }
417 }
418}
419
420impl Terminator<'_> {
421 pub fn is_return(&self) -> bool {
422 matches!(self.kind, TerminatorKind::Return)
423 }
424}
425
426impl Statement<'_> {
427 pub fn is_nop(&self) -> bool {
428 matches!(self.kind, StatementKind::Nop)
429 }
430}
431
432impl<'tcx> BodyRoot<'tcx> {
433 pub fn new(
434 facts: Rc<BodyWithBorrowckFacts<'tcx>>,
435 infcx: rustc_infer::infer::InferCtxt<'tcx>,
436 body: Body<'tcx>,
437 promoted: IndexVec<Promoted, Body<'tcx>>,
438 ) -> Self {
439 Self { body, promoted, infcx, facts }
440 }
441}
442
443impl<'tcx> Body<'tcx> {
444 pub fn new(
445 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
446 local_decls: IndexVec<Local, LocalDecl>,
447 facts: Rc<BodyWithBorrowckFacts<'tcx>>,
448 kind: BodyKind,
449 ) -> Self {
450 let rustc_body = kind.select_body(&facts);
451 let fake_predecessors = mk_fake_predecessors(&basic_blocks);
452
453 let graph = &rustc_body.basic_blocks;
455 let mut dominator_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
456 let reverse_post_order = graph::iterate::reverse_post_order(graph, graph.start_node());
457 assert_eq!(reverse_post_order.len(), graph.num_nodes());
458 for (rank, bb) in (0u32..).zip(reverse_post_order) {
459 dominator_order_rank[bb] = rank;
460 }
461 let local_names = rustc_body
462 .var_debug_info
463 .iter()
464 .flat_map(|var_debug_info| {
465 if let VarDebugInfoContents::Place(place) = var_debug_info.value {
466 let local = place.as_local()?;
467 Some((local, var_debug_info.name))
468 } else {
469 None
470 }
471 })
472 .collect();
473 Self {
474 basic_blocks,
475 local_decls,
476 fake_predecessors,
477 dominator_order_rank,
478 local_names,
479 facts,
480 kind,
481 }
482 }
483
484 pub fn rustc_body(&self) -> &rustc_middle::mir::Body<'tcx> {
487 self.kind.select_body(&self.facts)
488 }
489
490 pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
491 Location { block: bb, statement_index: self.basic_blocks[bb].statements.len() }
492 }
493
494 #[inline]
495 pub fn is_join_point(&self, bb: BasicBlock) -> bool {
496 let total_preds = self.rustc_body().basic_blocks.predecessors()[bb].len();
497 let real_preds = total_preds - self.fake_predecessors[bb];
498 real_preds > usize::from(bb != START_BLOCK)
501 }
502
503 #[inline]
504 pub fn dominators(&self) -> &Dominators<BasicBlock> {
505 self.rustc_body().basic_blocks.dominators()
506 }
507
508 #[inline]
509 pub fn args_iter(&self) -> impl ExactSizeIterator<Item = Local> {
510 (1..self.rustc_body().arg_count + 1).map(Local::new)
511 }
512
513 #[inline]
514 pub fn vars_and_temps_iter(&self) -> impl ExactSizeIterator<Item = Local> {
515 (self.rustc_body().arg_count + 1..self.local_decls.len()).map(Local::new)
516 }
517
518 pub fn span(&self) -> Span {
519 self.rustc_body().span
520 }
521
522 #[inline]
523 pub fn return_ty(&self) -> Ty {
524 self.local_decls[RETURN_PLACE].ty.clone()
525 }
526}
527
528fn mk_fake_predecessors(
537 basic_blocks: &IndexVec<BasicBlock, BasicBlockData>,
538) -> IndexVec<BasicBlock, usize> {
539 let mut res: IndexVec<BasicBlock, usize> = basic_blocks.iter().map(|_| 0).collect();
540
541 for bb in basic_blocks {
542 if let Some(terminator) = &bb.terminator
543 && let TerminatorKind::FalseEdge { imaginary_target, .. } = terminator.kind
544 {
545 res[imaginary_target] += 1;
546 }
547 }
548 res
549}
550
551impl fmt::Debug for Body<'_> {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 for (bb, data) in self.basic_blocks.iter_enumerated() {
554 writeln!(
555 f,
556 "{bb:?}: {{{}",
557 data.statements
558 .iter()
559 .filter(|stmt| !matches!(stmt.kind, StatementKind::Nop))
560 .format_with("", |stmt, f| f(&format_args!("\n {stmt:?};")))
561 )?;
562 if let Some(terminator) = &data.terminator {
563 writeln!(f, " {terminator:?}")?;
564 }
565 writeln!(f, "}}\n")?;
566 }
567 Ok(())
568 }
569}
570
571impl fmt::Debug for Statement<'_> {
572 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573 match &self.kind {
574 StatementKind::Assign(place, rvalue) => write!(f, "{place:?} = {rvalue:?}"),
575 StatementKind::Nop => write!(f, "nop"),
576 StatementKind::PlaceMention(place) => {
577 write!(f, "PlaceMention({place:?})")
578 }
579 StatementKind::SetDiscriminant(place, variant_idx) => {
580 write!(f, "discriminant({place:?}) = {variant_idx:?}")
581 }
582 StatementKind::FakeRead(box (cause, place)) => {
583 write!(f, "FakeRead({cause:?}, {place:?})")
584 }
585 StatementKind::AscribeUserType(place, variance) => {
586 write!(f, "AscribeUserType({place:?}, {variance:?})")
587 }
588 StatementKind::Intrinsic(NonDivergingIntrinsic::Assume(op)) => {
589 write!(f, "Assume({op:?})")
590 }
591 }
592 }
593}
594
595impl fmt::Debug for CallKind<'_> {
596 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
597 match self {
598 CallKind::FnDef { resolved_id, resolved_args, .. } => {
599 let fname = rustc_middle::ty::tls::with(|tcx| tcx.def_path_str(*resolved_id));
600 write!(f, "call {fname}")?;
601 if !resolved_args.lowered.is_empty() {
602 write!(f, "<{:?}>", resolved_args.lowered.iter().format(", "))?;
603 }
604 Ok(())
605 }
606 CallKind::FnPtr { fn_sig, operand } => write!(f, "FnPtr[{operand:?}]({fn_sig:?})"),
607 }
608 }
609}
610
611impl fmt::Debug for Terminator<'_> {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 match &self.kind {
614 TerminatorKind::Return => write!(f, "return"),
615 TerminatorKind::Unreachable => write!(f, "unreachable"),
616 TerminatorKind::Call { kind, args, destination, target, unwind, .. } => {
617 write!(
618 f,
619 "{destination:?} = call {kind:?}({args:?}) -> [return: {target}, unwind: {unwind:?}]",
620 args = args.iter().format(", "),
621 target = opt_bb_to_str(*target),
622 )
623 }
624 TerminatorKind::SwitchInt { discr, targets } => {
625 write!(
626 f,
627 "switchInt({discr:?}) -> [{}, otherwise: {:?}]",
628 targets
629 .iter()
630 .format_with(", ", |(val, bb), f| f(&format_args!("{val:?}: {bb:?}"))),
631 targets.otherwise()
632 )
633 }
634 TerminatorKind::Goto { target } => {
635 write!(f, "goto -> {target:?}")
636 }
637 TerminatorKind::Drop { place, target, unwind } => {
638 write!(f, "drop({place:?}) -> [{target:?}, unwind: {unwind:?}]",)
639 }
640 TerminatorKind::Assert { cond, target, expected, msg } => {
641 write!(
642 f,
643 "assert({cond:?} is expected to be {expected:?}, \"{msg:?}\") -> {target:?}"
644 )
645 }
646 TerminatorKind::FalseEdge { real_target, imaginary_target } => {
647 write!(f, "falseEdge -> [real: {real_target:?}, imaginary: {imaginary_target:?}]")
648 }
649 TerminatorKind::FalseUnwind { real_target, unwind } => {
650 write!(f, "falseUnwind -> [real: {real_target:?}, cleanup: {unwind:?}]")
651 }
652 TerminatorKind::UnwindResume => write!(f, "resume"),
653 TerminatorKind::CoroutineDrop => write!(f, "generator_drop"),
654 TerminatorKind::Yield { value, resume, drop, resume_arg } => {
655 write!(
656 f,
657 "{resume_arg:?} = yield({value:?}) -> [resume: {resume:?}, drop: {drop:?}]"
658 )
659 }
660 }
661 }
662}
663
664impl fmt::Debug for Place {
665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666 write!(f, "{:?}", self.as_ref())
667 }
668}
669
670impl fmt::Debug for PlaceRef<'_> {
671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672 let mut p = format!("{:?}", self.local);
673 let mut need_parens = false;
674 for elem in self.projection {
675 match elem {
676 PlaceElem::Field(f) => {
677 if need_parens {
678 p = format!("({p}).{}", u32::from(*f));
679 need_parens = false;
680 } else {
681 p = format!("{p}.{}", u32::from(*f));
682 }
683 }
684 PlaceElem::Deref => {
685 p = format!("*{p}");
686 need_parens = true;
687 }
688 PlaceElem::Downcast(variant_name, variant_idx) => {
689 if let Some(variant_name) = variant_name {
690 p = format!("{p} as {variant_name}");
691 } else {
692 p = format!("{p} as {variant_idx:?}");
693 }
694 need_parens = true;
695 }
696 PlaceElem::Index(v) => {
697 p = format!("{p}[{v:?}]");
698 need_parens = false;
699 }
700 PlaceElem::ConstantIndex { offset, min_length, .. } => {
701 p = format!("{p}[{offset:?} of {min_length:?}]");
702 need_parens = false;
703 }
704 }
705 }
706 write!(f, "{p}")
707 }
708}
709
710impl fmt::Debug for Rvalue<'_> {
711 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
712 match self {
713 Rvalue::Use(op) => write!(f, "{op:?}"),
714 Rvalue::Ref(r, BorrowKind::Mut { .. }, place) => {
715 write!(f, "&{} mut {place:?}", region_to_string(*r))
716 }
717 Rvalue::Ref(r, BorrowKind::Shared, place) => {
718 write!(f, "&{} {place:?}", region_to_string(*r))
719 }
720 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Shallow), place) => {
721 write!(f, "&{} fake shallow {place:?}", region_to_string(*r))
722 }
723 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Deep), place) => {
724 write!(f, "&{} fake deep {place:?}", region_to_string(*r))
725 }
726 Rvalue::RawPtr(mutbl, place) => write!(f, "&raw {} {place:?}", mutbl.ptr_str()),
727 Rvalue::Discriminant(place) => write!(f, "discriminant({place:?})"),
728 Rvalue::BinaryOp(bin_op, op1, op2) => write!(f, "{bin_op:?}({op1:?}, {op2:?})"),
729 Rvalue::UnaryOp(un_op, op) => write!(f, "{un_op:?}({op:?})"),
730 Rvalue::Aggregate(AggregateKind::Adt(def_id, variant_idx, args, _, _), operands) => {
731 let (fname, variant_name) = rustc_middle::ty::tls::with(|tcx| {
732 let variant_name = tcx.adt_def(*def_id).variant(*variant_idx).name;
733 let fname = tcx.def_path_str(*def_id);
734 (fname, variant_name)
735 });
736 write!(f, "{fname}::{variant_name}")?;
737 if !args.is_empty() {
738 write!(f, "<{:?}>", args.iter().format(", "),)?;
739 }
740 if !operands.is_empty() {
741 write!(f, "({:?})", operands.iter().format(", "))?;
742 }
743 Ok(())
744 }
745 Rvalue::Aggregate(AggregateKind::Closure(def_id, args), operands) => {
746 write!(
747 f,
748 "closure({}, {args:?}, {:?})",
749 def_id_to_string(*def_id),
750 operands.iter().format(", ")
751 )
752 }
753 Rvalue::Aggregate(AggregateKind::Coroutine(def_id, args), operands) => {
754 write!(
755 f,
756 "generator({}, {args:?}, {:?})",
757 def_id_to_string(*def_id),
758 operands.iter().format(", ")
759 )
760 }
761 Rvalue::Aggregate(AggregateKind::Array(_), args) => {
762 write!(f, "[{:?}]", args.iter().format(", "))
763 }
764 Rvalue::Aggregate(AggregateKind::Tuple, args) => {
765 write!(f, "({:?})", args.iter().format(", "))
766 }
767 Rvalue::Cast(kind, op, ty) => write!(f, "{op:?} as {ty:?} [{kind:?}]"),
768 Rvalue::Repeat(op, c) => write!(f, "[{op:?}; {c:?}]"),
769 Rvalue::ShallowInitBox(op, ty) => write!(f, "ShallowInitBox({op:?}, {ty:?})"),
770 }
771 }
772}
773
774impl fmt::Debug for PointerCast {
775 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776 match self {
777 PointerCast::MutToConstPointer => write!(f, "MutToConstPointer"),
778 PointerCast::Unsize => write!(f, "Unsize"),
779 PointerCast::ClosureFnPointer => write!(f, "ClosureFnPointer"),
780 PointerCast::ReifyFnPointer => write!(f, "ReifyFnPointer"),
781 }
782 }
783}
784
785impl fmt::Debug for CastKind {
786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787 match self {
788 CastKind::IntToInt => write!(f, "IntToInt"),
789 CastKind::FloatToInt => write!(f, "FloatToInt"),
790 CastKind::IntToFloat => write!(f, "IntToFloat"),
791 CastKind::FloatToFloat => write!(f, "FloatToFloat"),
792 CastKind::PtrToPtr => write!(f, "PtrToPtr"),
793 CastKind::PointerCoercion(c) => write!(f, "Pointer({c:?})"),
794 CastKind::PointerExposeProvenance => write!(f, "PointerExposeProvenance"),
795 CastKind::PointerWithExposedProvenance => write!(f, "PointerWithExposedProvenance"),
796 }
797 }
798}
799
800impl fmt::Debug for Operand<'_> {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 match self {
803 Self::Copy(place) => write!(f, "copy {place:?}"),
804 Self::Move(place) => write!(f, "move {place:?}"),
805 Self::Constant(c) => write!(f, "{:?}", c.const_),
806 }
807 }
808}
809
810fn opt_bb_to_str(bb: Option<BasicBlock>) -> String {
811 match bb {
812 Some(bb) => format!("{bb:?}"),
813 None => "None".to_string(),
814 }
815}