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