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