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