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 UnaryOp(UnOp, Operand<'tcx>),
245 Discriminant(Place),
246 Aggregate(AggregateKind, Vec<Operand<'tcx>>),
247 ShallowInitBox(Operand<'tcx>, Ty),
248}
249
250#[derive(Copy, Clone)]
251pub enum CastKind {
252 IntToInt,
253 FloatToInt,
254 IntToFloat,
255 PtrToPtr,
256 PointerCoercion(PointerCast),
257 PointerExposeProvenance,
258 PointerWithExposedProvenance,
259}
260
261#[derive(Copy, Clone)]
262pub enum PointerCast {
263 MutToConstPointer,
264 Unsize,
265 ClosureFnPointer,
266 ReifyFnPointer,
267}
268
269#[derive(Debug)]
270pub enum AggregateKind {
271 Adt(DefId, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
272 Array(Ty),
273 Tuple,
274 Closure(DefId, GenericArgs),
275 Coroutine(DefId, GenericArgs),
276}
277
278#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
279pub enum BinOp {
280 Gt,
281 Ge,
282 Lt,
283 Le,
284 Eq,
285 Ne,
286 Add,
287 Sub,
288 Mul,
289 Div,
290 Rem,
291 BitAnd,
292 BitOr,
293 BitXor,
294 Shl,
295 Shr,
296}
297
298pub enum Operand<'tcx> {
299 Copy(Place),
300 Move(Place),
301 Constant(ConstOperand<'tcx>),
302}
303
304pub struct ConstOperand<'tcx> {
309 pub ty: Ty,
314 pub span: Span,
315 pub const_: rustc_middle::mir::Const<'tcx>,
316}
317
318#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
319pub struct Place {
320 pub local: Local,
322 pub projection: Vec<PlaceElem>,
324}
325
326impl Place {
327 pub const RETURN: &'static Place = &Place { local: RETURN_PLACE, projection: vec![] };
328
329 pub fn new(local: Local, projection: Vec<PlaceElem>) -> Place {
330 Place { local, projection }
331 }
332
333 pub fn as_ref(&self) -> PlaceRef<'_> {
334 PlaceRef { local: self.local, projection: &self.projection[..] }
335 }
336
337 pub fn deref(&self) -> Self {
338 let mut projection = self.projection.clone();
339 projection.push(PlaceElem::Deref);
340 Place { local: self.local, projection }
341 }
342
343 pub fn name(&self, local_names: &UnordMap<Local, Symbol>) -> Option<Symbol> {
345 if self.projection.is_empty() { local_names.get(&self.local).copied() } else { None }
346 }
347}
348
349#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
350pub enum PlaceElem {
351 Deref,
352 Field(FieldIdx),
353 Downcast(Option<Symbol>, VariantIdx),
354 Index(Local),
355 ConstantIndex {
356 offset: u64,
358 min_length: u64,
361 from_end: bool,
364 },
365}
366
367#[derive(Clone, Copy, PartialEq, Eq)]
368pub struct PlaceRef<'a> {
369 pub local: Local,
370 pub projection: &'a [PlaceElem],
371}
372
373impl<'a> PlaceRef<'a> {
374 pub fn truncate(self, i: usize) -> PlaceRef<'a> {
375 Self { local: self.local, projection: &self.projection[..i] }
376 }
377
378 pub fn to_place(self) -> Place {
379 Place { local: self.local, projection: self.projection.to_vec() }
380 }
381
382 pub fn last_projection(self) -> Option<(PlaceRef<'a>, PlaceElem)> {
383 if let [base @ .., elem] = self.projection {
384 Some((PlaceRef { local: self.local, projection: base }, *elem))
385 } else {
386 None
387 }
388 }
389}
390
391impl Terminator<'_> {
392 pub fn is_return(&self) -> bool {
393 matches!(self.kind, TerminatorKind::Return)
394 }
395}
396
397impl Statement<'_> {
398 pub fn is_nop(&self) -> bool {
399 matches!(self.kind, StatementKind::Nop)
400 }
401}
402
403impl<'tcx> BodyRoot<'tcx> {
404 pub fn new(
405 borrow_set: BorrowSet<'tcx>,
406 region_inference_context: RegionInferenceContext<'tcx>,
407 infcx: rustc_infer::infer::InferCtxt<'tcx>,
408 body: Body<'tcx>,
409 promoted: IndexVec<Promoted, Body<'tcx>>,
410 ) -> Self {
411 Self { body, promoted, infcx, borrow_set, region_inference_context }
412 }
413}
414
415impl<'tcx> Body<'tcx> {
416 pub fn new(
417 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
418 local_decls: IndexVec<Local, LocalDecl>,
419 rustc_body: rustc_middle::mir::Body<'tcx>,
420 ) -> Self {
421 let fake_predecessors = mk_fake_predecessors(&basic_blocks);
422
423 let graph = &rustc_body.basic_blocks;
425 let mut dominator_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
426 let reverse_post_order = graph::iterate::reverse_post_order(graph, graph.start_node());
427 assert_eq!(reverse_post_order.len(), graph.num_nodes());
428 for (rank, bb) in (0u32..).zip(reverse_post_order) {
429 dominator_order_rank[bb] = rank;
430 }
431 let local_names = rustc_body
432 .var_debug_info
433 .iter()
434 .flat_map(|var_debug_info| {
435 if let VarDebugInfoContents::Place(place) = var_debug_info.value {
436 let local = place.as_local()?;
437 Some((local, var_debug_info.name))
438 } else {
439 None
440 }
441 })
442 .collect();
443 Self {
444 basic_blocks,
445 local_decls,
446 fake_predecessors,
447 dominator_order_rank,
448 local_names,
449 rustc_body,
450 }
451 }
452
453 pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
454 Location { block: bb, statement_index: self.basic_blocks[bb].statements.len() }
455 }
456
457 #[inline]
458 pub fn is_join_point(&self, bb: BasicBlock) -> bool {
459 let total_preds = self.rustc_body.basic_blocks.predecessors()[bb].len();
460 let real_preds = total_preds - self.fake_predecessors[bb];
461 real_preds > usize::from(bb != START_BLOCK)
464 }
465
466 #[inline]
467 pub fn dominators(&self) -> &Dominators<BasicBlock> {
468 self.rustc_body.basic_blocks.dominators()
469 }
470
471 #[inline]
472 pub fn args_iter(&self) -> impl ExactSizeIterator<Item = Local> {
473 (1..self.rustc_body.arg_count + 1).map(Local::new)
474 }
475
476 #[inline]
477 pub fn vars_and_temps_iter(&self) -> impl ExactSizeIterator<Item = Local> {
478 (self.rustc_body.arg_count + 1..self.local_decls.len()).map(Local::new)
479 }
480
481 pub fn span(&self) -> Span {
482 self.rustc_body.span
483 }
484
485 #[inline]
486 pub fn return_ty(&self) -> Ty {
487 self.local_decls[RETURN_PLACE].ty.clone()
488 }
489}
490
491fn mk_fake_predecessors(
500 basic_blocks: &IndexVec<BasicBlock, BasicBlockData>,
501) -> IndexVec<BasicBlock, usize> {
502 let mut res: IndexVec<BasicBlock, usize> = basic_blocks.iter().map(|_| 0).collect();
503
504 for bb in basic_blocks {
505 if let Some(terminator) = &bb.terminator
506 && let TerminatorKind::FalseEdge { imaginary_target, .. } = terminator.kind
507 {
508 res[imaginary_target] += 1;
509 }
510 }
511 res
512}
513
514impl fmt::Debug for Body<'_> {
515 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 for (bb, data) in self.basic_blocks.iter_enumerated() {
517 writeln!(
518 f,
519 "{bb:?}: {{{}",
520 data.statements
521 .iter()
522 .filter(|stmt| !matches!(stmt.kind, StatementKind::Nop))
523 .format_with("", |stmt, f| f(&format_args!("\n {stmt:?};")))
524 )?;
525 if let Some(terminator) = &data.terminator {
526 writeln!(f, " {terminator:?}")?;
527 }
528 writeln!(f, "}}\n")?;
529 }
530 Ok(())
531 }
532}
533
534impl fmt::Debug for Statement<'_> {
535 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536 match &self.kind {
537 StatementKind::Assign(place, rvalue) => write!(f, "{place:?} = {rvalue:?}"),
538 StatementKind::Nop => write!(f, "nop"),
539 StatementKind::PlaceMention(place) => {
540 write!(f, "PlaceMention({place:?})")
541 }
542 StatementKind::SetDiscriminant(place, variant_idx) => {
543 write!(f, "discriminant({place:?}) = {variant_idx:?}")
544 }
545 StatementKind::FakeRead(box (cause, place)) => {
546 write!(f, "FakeRead({cause:?}, {place:?})")
547 }
548 StatementKind::AscribeUserType(place, variance) => {
549 write!(f, "AscribeUserType({place:?}, {variance:?})")
550 }
551 StatementKind::Intrinsic(NonDivergingIntrinsic::Assume(op)) => {
552 write!(f, "Assume({op:?})")
553 }
554 }
555 }
556}
557
558impl fmt::Debug for CallKind<'_> {
559 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560 match self {
561 CallKind::FnDef { resolved_id, resolved_args, .. } => {
562 let fname = rustc_middle::ty::tls::with(|tcx| tcx.def_path_str(*resolved_id));
563 write!(f, "call {fname}")?;
564 if !resolved_args.lowered.is_empty() {
565 write!(f, "<{:?}>", resolved_args.lowered.iter().format(", "))?;
566 }
567 Ok(())
568 }
569 CallKind::FnPtr { fn_sig, operand } => write!(f, "FnPtr[{operand:?}]({fn_sig:?})"),
570 }
571 }
572}
573
574impl fmt::Debug for Terminator<'_> {
575 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576 match &self.kind {
577 TerminatorKind::Return => write!(f, "return"),
578 TerminatorKind::Unreachable => write!(f, "unreachable"),
579 TerminatorKind::Call { kind, args, destination, target, unwind, .. } => {
580 write!(
581 f,
582 "{destination:?} = call {kind:?}({args:?}) -> [return: {target}, unwind: {unwind:?}]",
583 args = args.iter().format(", "),
584 target = opt_bb_to_str(*target),
585 )
586 }
587 TerminatorKind::SwitchInt { discr, targets } => {
588 write!(
589 f,
590 "switchInt({discr:?}) -> [{}, otherwise: {:?}]",
591 targets
592 .iter()
593 .format_with(", ", |(val, bb), f| f(&format_args!("{val:?}: {bb:?}"))),
594 targets.otherwise()
595 )
596 }
597 TerminatorKind::Goto { target } => {
598 write!(f, "goto -> {target:?}")
599 }
600 TerminatorKind::Drop { place, target, unwind } => {
601 write!(f, "drop({place:?}) -> [{target:?}, unwind: {unwind:?}]",)
602 }
603 TerminatorKind::Assert { cond, target, expected, msg } => {
604 write!(
605 f,
606 "assert({cond:?} is expected to be {expected:?}, \"{msg:?}\") -> {target:?}"
607 )
608 }
609 TerminatorKind::FalseEdge { real_target, imaginary_target } => {
610 write!(f, "falseEdge -> [real: {real_target:?}, imaginary: {imaginary_target:?}]")
611 }
612 TerminatorKind::FalseUnwind { real_target, unwind } => {
613 write!(f, "falseUnwind -> [real: {real_target:?}, cleanup: {unwind:?}]")
614 }
615 TerminatorKind::UnwindResume => write!(f, "resume"),
616 TerminatorKind::CoroutineDrop => write!(f, "generator_drop"),
617 TerminatorKind::Yield { value, resume, drop, resume_arg } => {
618 write!(
619 f,
620 "{resume_arg:?} = yield({value:?}) -> [resume: {resume:?}, drop: {drop:?}]"
621 )
622 }
623 }
624 }
625}
626
627impl fmt::Debug for Place {
628 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
629 write!(f, "{:?}", self.as_ref())
630 }
631}
632
633impl fmt::Debug for PlaceRef<'_> {
634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635 let mut p = format!("{:?}", self.local);
636 let mut need_parens = false;
637 for elem in self.projection {
638 match elem {
639 PlaceElem::Field(f) => {
640 if need_parens {
641 p = format!("({p}).{}", u32::from(*f));
642 need_parens = false;
643 } else {
644 p = format!("{p}.{}", u32::from(*f));
645 }
646 }
647 PlaceElem::Deref => {
648 p = format!("*{p}");
649 need_parens = true;
650 }
651 PlaceElem::Downcast(variant_name, variant_idx) => {
652 if let Some(variant_name) = variant_name {
653 p = format!("{p} as {variant_name}");
654 } else {
655 p = format!("{p} as {variant_idx:?}");
656 }
657 need_parens = true;
658 }
659 PlaceElem::Index(v) => {
660 p = format!("{p}[{v:?}]");
661 need_parens = false;
662 }
663 PlaceElem::ConstantIndex { offset, min_length, .. } => {
664 p = format!("{p}[{offset:?} of {min_length:?}]");
665 need_parens = false;
666 }
667 }
668 }
669 write!(f, "{p}")
670 }
671}
672
673impl fmt::Debug for Rvalue<'_> {
674 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
675 match self {
676 Rvalue::Use(op) => write!(f, "{op:?}"),
677 Rvalue::Ref(r, BorrowKind::Mut { .. }, place) => {
678 write!(f, "&{} mut {place:?}", region_to_string(*r))
679 }
680 Rvalue::Ref(r, BorrowKind::Shared, place) => {
681 write!(f, "&{} {place:?}", region_to_string(*r))
682 }
683 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Shallow), place) => {
684 write!(f, "&{} fake shallow {place:?}", region_to_string(*r))
685 }
686 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Deep), place) => {
687 write!(f, "&{} fake deep {place:?}", region_to_string(*r))
688 }
689 Rvalue::RawPtr(mutbl, place) => write!(f, "&raw {} {place:?}", mutbl.ptr_str()),
690 Rvalue::Discriminant(place) => write!(f, "discriminant({place:?})"),
691 Rvalue::BinaryOp(bin_op, op1, op2) => write!(f, "{bin_op:?}({op1:?}, {op2:?})"),
692 Rvalue::UnaryOp(un_op, op) => write!(f, "{un_op:?}({op:?})"),
693 Rvalue::Aggregate(AggregateKind::Adt(def_id, variant_idx, args, _, _), operands) => {
694 let (fname, variant_name) = rustc_middle::ty::tls::with(|tcx| {
695 let variant_name = tcx.adt_def(*def_id).variant(*variant_idx).name;
696 let fname = tcx.def_path_str(*def_id);
697 (fname, variant_name)
698 });
699 write!(f, "{fname}::{variant_name}")?;
700 if !args.is_empty() {
701 write!(f, "<{:?}>", args.iter().format(", "),)?;
702 }
703 if !operands.is_empty() {
704 write!(f, "({:?})", operands.iter().format(", "))?;
705 }
706 Ok(())
707 }
708 Rvalue::Aggregate(AggregateKind::Closure(def_id, args), operands) => {
709 write!(
710 f,
711 "closure({}, {args:?}, {:?})",
712 def_id_to_string(*def_id),
713 operands.iter().format(", ")
714 )
715 }
716 Rvalue::Aggregate(AggregateKind::Coroutine(def_id, args), operands) => {
717 write!(
718 f,
719 "generator({}, {args:?}, {:?})",
720 def_id_to_string(*def_id),
721 operands.iter().format(", ")
722 )
723 }
724 Rvalue::Aggregate(AggregateKind::Array(_), args) => {
725 write!(f, "[{:?}]", args.iter().format(", "))
726 }
727 Rvalue::Aggregate(AggregateKind::Tuple, args) => {
728 write!(f, "({:?})", args.iter().format(", "))
729 }
730 Rvalue::Cast(kind, op, ty) => write!(f, "{op:?} as {ty:?} [{kind:?}]"),
731 Rvalue::Repeat(op, c) => write!(f, "[{op:?}; {c:?}]"),
732 Rvalue::ShallowInitBox(op, ty) => write!(f, "ShallowInitBox({op:?}, {ty:?})"),
733 }
734 }
735}
736
737impl fmt::Debug for PointerCast {
738 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739 match self {
740 PointerCast::MutToConstPointer => write!(f, "MutToConstPointer"),
741 PointerCast::Unsize => write!(f, "Unsize"),
742 PointerCast::ClosureFnPointer => write!(f, "ClosureFnPointer"),
743 PointerCast::ReifyFnPointer => write!(f, "ReifyFnPointer"),
744 }
745 }
746}
747
748impl fmt::Debug for CastKind {
749 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
750 match self {
751 CastKind::IntToInt => write!(f, "IntToInt"),
752 CastKind::FloatToInt => write!(f, "FloatToInt"),
753 CastKind::IntToFloat => write!(f, "IntToFloat"),
754 CastKind::PtrToPtr => write!(f, "PtrToPtr"),
755 CastKind::PointerCoercion(c) => write!(f, "Pointer({c:?})"),
756 CastKind::PointerExposeProvenance => write!(f, "PointerExposeProvenance"),
757 CastKind::PointerWithExposedProvenance => write!(f, "PointerWithExposedProvenance"),
758 }
759 }
760}
761
762impl fmt::Debug for Operand<'_> {
763 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764 match self {
765 Self::Copy(place) => write!(f, "copy {place:?}"),
766 Self::Move(place) => write!(f, "move {place:?}"),
767 Self::Constant(c) => write!(f, "{:?}", c.const_),
768 }
769 }
770}
771
772fn opt_bb_to_str(bb: Option<BasicBlock>) -> String {
773 match bb {
774 Some(bb) => format!("{bb:?}"),
775 None => "None".to_string(),
776 }
777}