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