rustc_smir/rustc_smir/convert/
mir.rs

1//! Conversion of internal Rust compiler `mir` items to stable ones.
2
3use rustc_middle::mir::interpret::alloc_range;
4use rustc_middle::mir::mono::MonoItem;
5use rustc_middle::{bug, mir};
6use stable_mir::mir::alloc::GlobalAlloc;
7use stable_mir::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment};
8use stable_mir::ty::{Allocation, ConstantKind, MirConst};
9use stable_mir::{Error, opaque};
10
11use crate::rustc_smir::{Stable, Tables, alloc};
12
13impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
14    type T = stable_mir::mir::Body;
15
16    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
17        stable_mir::mir::Body::new(
18            self.basic_blocks
19                .iter()
20                .map(|block| stable_mir::mir::BasicBlock {
21                    terminator: block.terminator().stable(tables),
22                    statements: block
23                        .statements
24                        .iter()
25                        .map(|statement| statement.stable(tables))
26                        .collect(),
27                })
28                .collect(),
29            self.local_decls
30                .iter()
31                .map(|decl| stable_mir::mir::LocalDecl {
32                    ty: decl.ty.stable(tables),
33                    span: decl.source_info.span.stable(tables),
34                    mutability: decl.mutability.stable(tables),
35                })
36                .collect(),
37            self.arg_count,
38            self.var_debug_info.iter().map(|info| info.stable(tables)).collect(),
39            self.spread_arg.stable(tables),
40            self.span.stable(tables),
41        )
42    }
43}
44
45impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> {
46    type T = stable_mir::mir::VarDebugInfo;
47    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
48        stable_mir::mir::VarDebugInfo {
49            name: self.name.to_string(),
50            source_info: self.source_info.stable(tables),
51            composite: self.composite.as_ref().map(|composite| composite.stable(tables)),
52            value: self.value.stable(tables),
53            argument_index: self.argument_index,
54        }
55    }
56}
57
58impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
59    type T = stable_mir::mir::Statement;
60    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
61        Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
62    }
63}
64
65impl<'tcx> Stable<'tcx> for mir::SourceInfo {
66    type T = stable_mir::mir::SourceInfo;
67    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
68        stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() }
69    }
70}
71
72impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> {
73    type T = stable_mir::mir::VarDebugInfoFragment;
74    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
75        VarDebugInfoFragment {
76            ty: self.ty.stable(tables),
77            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
78        }
79    }
80}
81
82impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> {
83    type T = stable_mir::mir::VarDebugInfoContents;
84    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
85        match self {
86            mir::VarDebugInfoContents::Place(place) => {
87                stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables))
88            }
89            mir::VarDebugInfoContents::Const(const_operand) => {
90                let op = ConstOperand {
91                    span: const_operand.span.stable(tables),
92                    user_ty: const_operand.user_ty.map(|index| index.as_usize()),
93                    const_: const_operand.const_.stable(tables),
94                };
95                stable_mir::mir::VarDebugInfoContents::Const(op)
96            }
97        }
98    }
99}
100
101impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
102    type T = stable_mir::mir::StatementKind;
103    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
104        match self {
105            mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign(
106                assign.0.stable(tables),
107                assign.1.stable(tables),
108            ),
109            mir::StatementKind::FakeRead(fake_read_place) => {
110                stable_mir::mir::StatementKind::FakeRead(
111                    fake_read_place.0.stable(tables),
112                    fake_read_place.1.stable(tables),
113                )
114            }
115            mir::StatementKind::SetDiscriminant { place, variant_index } => {
116                stable_mir::mir::StatementKind::SetDiscriminant {
117                    place: place.as_ref().stable(tables),
118                    variant_index: variant_index.stable(tables),
119                }
120            }
121            mir::StatementKind::Deinit(place) => {
122                stable_mir::mir::StatementKind::Deinit(place.stable(tables))
123            }
124
125            mir::StatementKind::StorageLive(place) => {
126                stable_mir::mir::StatementKind::StorageLive(place.stable(tables))
127            }
128
129            mir::StatementKind::StorageDead(place) => {
130                stable_mir::mir::StatementKind::StorageDead(place.stable(tables))
131            }
132            mir::StatementKind::Retag(retag, place) => {
133                stable_mir::mir::StatementKind::Retag(retag.stable(tables), place.stable(tables))
134            }
135            mir::StatementKind::PlaceMention(place) => {
136                stable_mir::mir::StatementKind::PlaceMention(place.stable(tables))
137            }
138            mir::StatementKind::AscribeUserType(place_projection, variance) => {
139                stable_mir::mir::StatementKind::AscribeUserType {
140                    place: place_projection.as_ref().0.stable(tables),
141                    projections: place_projection.as_ref().1.stable(tables),
142                    variance: variance.stable(tables),
143                }
144            }
145            mir::StatementKind::Coverage(coverage) => {
146                stable_mir::mir::StatementKind::Coverage(opaque(coverage))
147            }
148            mir::StatementKind::Intrinsic(intrinstic) => {
149                stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables))
150            }
151            mir::StatementKind::ConstEvalCounter => {
152                stable_mir::mir::StatementKind::ConstEvalCounter
153            }
154            // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop.
155            mir::StatementKind::BackwardIncompatibleDropHint { .. } => {
156                stable_mir::mir::StatementKind::Nop
157            }
158            mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop,
159        }
160    }
161}
162
163impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
164    type T = stable_mir::mir::Rvalue;
165    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
166        use rustc_middle::mir::Rvalue::*;
167        match self {
168            Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)),
169            Repeat(op, len) => {
170                let len = len.stable(tables);
171                stable_mir::mir::Rvalue::Repeat(op.stable(tables), len)
172            }
173            Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref(
174                region.stable(tables),
175                kind.stable(tables),
176                place.stable(tables),
177            ),
178            ThreadLocalRef(def_id) => {
179                stable_mir::mir::Rvalue::ThreadLocalRef(tables.crate_item(*def_id))
180            }
181            RawPtr(mutability, place) => {
182                stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
183            }
184            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
185            Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
186                cast_kind.stable(tables),
187                op.stable(tables),
188                ty.stable(tables),
189            ),
190            BinaryOp(bin_op, ops) => {
191                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
192                    stable_mir::mir::Rvalue::CheckedBinaryOp(
193                        bin_op.stable(tables),
194                        ops.0.stable(tables),
195                        ops.1.stable(tables),
196                    )
197                } else {
198                    stable_mir::mir::Rvalue::BinaryOp(
199                        bin_op.stable(tables),
200                        ops.0.stable(tables),
201                        ops.1.stable(tables),
202                    )
203                }
204            }
205            NullaryOp(null_op, ty) => {
206                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
207            }
208            UnaryOp(un_op, op) => {
209                stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
210            }
211            Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)),
212            Aggregate(agg_kind, operands) => {
213                let operands = operands.iter().map(|op| op.stable(tables)).collect();
214                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
215            }
216            ShallowInitBox(op, ty) => {
217                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
218            }
219            CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
220            WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
221        }
222    }
223}
224
225impl<'tcx> Stable<'tcx> for mir::Mutability {
226    type T = stable_mir::mir::Mutability;
227    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
228        use rustc_hir::Mutability::*;
229        match *self {
230            Not => stable_mir::mir::Mutability::Not,
231            Mut => stable_mir::mir::Mutability::Mut,
232        }
233    }
234}
235
236impl<'tcx> Stable<'tcx> for mir::RawPtrKind {
237    type T = stable_mir::mir::RawPtrKind;
238    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
239        use mir::RawPtrKind::*;
240        match *self {
241            Const => stable_mir::mir::RawPtrKind::Const,
242            Mut => stable_mir::mir::RawPtrKind::Mut,
243            FakeForPtrMetadata => stable_mir::mir::RawPtrKind::FakeForPtrMetadata,
244        }
245    }
246}
247
248impl<'tcx> Stable<'tcx> for mir::BorrowKind {
249    type T = stable_mir::mir::BorrowKind;
250    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
251        use rustc_middle::mir::BorrowKind::*;
252        match *self {
253            Shared => stable_mir::mir::BorrowKind::Shared,
254            Fake(kind) => stable_mir::mir::BorrowKind::Fake(kind.stable(tables)),
255            Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
256        }
257    }
258}
259
260impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
261    type T = stable_mir::mir::MutBorrowKind;
262    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
263        use rustc_middle::mir::MutBorrowKind::*;
264        match *self {
265            Default => stable_mir::mir::MutBorrowKind::Default,
266            TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow,
267            ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture,
268        }
269    }
270}
271
272impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
273    type T = stable_mir::mir::FakeBorrowKind;
274    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
275        use rustc_middle::mir::FakeBorrowKind::*;
276        match *self {
277            Deep => stable_mir::mir::FakeBorrowKind::Deep,
278            Shallow => stable_mir::mir::FakeBorrowKind::Shallow,
279        }
280    }
281}
282
283impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
284    type T = stable_mir::mir::NullOp;
285    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
286        use rustc_middle::mir::NullOp::*;
287        match self {
288            SizeOf => stable_mir::mir::NullOp::SizeOf,
289            AlignOf => stable_mir::mir::NullOp::AlignOf,
290            OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
291                indices.iter().map(|idx| idx.stable(tables)).collect(),
292            ),
293            UbChecks => stable_mir::mir::NullOp::UbChecks,
294            ContractChecks => stable_mir::mir::NullOp::ContractChecks,
295        }
296    }
297}
298
299impl<'tcx> Stable<'tcx> for mir::CastKind {
300    type T = stable_mir::mir::CastKind;
301    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
302        use rustc_middle::mir::CastKind::*;
303        use rustc_middle::ty::adjustment::PointerCoercion;
304        match self {
305            PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress,
306            PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
307            PointerCoercion(PointerCoercion::DynStar, _) => stable_mir::mir::CastKind::DynStar,
308            PointerCoercion(c, _) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
309            IntToInt => stable_mir::mir::CastKind::IntToInt,
310            FloatToInt => stable_mir::mir::CastKind::FloatToInt,
311            FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
312            IntToFloat => stable_mir::mir::CastKind::IntToFloat,
313            PtrToPtr => stable_mir::mir::CastKind::PtrToPtr,
314            FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr,
315            Transmute => stable_mir::mir::CastKind::Transmute,
316        }
317    }
318}
319
320impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
321    type T = stable_mir::mir::FakeReadCause;
322    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
323        use rustc_middle::mir::FakeReadCause::*;
324        match self {
325            ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
326            ForMatchedPlace(local_def_id) => {
327                stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id))
328            }
329            ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding,
330            ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)),
331            ForIndex => stable_mir::mir::FakeReadCause::ForIndex,
332        }
333    }
334}
335
336impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
337    type T = stable_mir::mir::Operand;
338    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
339        use rustc_middle::mir::Operand::*;
340        match self {
341            Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)),
342            Move(place) => stable_mir::mir::Operand::Move(place.stable(tables)),
343            Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables)),
344        }
345    }
346}
347
348impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
349    type T = stable_mir::mir::ConstOperand;
350
351    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
352        stable_mir::mir::ConstOperand {
353            span: self.span.stable(tables),
354            user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
355            const_: self.const_.stable(tables),
356        }
357    }
358}
359
360impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
361    type T = stable_mir::mir::Place;
362    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
363        stable_mir::mir::Place {
364            local: self.local.as_usize(),
365            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
366        }
367    }
368}
369
370impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
371    type T = stable_mir::mir::ProjectionElem;
372    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
373        use rustc_middle::mir::ProjectionElem::*;
374        match self {
375            Deref => stable_mir::mir::ProjectionElem::Deref,
376            Field(idx, ty) => {
377                stable_mir::mir::ProjectionElem::Field(idx.stable(tables), ty.stable(tables))
378            }
379            Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables)),
380            ConstantIndex { offset, min_length, from_end } => {
381                stable_mir::mir::ProjectionElem::ConstantIndex {
382                    offset: *offset,
383                    min_length: *min_length,
384                    from_end: *from_end,
385                }
386            }
387            Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice {
388                from: *from,
389                to: *to,
390                from_end: *from_end,
391            },
392            // MIR includes an `Option<Symbol>` argument for `Downcast` that is the name of the
393            // variant, used for printing MIR. However this information should also be accessible
394            // via a lookup using the `VariantIdx`. The `Option<Symbol>` argument is therefore
395            // dropped when converting to Stable MIR. A brief justification for this decision can be
396            // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486
397            Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
398            OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
399            Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
400            UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
401        }
402    }
403}
404
405impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
406    type T = stable_mir::mir::UserTypeProjection;
407
408    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
409        UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) }
410    }
411}
412
413impl<'tcx> Stable<'tcx> for mir::Local {
414    type T = stable_mir::mir::Local;
415    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
416        self.as_usize()
417    }
418}
419
420impl<'tcx> Stable<'tcx> for mir::RetagKind {
421    type T = stable_mir::mir::RetagKind;
422    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
423        use rustc_middle::mir::RetagKind;
424        match self {
425            RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
426            RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase,
427            RetagKind::Raw => stable_mir::mir::RetagKind::Raw,
428            RetagKind::Default => stable_mir::mir::RetagKind::Default,
429        }
430    }
431}
432
433impl<'tcx> Stable<'tcx> for mir::UnwindAction {
434    type T = stable_mir::mir::UnwindAction;
435    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
436        use rustc_middle::mir::UnwindAction;
437        match self {
438            UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
439            UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
440            UnwindAction::Terminate(_) => stable_mir::mir::UnwindAction::Terminate,
441            UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
442        }
443    }
444}
445
446impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
447    type T = stable_mir::mir::NonDivergingIntrinsic;
448
449    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
450        use rustc_middle::mir::NonDivergingIntrinsic;
451        use stable_mir::mir::CopyNonOverlapping;
452        match self {
453            NonDivergingIntrinsic::Assume(op) => {
454                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
455            }
456            NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
457                stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
458                    src: copy_non_overlapping.src.stable(tables),
459                    dst: copy_non_overlapping.dst.stable(tables),
460                    count: copy_non_overlapping.count.stable(tables),
461                })
462            }
463        }
464    }
465}
466
467impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
468    type T = stable_mir::mir::AssertMessage;
469    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
470        use rustc_middle::mir::AssertKind;
471        match self {
472            AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
473                len: len.stable(tables),
474                index: index.stable(tables),
475            },
476            AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
477                bin_op.stable(tables),
478                op1.stable(tables),
479                op2.stable(tables),
480            ),
481            AssertKind::OverflowNeg(op) => {
482                stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables))
483            }
484            AssertKind::DivisionByZero(op) => {
485                stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables))
486            }
487            AssertKind::RemainderByZero(op) => {
488                stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables))
489            }
490            AssertKind::ResumedAfterReturn(coroutine) => {
491                stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables))
492            }
493            AssertKind::ResumedAfterPanic(coroutine) => {
494                stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables))
495            }
496            AssertKind::MisalignedPointerDereference { required, found } => {
497                stable_mir::mir::AssertMessage::MisalignedPointerDereference {
498                    required: required.stable(tables),
499                    found: found.stable(tables),
500                }
501            }
502            AssertKind::NullPointerDereference => {
503                stable_mir::mir::AssertMessage::NullPointerDereference
504            }
505        }
506    }
507}
508
509impl<'tcx> Stable<'tcx> for mir::BinOp {
510    type T = stable_mir::mir::BinOp;
511    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
512        use rustc_middle::mir::BinOp;
513        match self {
514            BinOp::Add => stable_mir::mir::BinOp::Add,
515            BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked,
516            BinOp::AddWithOverflow => bug!("AddWithOverflow should have been translated already"),
517            BinOp::Sub => stable_mir::mir::BinOp::Sub,
518            BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked,
519            BinOp::SubWithOverflow => bug!("AddWithOverflow should have been translated already"),
520            BinOp::Mul => stable_mir::mir::BinOp::Mul,
521            BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked,
522            BinOp::MulWithOverflow => bug!("AddWithOverflow should have been translated already"),
523            BinOp::Div => stable_mir::mir::BinOp::Div,
524            BinOp::Rem => stable_mir::mir::BinOp::Rem,
525            BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
526            BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
527            BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
528            BinOp::Shl => stable_mir::mir::BinOp::Shl,
529            BinOp::ShlUnchecked => stable_mir::mir::BinOp::ShlUnchecked,
530            BinOp::Shr => stable_mir::mir::BinOp::Shr,
531            BinOp::ShrUnchecked => stable_mir::mir::BinOp::ShrUnchecked,
532            BinOp::Eq => stable_mir::mir::BinOp::Eq,
533            BinOp::Lt => stable_mir::mir::BinOp::Lt,
534            BinOp::Le => stable_mir::mir::BinOp::Le,
535            BinOp::Ne => stable_mir::mir::BinOp::Ne,
536            BinOp::Ge => stable_mir::mir::BinOp::Ge,
537            BinOp::Gt => stable_mir::mir::BinOp::Gt,
538            BinOp::Cmp => stable_mir::mir::BinOp::Cmp,
539            BinOp::Offset => stable_mir::mir::BinOp::Offset,
540        }
541    }
542}
543
544impl<'tcx> Stable<'tcx> for mir::UnOp {
545    type T = stable_mir::mir::UnOp;
546    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
547        use rustc_middle::mir::UnOp;
548        match self {
549            UnOp::Not => stable_mir::mir::UnOp::Not,
550            UnOp::Neg => stable_mir::mir::UnOp::Neg,
551            UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata,
552        }
553    }
554}
555
556impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
557    type T = stable_mir::mir::AggregateKind;
558    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
559        match self {
560            mir::AggregateKind::Array(ty) => {
561                stable_mir::mir::AggregateKind::Array(ty.stable(tables))
562            }
563            mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
564            mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
565                stable_mir::mir::AggregateKind::Adt(
566                    tables.adt_def(*def_id),
567                    var_idx.stable(tables),
568                    generic_arg.stable(tables),
569                    user_ty_index.map(|idx| idx.index()),
570                    field_idx.map(|idx| idx.index()),
571                )
572            }
573            mir::AggregateKind::Closure(def_id, generic_arg) => {
574                stable_mir::mir::AggregateKind::Closure(
575                    tables.closure_def(*def_id),
576                    generic_arg.stable(tables),
577                )
578            }
579            mir::AggregateKind::Coroutine(def_id, generic_arg) => {
580                stable_mir::mir::AggregateKind::Coroutine(
581                    tables.coroutine_def(*def_id),
582                    generic_arg.stable(tables),
583                    tables.tcx.coroutine_movability(*def_id).stable(tables),
584                )
585            }
586            mir::AggregateKind::CoroutineClosure(def_id, generic_args) => {
587                stable_mir::mir::AggregateKind::CoroutineClosure(
588                    tables.coroutine_closure_def(*def_id),
589                    generic_args.stable(tables),
590                )
591            }
592            mir::AggregateKind::RawPtr(ty, mutability) => {
593                stable_mir::mir::AggregateKind::RawPtr(ty.stable(tables), mutability.stable(tables))
594            }
595        }
596    }
597}
598
599impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
600    type T = stable_mir::mir::InlineAsmOperand;
601    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
602        use rustc_middle::mir::InlineAsmOperand;
603
604        let (in_value, out_place) = match self {
605            InlineAsmOperand::In { value, .. } => (Some(value.stable(tables)), None),
606            InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable(tables))),
607            InlineAsmOperand::InOut { in_value, out_place, .. } => {
608                (Some(in_value.stable(tables)), out_place.map(|place| place.stable(tables)))
609            }
610            InlineAsmOperand::Const { .. }
611            | InlineAsmOperand::SymFn { .. }
612            | InlineAsmOperand::SymStatic { .. }
613            | InlineAsmOperand::Label { .. } => (None, None),
614        };
615
616        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") }
617    }
618}
619
620impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
621    type T = stable_mir::mir::Terminator;
622    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
623        use stable_mir::mir::Terminator;
624        Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
625    }
626}
627
628impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
629    type T = stable_mir::mir::TerminatorKind;
630    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
631        use stable_mir::mir::TerminatorKind;
632        match self {
633            mir::TerminatorKind::Goto { target } => {
634                TerminatorKind::Goto { target: target.as_usize() }
635            }
636            mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
637                discr: discr.stable(tables),
638                targets: {
639                    let branches = targets.iter().map(|(val, target)| (val, target.as_usize()));
640                    stable_mir::mir::SwitchTargets::new(
641                        branches.collect(),
642                        targets.otherwise().as_usize(),
643                    )
644                },
645            },
646            mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
647            mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
648            mir::TerminatorKind::Return => TerminatorKind::Return,
649            mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable,
650            mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
651                TerminatorKind::Drop {
652                    place: place.stable(tables),
653                    target: target.as_usize(),
654                    unwind: unwind.stable(tables),
655                }
656            }
657            mir::TerminatorKind::Call {
658                func,
659                args,
660                destination,
661                target,
662                unwind,
663                call_source: _,
664                fn_span: _,
665            } => TerminatorKind::Call {
666                func: func.stable(tables),
667                args: args.iter().map(|arg| arg.node.stable(tables)).collect(),
668                destination: destination.stable(tables),
669                target: target.map(|t| t.as_usize()),
670                unwind: unwind.stable(tables),
671            },
672            mir::TerminatorKind::TailCall { func: _, args: _, fn_span: _ } => todo!(),
673            mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => {
674                TerminatorKind::Assert {
675                    cond: cond.stable(tables),
676                    expected: *expected,
677                    msg: msg.stable(tables),
678                    target: target.as_usize(),
679                    unwind: unwind.stable(tables),
680                }
681            }
682            mir::TerminatorKind::InlineAsm {
683                asm_macro: _,
684                template,
685                operands,
686                options,
687                line_spans,
688                targets,
689                unwind,
690            } => TerminatorKind::InlineAsm {
691                template: format!("{template:?}"),
692                operands: operands.iter().map(|operand| operand.stable(tables)).collect(),
693                options: format!("{options:?}"),
694                line_spans: format!("{line_spans:?}"),
695                // FIXME: Figure out how to do labels in SMIR
696                destination: targets.first().map(|d| d.as_usize()),
697                unwind: unwind.stable(tables),
698            },
699            mir::TerminatorKind::Yield { .. }
700            | mir::TerminatorKind::CoroutineDrop
701            | mir::TerminatorKind::FalseEdge { .. }
702            | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(),
703        }
704    }
705}
706
707impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> {
708    type T = Allocation;
709
710    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
711        self.inner().stable(tables)
712    }
713}
714
715impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
716    type T = stable_mir::ty::Allocation;
717
718    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
719        alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables)
720    }
721}
722
723impl<'tcx> Stable<'tcx> for mir::interpret::AllocId {
724    type T = stable_mir::mir::alloc::AllocId;
725    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
726        tables.create_alloc_id(*self)
727    }
728}
729
730impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
731    type T = GlobalAlloc;
732
733    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
734        match self {
735            mir::interpret::GlobalAlloc::Function { instance, .. } => {
736                GlobalAlloc::Function(instance.stable(tables))
737            }
738            mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => {
739                // FIXME: Should we record the whole vtable?
740                GlobalAlloc::VTable(ty.stable(tables), dyn_ty.principal().stable(tables))
741            }
742            mir::interpret::GlobalAlloc::Static(def) => {
743                GlobalAlloc::Static(tables.static_def(*def))
744            }
745            mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)),
746        }
747    }
748}
749
750impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
751    type T = stable_mir::ty::MirConst;
752
753    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
754        let id = tables.intern_mir_const(tables.tcx.lift(*self).unwrap());
755        match *self {
756            mir::Const::Ty(ty, c) => MirConst::new(
757                stable_mir::ty::ConstantKind::Ty(c.stable(tables)),
758                ty.stable(tables),
759                id,
760            ),
761            mir::Const::Unevaluated(unev_const, ty) => {
762                let kind =
763                    stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
764                        def: tables.const_def(unev_const.def),
765                        args: unev_const.args.stable(tables),
766                        promoted: unev_const.promoted.map(|u| u.as_u32()),
767                    });
768                let ty = ty.stable(tables);
769                MirConst::new(kind, ty, id)
770            }
771            mir::Const::Val(mir::ConstValue::ZeroSized, ty) => {
772                let ty = ty.stable(tables);
773                MirConst::new(ConstantKind::ZeroSized, ty, id)
774            }
775            mir::Const::Val(val, ty) => {
776                let ty = tables.tcx.lift(ty).unwrap();
777                let val = tables.tcx.lift(val).unwrap();
778                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
779                let ty = ty.stable(tables);
780                MirConst::new(kind, ty, id)
781            }
782        }
783    }
784}
785
786impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled {
787    type T = Error;
788
789    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
790        Error::new(format!("{self:?}"))
791    }
792}
793
794impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
795    type T = stable_mir::mir::mono::MonoItem;
796
797    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
798        use stable_mir::mir::mono::MonoItem as StableMonoItem;
799        match self {
800            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)),
801            MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)),
802            MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)),
803        }
804    }
805}