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