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