stable_mir/mir/
mono.rs

1use std::fmt::{Debug, Formatter};
2use std::io;
3
4use serde::Serialize;
5
6use crate::abi::FnAbi;
7use crate::crate_def::CrateDef;
8use crate::mir::Body;
9use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
10use crate::{CrateItem, DefId, Error, ItemKind, Opaque, Symbol, with};
11
12#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
13pub enum MonoItem {
14    Fn(Instance),
15    Static(StaticDef),
16    GlobalAsm(Opaque),
17}
18
19#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)]
20pub struct Instance {
21    /// The type of instance.
22    pub kind: InstanceKind,
23    /// An ID used to get the instance definition from the compiler.
24    /// Do not use this field directly.
25    pub def: InstanceDef,
26}
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
29pub enum InstanceKind {
30    /// A user defined item.
31    Item,
32    /// A compiler intrinsic function.
33    Intrinsic,
34    /// A virtual function definition stored in a VTable.
35    /// The `idx` field indicates the position in the VTable for this instance.
36    Virtual { idx: usize },
37    /// A compiler generated shim.
38    Shim,
39}
40
41impl Instance {
42    /// Get the arguments this instance was instantiated with.
43    pub fn args(&self) -> GenericArgs {
44        with(|cx| cx.instance_args(self.def))
45    }
46
47    /// Get the body of an Instance.
48    ///
49    /// The body will be eagerly monomorphized and all constants will already be evaluated.
50    ///
51    /// This method will return the intrinsic fallback body if one was defined.
52    pub fn body(&self) -> Option<Body> {
53        with(|context| context.instance_body(self.def))
54    }
55
56    /// Check whether this instance has a body available.
57    ///
58    /// For intrinsics with fallback body, this will return `true`. It is up to the user to decide
59    /// whether to specialize the intrinsic or to use its fallback body.
60    ///
61    /// For more information on fallback body, see <https://github.com/rust-lang/rust/issues/93145>.
62    ///
63    /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build
64    /// the StableMIR body.
65    pub fn has_body(&self) -> bool {
66        with(|cx| cx.has_body(self.def.def_id()))
67    }
68
69    pub fn is_foreign_item(&self) -> bool {
70        with(|cx| cx.is_foreign_item(self.def.def_id()))
71    }
72
73    /// Get the instance type with generic instantiations applied and lifetimes erased.
74    pub fn ty(&self) -> Ty {
75        with(|context| context.instance_ty(self.def))
76    }
77
78    /// Retrieve information about this instance binary interface.
79    pub fn fn_abi(&self) -> Result<FnAbi, Error> {
80        with(|cx| cx.instance_abi(self.def))
81    }
82
83    /// Retrieve the instance's mangled name used for calling the given instance.
84    ///
85    /// This will also look up the correct name of instances from upstream crates.
86    pub fn mangled_name(&self) -> Symbol {
87        with(|context| context.instance_mangled_name(self.def))
88    }
89
90    /// Retrieve the instance name for diagnostic messages.
91    ///
92    /// This will return the specialized name, e.g., `std::vec::Vec<u8>::new`.
93    pub fn name(&self) -> Symbol {
94        with(|context| context.instance_name(self.def, false))
95    }
96
97    /// Return a trimmed name of the given instance including its args.
98    ///
99    /// If a symbol name can only be imported from one place for a type, and as
100    /// long as it was not glob-imported anywhere in the current crate, we trim its
101    /// path and print only the name.
102    pub fn trimmed_name(&self) -> Symbol {
103        with(|context| context.instance_name(self.def, true))
104    }
105
106    /// Retrieve the plain intrinsic name of an instance if it's an intrinsic.
107    ///
108    /// The plain name does not include type arguments (as `trimmed_name` does),
109    /// which is more convenient to match with intrinsic symbols.
110    pub fn intrinsic_name(&self) -> Option<Symbol> {
111        match self.kind {
112            InstanceKind::Intrinsic => {
113                Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name()))
114            }
115            InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None,
116        }
117    }
118
119    /// Resolve an instance starting from a function definition and generic arguments.
120    pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
121        with(|context| {
122            context.resolve_instance(def, args).ok_or_else(|| {
123                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
124            })
125        })
126    }
127
128    /// Resolve the drop in place for a given type.
129    pub fn resolve_drop_in_place(ty: Ty) -> Instance {
130        with(|cx| cx.resolve_drop_in_place(ty))
131    }
132
133    /// Resolve an instance for a given function pointer.
134    pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
135        with(|context| {
136            context.resolve_for_fn_ptr(def, args).ok_or_else(|| {
137                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
138            })
139        })
140    }
141
142    /// Resolve a closure with the expected kind.
143    pub fn resolve_closure(
144        def: ClosureDef,
145        args: &GenericArgs,
146        kind: ClosureKind,
147    ) -> Result<Instance, crate::Error> {
148        with(|context| {
149            context.resolve_closure(def, args, kind).ok_or_else(|| {
150                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
151            })
152        })
153    }
154
155    /// Check whether this instance is an empty shim.
156    ///
157    /// Allow users to check if this shim can be ignored when called directly.
158    ///
159    /// We have decided not to export different types of Shims to StableMIR users, however, this
160    /// is a query that can be very helpful for users when processing DropGlue.
161    ///
162    /// When generating code for a Drop terminator, users can ignore an empty drop glue.
163    /// These shims are only needed to generate a valid Drop call done via VTable.
164    pub fn is_empty_shim(&self) -> bool {
165        self.kind == InstanceKind::Shim
166            && with(|cx| {
167                cx.is_empty_drop_shim(self.def) || cx.is_empty_async_drop_ctor_shim(self.def)
168            })
169    }
170
171    /// Try to constant evaluate the instance into a constant with the given type.
172    ///
173    /// This can be used to retrieve a constant that represents an intrinsic return such as
174    /// `type_id`.
175    pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
176        with(|cx| cx.eval_instance(self.def, const_ty))
177    }
178
179    /// Emit the body of this instance if it has one.
180    pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
181        if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) }
182    }
183}
184
185impl Debug for Instance {
186    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187        f.debug_struct("Instance")
188            .field("kind", &self.kind)
189            .field("def", &self.mangled_name())
190            .field("args", &self.args())
191            .finish()
192    }
193}
194
195/// Try to convert a crate item into an instance.
196/// The item cannot be generic in order to be converted into an instance.
197impl TryFrom<CrateItem> for Instance {
198    type Error = crate::Error;
199
200    fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
201        with(|context| {
202            let def_id = item.def_id();
203            if !context.requires_monomorphization(def_id) {
204                Ok(context.mono_instance(def_id))
205            } else {
206                Err(Error::new("Item requires monomorphization".to_string()))
207            }
208        })
209    }
210}
211
212/// Try to convert an instance into a crate item.
213/// Only user defined instances can be converted.
214impl TryFrom<Instance> for CrateItem {
215    type Error = crate::Error;
216
217    fn try_from(value: Instance) -> Result<Self, Self::Error> {
218        with(|context| {
219            if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) {
220                Ok(CrateItem(context.instance_def_id(value.def)))
221            } else {
222                Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
223            }
224        })
225    }
226}
227
228impl From<Instance> for MonoItem {
229    fn from(value: Instance) -> Self {
230        MonoItem::Fn(value)
231    }
232}
233
234impl From<StaticDef> for MonoItem {
235    fn from(value: StaticDef) -> Self {
236        MonoItem::Static(value)
237    }
238}
239
240impl From<StaticDef> for CrateItem {
241    fn from(value: StaticDef) -> Self {
242        CrateItem(value.0)
243    }
244}
245
246#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
247pub struct InstanceDef(usize);
248
249impl CrateDef for InstanceDef {
250    fn def_id(&self) -> DefId {
251        with(|context| context.instance_def_id(*self))
252    }
253}
254
255crate_def! {
256    /// Holds information about a static variable definition.
257    #[derive(Serialize)]
258    pub StaticDef;
259}
260
261impl TryFrom<CrateItem> for StaticDef {
262    type Error = crate::Error;
263
264    fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
265        if matches!(value.kind(), ItemKind::Static) {
266            Ok(StaticDef(value.0))
267        } else {
268            Err(Error::new(format!("Expected a static item, but found: {value:?}")))
269        }
270    }
271}
272
273impl TryFrom<Instance> for StaticDef {
274    type Error = crate::Error;
275
276    fn try_from(value: Instance) -> Result<Self, Self::Error> {
277        StaticDef::try_from(CrateItem::try_from(value)?)
278    }
279}
280
281impl From<StaticDef> for Instance {
282    fn from(value: StaticDef) -> Self {
283        // A static definition should always be convertible to an instance.
284        with(|cx| cx.mono_instance(value.def_id()))
285    }
286}
287
288impl StaticDef {
289    /// Return the type of this static definition.
290    pub fn ty(&self) -> Ty {
291        with(|cx| cx.def_ty(self.0))
292    }
293
294    /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
295    pub fn eval_initializer(&self) -> Result<Allocation, Error> {
296        with(|cx| cx.eval_static_initializer(*self))
297    }
298}
299
300impl IndexedVal for InstanceDef {
301    fn to_val(index: usize) -> Self {
302        InstanceDef(index)
303    }
304    fn to_index(&self) -> usize {
305        self.0
306    }
307}