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