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| tcx.def_path_str(*resolved_id));
556 write!(f, "call {fname}")?;
557 if !resolved_args.lowered.is_empty() {
558 write!(f, "<{:?}>", resolved_args.lowered.iter().format(", "))?;
559 }
560 Ok(())
561 }
562 CallKind::FnPtr { fn_sig, operand } => write!(f, "FnPtr[{operand:?}]({fn_sig:?})"),
563 }
564 }
565}
566
567impl fmt::Debug for Terminator<'_> {
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569 match &self.kind {
570 TerminatorKind::Return => write!(f, "return"),
571 TerminatorKind::Unreachable => write!(f, "unreachable"),
572 TerminatorKind::Call { kind, args, destination, target, unwind, .. } => {
573 write!(
574 f,
575 "{destination:?} = call {kind:?}({args:?}) -> [return: {target}, unwind: {unwind:?}]",
576 args = args.iter().format(", "),
577 target = opt_bb_to_str(*target),
578 )
579 }
580 TerminatorKind::SwitchInt { discr, targets } => {
581 write!(
582 f,
583 "switchInt({discr:?}) -> [{}, otherwise: {:?}]",
584 targets
585 .iter()
586 .format_with(", ", |(val, bb), f| f(&format_args!("{val:?}: {bb:?}"))),
587 targets.otherwise()
588 )
589 }
590 TerminatorKind::Goto { target } => {
591 write!(f, "goto -> {target:?}")
592 }
593 TerminatorKind::Drop { place, target, unwind } => {
594 write!(f, "drop({place:?}) -> [{target:?}, unwind: {unwind:?}]",)
595 }
596 TerminatorKind::Assert { cond, target, expected, msg } => {
597 write!(
598 f,
599 "assert({cond:?} is expected to be {expected:?}, \"{msg:?}\") -> {target:?}"
600 )
601 }
602 TerminatorKind::FalseEdge { real_target, imaginary_target } => {
603 write!(f, "falseEdge -> [real: {real_target:?}, imaginary: {imaginary_target:?}]")
604 }
605 TerminatorKind::FalseUnwind { real_target, unwind } => {
606 write!(f, "falseUnwind -> [real: {real_target:?}, cleanup: {unwind:?}]")
607 }
608 TerminatorKind::UnwindResume => write!(f, "resume"),
609 TerminatorKind::CoroutineDrop => write!(f, "generator_drop"),
610 TerminatorKind::Yield { value, resume, drop, resume_arg } => {
611 write!(
612 f,
613 "{resume_arg:?} = yield({value:?}) -> [resume: {resume:?}, drop: {drop:?}]"
614 )
615 }
616 }
617 }
618}
619
620impl fmt::Debug for Place {
621 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622 write!(f, "{:?}", self.as_ref())
623 }
624}
625
626impl fmt::Debug for PlaceRef<'_> {
627 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
628 let mut p = format!("{:?}", self.local);
629 let mut need_parens = false;
630 for elem in self.projection {
631 match elem {
632 PlaceElem::Field(f) => {
633 if need_parens {
634 p = format!("({p}).{}", u32::from(*f));
635 need_parens = false;
636 } else {
637 p = format!("{p}.{}", u32::from(*f));
638 }
639 }
640 PlaceElem::Deref => {
641 p = format!("*{p}");
642 need_parens = true;
643 }
644 PlaceElem::Downcast(variant_name, variant_idx) => {
645 if let Some(variant_name) = variant_name {
646 p = format!("{p} as {variant_name}");
647 } else {
648 p = format!("{p} as {variant_idx:?}");
649 }
650 need_parens = true;
651 }
652 PlaceElem::Index(v) => {
653 p = format!("{p}[{v:?}]");
654 need_parens = false;
655 }
656 PlaceElem::ConstantIndex { offset, min_length, .. } => {
657 p = format!("{p}[{offset:?} of {min_length:?}]");
658 need_parens = false;
659 }
660 }
661 }
662 write!(f, "{p}")
663 }
664}
665
666impl fmt::Debug for Rvalue {
667 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668 match self {
669 Rvalue::Use(op) => write!(f, "{op:?}"),
670 Rvalue::Ref(r, BorrowKind::Mut { .. }, place) => {
671 write!(f, "&{} mut {place:?}", region_to_string(*r))
672 }
673 Rvalue::Ref(r, BorrowKind::Shared, place) => {
674 write!(f, "&{} {place:?}", region_to_string(*r))
675 }
676 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Shallow), place) => {
677 write!(f, "&{} fake shallow {place:?}", region_to_string(*r))
678 }
679 Rvalue::Ref(r, BorrowKind::Fake(FakeBorrowKind::Deep), place) => {
680 write!(f, "&{} fake deep {place:?}", region_to_string(*r))
681 }
682 Rvalue::RawPtr(mutbl, place) => write!(f, "&raw {} {place:?}", mutbl.ptr_str()),
683 Rvalue::Discriminant(place) => write!(f, "discriminant({place:?})"),
684 Rvalue::BinaryOp(bin_op, op1, op2) => write!(f, "{bin_op:?}({op1:?}, {op2:?})"),
685 Rvalue::NullaryOp(null_op, ty) => write!(f, "{null_op:?}({ty:?})"),
686 Rvalue::UnaryOp(un_op, op) => write!(f, "{un_op:?}({op:?})"),
687 Rvalue::Aggregate(AggregateKind::Adt(def_id, variant_idx, args, _, _), operands) => {
688 let (fname, variant_name) = rustc_middle::ty::tls::with(|tcx| {
689 let variant_name = tcx.adt_def(*def_id).variant(*variant_idx).name;
690 let fname = tcx.def_path_str(*def_id);
691 (fname, variant_name)
692 });
693 write!(f, "{fname}::{variant_name}")?;
694 if !args.is_empty() {
695 write!(f, "<{:?}>", args.iter().format(", "),)?;
696 }
697 if !operands.is_empty() {
698 write!(f, "({:?})", operands.iter().format(", "))?;
699 }
700 Ok(())
701 }
702 Rvalue::Aggregate(AggregateKind::Closure(def_id, args), operands) => {
703 write!(
704 f,
705 "closure({}, {args:?}, {:?})",
706 def_id_to_string(*def_id),
707 operands.iter().format(", ")
708 )
709 }
710 Rvalue::Aggregate(AggregateKind::Coroutine(def_id, args), operands) => {
711 write!(
712 f,
713 "generator({}, {args:?}, {:?})",
714 def_id_to_string(*def_id),
715 operands.iter().format(", ")
716 )
717 }
718 Rvalue::Aggregate(AggregateKind::Array(_), args) => {
719 write!(f, "[{:?}]", args.iter().format(", "))
720 }
721 Rvalue::Aggregate(AggregateKind::Tuple, args) => {
722 write!(f, "({:?})", args.iter().format(", "))
723 }
724 Rvalue::Len(place) => write!(f, "Len({place:?})"),
725 Rvalue::Cast(kind, op, ty) => write!(f, "{op:?} as {ty:?} [{kind:?}]"),
726 Rvalue::Repeat(op, c) => write!(f, "[{op:?}; {c:?}]"),
727 Rvalue::ShallowInitBox(op, ty) => write!(f, "ShallowInitBox({op:?}, {ty:?})"),
728 }
729 }
730}
731
732impl fmt::Debug for PointerCast {
733 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734 match self {
735 PointerCast::MutToConstPointer => write!(f, "MutToConstPointer"),
736 PointerCast::Unsize => write!(f, "Unsize"),
737 PointerCast::ClosureFnPointer => write!(f, "ClosureFnPointer"),
738 PointerCast::ReifyFnPointer => write!(f, "ReifyFnPointer"),
739 }
740 }
741}
742
743impl fmt::Debug for CastKind {
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 match self {
746 CastKind::IntToInt => write!(f, "IntToInt"),
747 CastKind::FloatToInt => write!(f, "FloatToInt"),
748 CastKind::IntToFloat => write!(f, "IntToFloat"),
749 CastKind::PtrToPtr => write!(f, "PtrToPtr"),
750 CastKind::PointerCoercion(c) => write!(f, "Pointer({c:?})"),
751 CastKind::PointerExposeProvenance => write!(f, "PointerExposeProvenance"),
752 CastKind::PointerWithExposedProvenance => write!(f, "PointerWithExposedProvenance"),
753 }
754 }
755}
756
757impl fmt::Debug for Operand {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
759 match self {
760 Self::Copy(place) => write!(f, "copy {place:?}"),
761 Self::Move(place) => write!(f, "move {place:?}"),
762 Self::Constant(c) => write!(f, "{c:?}"),
763 }
764 }
765}
766
767impl fmt::Debug for Constant {
768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
769 match self {
770 Constant::Int(n, int_ty) => write!(f, "{n}{}", int_ty.name_str()),
771 Constant::Uint(n, uint_ty) => write!(f, "{n}{}", uint_ty.name_str()),
772 Constant::Float(bits, float_ty) => write!(f, "{bits}{}", float_ty.name_str()),
773 Constant::Bool(b) => write!(f, "{b}"),
774 Constant::Unit => write!(f, "()"),
775 Constant::Str(s) => write!(f, "\"{s:?}\""),
776 Constant::Char(c) => write!(f, "\'{c}\'"),
777 Constant::Opaque(ty) => write!(f, "<opaque {ty:?}>"),
778 Constant::Param(p, _) => write!(f, "{p:?}"),
779 Constant::Unevaluated(ty, def_id) => write!(f, "<uneval {ty:?} from {def_id:?}>"),
780 }
781 }
782}
783
784fn opt_bb_to_str(bb: Option<BasicBlock>) -> String {
785 match bb {
786 Some(bb) => format!("{bb:?}"),
787 None => "None".to_string(),
788 }
789}