summaryrefslogtreecommitdiffstats
path: root/compiler/stable_mir
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/stable_mir')
-rw-r--r--compiler/stable_mir/src/error.rs76
-rw-r--r--compiler/stable_mir/src/fold.rs245
-rw-r--r--compiler/stable_mir/src/lib.rs150
-rw-r--r--compiler/stable_mir/src/mir.rs3
-rw-r--r--compiler/stable_mir/src/mir/body.rs184
-rw-r--r--compiler/stable_mir/src/mir/mono.rs102
-rw-r--r--compiler/stable_mir/src/mir/visit.rs414
-rw-r--r--compiler/stable_mir/src/ty.rs182
-rw-r--r--compiler/stable_mir/src/visitor.rs8
9 files changed, 958 insertions, 406 deletions
diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs
new file mode 100644
index 000000000..199106914
--- /dev/null
+++ b/compiler/stable_mir/src/error.rs
@@ -0,0 +1,76 @@
+//! When things go wrong, we need some error handling.
+//! There are a few different types of errors in StableMIR:
+//!
+//! - [CompilerError]: This represents errors that can be raised when invoking the compiler.
+//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
+
+use std::convert::From;
+use std::fmt::{Debug, Display, Formatter};
+use std::{error, fmt};
+
+/// An error type used to represent an error that has already been reported by the compiler.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum CompilerError<T> {
+ /// Internal compiler error (I.e.: Compiler crashed).
+ ICE,
+ /// Compilation failed.
+ CompilationFailed,
+ /// Compilation was interrupted.
+ Interrupted(T),
+ /// Compilation skipped. This happens when users invoke rustc to retrieve information such as
+ /// --version.
+ Skipped,
+}
+
+/// A generic error to represent an API request that cannot be fulfilled.
+#[derive(Debug)]
+pub struct Error(String);
+
+impl Error {
+ pub(crate) fn new(msg: String) -> Self {
+ Self(msg)
+ }
+}
+
+impl From<&str> for Error {
+ fn from(value: &str) -> Self {
+ Self(value.into())
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+}
+
+impl<T> Display for CompilerError<T>
+where
+ T: Display,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ CompilerError::ICE => write!(f, "Internal Compiler Error"),
+ CompilerError::CompilationFailed => write!(f, "Compilation Failed"),
+ CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"),
+ CompilerError::Skipped => write!(f, "Compilation Skipped"),
+ }
+ }
+}
+
+impl<T> Debug for CompilerError<T>
+where
+ T: Debug,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ CompilerError::ICE => write!(f, "Internal Compiler Error"),
+ CompilerError::CompilationFailed => write!(f, "Compilation Failed"),
+ CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"),
+ CompilerError::Skipped => write!(f, "Compilation Skipped"),
+ }
+ }
+}
+
+impl error::Error for Error {}
+impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
diff --git a/compiler/stable_mir/src/fold.rs b/compiler/stable_mir/src/fold.rs
deleted file mode 100644
index 6471b2c2a..000000000
--- a/compiler/stable_mir/src/fold.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-use std::ops::ControlFlow;
-
-use crate::Opaque;
-
-use super::ty::{
- Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind,
- GenericArgs, Promoted, Region, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst,
-};
-
-pub trait Folder: Sized {
- type Break;
- fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
- ty.super_fold(self)
- }
- fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
- c.super_fold(self)
- }
- fn fold_reg(&mut self, reg: &Region) -> ControlFlow<Self::Break, Region> {
- reg.super_fold(self)
- }
-}
-
-pub trait Foldable: Sized + Clone {
- fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- self.super_fold(folder)
- }
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self>;
-}
-
-impl Foldable for Ty {
- fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- folder.fold_ty(self)
- }
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut kind = self.kind();
- match &mut kind {
- super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?,
- super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?,
- super::ty::TyKind::Param(_) => {}
- super::ty::TyKind::Bound(_, _) => {}
- }
- ControlFlow::Continue(kind.into())
- }
-}
-
-impl Foldable for Const {
- fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- folder.fold_const(self)
- }
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut this = self.clone();
- match &mut this.literal {
- super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?,
- super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?,
- super::ty::ConstantKind::Param(_) => {}
- }
- this.ty = this.ty.fold(folder)?;
- ControlFlow::Continue(this)
- }
-}
-
-impl Foldable for Opaque {
- fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(self.clone())
- }
-}
-
-impl Foldable for Allocation {
- fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(self.clone())
- }
-}
-
-impl Foldable for UnevaluatedConst {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let UnevaluatedConst { def, args, promoted } = self;
- ControlFlow::Continue(UnevaluatedConst {
- def: def.fold(folder)?,
- args: args.fold(folder)?,
- promoted: promoted.fold(folder)?,
- })
- }
-}
-
-impl Foldable for ConstDef {
- fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(*self)
- }
-}
-
-impl<T: Foldable> Foldable for Option<T> {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(match self {
- Some(val) => Some(val.fold(folder)?),
- None => None,
- })
- }
-}
-
-impl Foldable for Promoted {
- fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(*self)
- }
-}
-
-impl Foldable for GenericArgs {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(GenericArgs(self.0.fold(folder)?))
- }
-}
-
-impl Foldable for Region {
- fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- folder.fold_reg(self)
- }
- fn super_fold<V: Folder>(&self, _: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(self.clone())
- }
-}
-
-impl Foldable for GenericArgKind {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut this = self.clone();
- match &mut this {
- GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?,
- GenericArgKind::Type(t) => *t = t.fold(folder)?,
- GenericArgKind::Const(c) => *c = c.fold(folder)?,
- }
- ControlFlow::Continue(this)
- }
-}
-
-impl Foldable for RigidTy {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut this = self.clone();
- match &mut this {
- RigidTy::Bool
- | RigidTy::Char
- | RigidTy::Int(_)
- | RigidTy::Uint(_)
- | RigidTy::Float(_)
- | RigidTy::Never
- | RigidTy::Foreign(_)
- | RigidTy::Str => {}
- RigidTy::Array(t, c) => {
- *t = t.fold(folder)?;
- *c = c.fold(folder)?;
- }
- RigidTy::Slice(inner) => *inner = inner.fold(folder)?,
- RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?,
- RigidTy::Ref(reg, ty, _) => {
- *reg = reg.fold(folder)?;
- *ty = ty.fold(folder)?
- }
- RigidTy::FnDef(_, args) => *args = args.fold(folder)?,
- RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?,
- RigidTy::Closure(_, args) => *args = args.fold(folder)?,
- RigidTy::Generator(_, args, _) => *args = args.fold(folder)?,
- RigidTy::Dynamic(pred, r, _) => {
- *pred = pred.fold(folder)?;
- *r = r.fold(folder)?;
- }
- RigidTy::Tuple(fields) => *fields = fields.fold(folder)?,
- RigidTy::Adt(_, args) => *args = args.fold(folder)?,
- }
- ControlFlow::Continue(this)
- }
-}
-
-impl<T: Foldable> Foldable for Vec<T> {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut this = self.clone();
- for arg in &mut this {
- *arg = arg.fold(folder)?;
- }
- ControlFlow::Continue(this)
- }
-}
-
-impl<T: Foldable> Foldable for Binder<T> {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(Self {
- value: self.value.fold(folder)?,
- bound_vars: self.bound_vars.clone(),
- })
- }
-}
-
-impl Foldable for ExistentialPredicate {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- let mut this = self.clone();
- match &mut this {
- ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?,
- ExistentialPredicate::Projection(p) => {
- p.term = p.term.fold(folder)?;
- p.generic_args = p.generic_args.fold(folder)?;
- }
- ExistentialPredicate::AutoTrait(_) => {}
- }
- ControlFlow::Continue(this)
- }
-}
-
-impl Foldable for TermKind {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(match self {
- TermKind::Type(t) => TermKind::Type(t.fold(folder)?),
- TermKind::Const(c) => TermKind::Const(c.fold(folder)?),
- })
- }
-}
-
-impl Foldable for FnSig {
- fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
- ControlFlow::Continue(Self {
- inputs_and_output: self.inputs_and_output.fold(folder)?,
- c_variadic: self.c_variadic,
- unsafety: self.unsafety,
- abi: self.abi.clone(),
- })
- }
-}
-
-pub enum Never {}
-
-/// In order to instantiate a `Foldable`'s generic parameters with specific arguments,
-/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params
-/// with the entries in its list.
-impl Folder for GenericArgs {
- type Break = Never;
-
- fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
- ControlFlow::Continue(match ty.kind() {
- TyKind::Param(p) => self[p],
- _ => *ty,
- })
- }
-
- fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
- ControlFlow::Continue(match &c.literal {
- ConstantKind::Param(p) => self[p.clone()].clone(),
- _ => c.clone(),
- })
- }
-}
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 104985493..f316671b2 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -17,22 +17,29 @@
//! The goal is to eventually be published on
//! [crates.io](https://crates.io).
+use crate::mir::mono::InstanceDef;
+use crate::mir::Body;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use self::ty::{
- GenericPredicates, Generics, ImplDef, ImplTrait, Span, TraitDecl, TraitDef, Ty, TyKind,
+ GenericPredicates, Generics, ImplDef, ImplTrait, IndexedVal, LineInfo, Span, TraitDecl,
+ TraitDef, Ty, TyKind,
};
#[macro_use]
extern crate scoped_tls;
-pub mod fold;
+pub mod error;
pub mod mir;
pub mod ty;
pub mod visitor;
+pub use error::*;
+use mir::mono::Instance;
+use ty::{FnDef, GenericArgs};
+
/// Use String for now but we should replace it.
pub type Symbol = String;
@@ -41,7 +48,7 @@ pub type CrateNum = usize;
/// A unique identification number for each item accessible for the current compilation unit.
#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct DefId(pub usize);
+pub struct DefId(usize);
impl Debug for DefId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -52,9 +59,28 @@ impl Debug for DefId {
}
}
+impl IndexedVal for DefId {
+ fn to_val(index: usize) -> Self {
+ DefId(index)
+ }
+
+ fn to_index(&self) -> usize {
+ self.0
+ }
+}
+
/// A unique identification number for each provenance
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct AllocId(pub usize);
+pub struct AllocId(usize);
+
+impl IndexedVal for AllocId {
+ fn to_val(index: usize) -> Self {
+ AllocId(index)
+ }
+ fn to_index(&self) -> usize {
+ self.0
+ }
+}
/// A list of crate items.
pub type CrateItems = Vec<CrateItem>;
@@ -65,20 +91,6 @@ pub type TraitDecls = Vec<TraitDef>;
/// A list of impl trait decls.
pub type ImplTraitDecls = Vec<ImplDef>;
-/// An error type used to represent an error that has already been reported by the compiler.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum CompilerError<T> {
- /// Internal compiler error (I.e.: Compiler crashed).
- ICE,
- /// Compilation failed.
- CompilationFailed,
- /// Compilation was interrupted.
- Interrupted(T),
- /// Compilation skipped. This happens when users invoke rustc to retrieve information such as
- /// --version.
- Skipped,
-}
-
/// Holds information about a crate.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Crate {
@@ -88,11 +100,10 @@ pub struct Crate {
}
pub type DefKind = Opaque;
+pub type Filename = Opaque;
/// Holds information about an item in the crate.
-/// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to
-/// use this item.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CrateItem(pub DefId);
impl CrateItem {
@@ -111,6 +122,10 @@ impl CrateItem {
pub fn kind(&self) -> DefKind {
with(|cx| cx.def_kind(self.0))
}
+
+ pub fn requires_monomorphization(&self) -> bool {
+ with(|cx| cx.requires_monomorphization(self.0))
+ }
}
/// Return the function where execution starts if the current
@@ -125,9 +140,9 @@ pub fn local_crate() -> Crate {
with(|cx| cx.local_crate())
}
-/// Try to find a crate with the given name.
-pub fn find_crate(name: &str) -> Option<Crate> {
- with(|cx| cx.find_crate(name))
+/// Try to find a crate or crates if multiple crates exist from given name.
+pub fn find_crates(name: &str) -> Vec<Crate> {
+ with(|cx| cx.find_crates(name))
}
/// Try to find a crate with the given name.
@@ -157,72 +172,95 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
}
pub trait Context {
- fn entry_fn(&mut self) -> Option<CrateItem>;
+ fn entry_fn(&self) -> Option<CrateItem>;
/// Retrieve all items of the local crate that have a MIR associated with them.
- fn all_local_items(&mut self) -> CrateItems;
- fn mir_body(&mut self, item: DefId) -> mir::Body;
- fn all_trait_decls(&mut self) -> TraitDecls;
- fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
- fn all_trait_impls(&mut self) -> ImplTraitDecls;
- fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait;
- fn generics_of(&mut self, def_id: DefId) -> Generics;
- fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
- fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
+ fn all_local_items(&self) -> CrateItems;
+ fn mir_body(&self, item: DefId) -> mir::Body;
+ fn all_trait_decls(&self) -> TraitDecls;
+ fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
+ fn all_trait_impls(&self) -> ImplTraitDecls;
+ fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
+ fn generics_of(&self, def_id: DefId) -> Generics;
+ fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
+ fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
/// Get information about the local crate.
fn local_crate(&self) -> Crate;
/// Retrieve a list of all external crates.
fn external_crates(&self) -> Vec<Crate>;
/// Find a crate with the given name.
- fn find_crate(&self, name: &str) -> Option<Crate>;
+ fn find_crates(&self, name: &str) -> Vec<Crate>;
- /// Prints the name of given `DefId`
+ /// Returns the name of given `DefId`
fn name_of_def_id(&self, def_id: DefId) -> String;
- /// Prints a human readable form of `Span`
- fn print_span(&self, span: Span) -> String;
+ /// Returns printable, human readable form of `Span`
+ fn span_to_string(&self, span: Span) -> String;
- /// Prints the kind of given `DefId`
- fn def_kind(&mut self, def_id: DefId) -> DefKind;
+ /// Return filename from given `Span`, for diagnostic purposes
+ fn get_filename(&self, span: &Span) -> Filename;
+
+ /// Return lines corresponding to this `Span`
+ fn get_lines(&self, span: &Span) -> LineInfo;
+
+ /// Returns the `kind` of given `DefId`
+ fn def_kind(&self, def_id: DefId) -> DefKind;
/// `Span` of an item
- fn span_of_an_item(&mut self, def_id: DefId) -> Span;
+ fn span_of_an_item(&self, def_id: DefId) -> Span;
/// Obtain the representation of a type.
- fn ty_kind(&mut self, ty: Ty) -> TyKind;
+ fn ty_kind(&self, ty: Ty) -> TyKind;
+
+ /// Get the body of an Instance.
+ /// FIXME: Monomorphize the body.
+ fn instance_body(&self, instance: InstanceDef) -> Body;
- /// Create a new `Ty` from scratch without information from rustc.
- fn mk_ty(&mut self, kind: TyKind) -> Ty;
+ /// Get the instance type with generic substitutions applied and lifetimes erased.
+ fn instance_ty(&self, instance: InstanceDef) -> Ty;
+
+ /// Get the instance.
+ fn instance_def_id(&self, instance: InstanceDef) -> DefId;
+
+ /// Get the instance mangled name.
+ fn instance_mangled_name(&self, instance: InstanceDef) -> String;
+
+ /// Convert a non-generic crate item into an instance.
+ /// This function will panic if the item is generic.
+ fn mono_instance(&self, item: CrateItem) -> Instance;
+
+ /// Item requires monomorphization.
+ fn requires_monomorphization(&self, def_id: DefId) -> bool;
+
+ /// Resolve an instance from the given function definition and generic arguments.
+ fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
}
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
// datastructures and stable MIR datastructures
-scoped_thread_local! (static TLV: Cell<*mut ()>);
+scoped_thread_local! (static TLV: Cell<*const ()>);
-pub fn run(mut context: impl Context, f: impl FnOnce()) {
+pub fn run(context: &dyn Context, f: impl FnOnce()) {
assert!(!TLV.is_set());
- fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
- let ptr: *mut () = &mut context as *mut &mut _ as _;
- TLV.set(&Cell::new(ptr), || {
- f();
- });
- }
- g(&mut context, f);
+ let ptr: *const () = &context as *const &_ as _;
+ TLV.set(&Cell::new(ptr), || {
+ f();
+ });
}
/// Loads the current context and calls a function with it.
/// Do not nest these, as that will ICE.
-pub fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
+pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
assert!(TLV.is_set());
TLV.with(|tlv| {
let ptr = tlv.get();
assert!(!ptr.is_null());
- f(unsafe { *(ptr as *mut &mut dyn Context) })
+ f(unsafe { *(ptr as *const &dyn Context) })
})
}
/// A type that provides internal information but that can still be used for debug purpose.
-#[derive(Clone)]
+#[derive(Clone, Eq, PartialEq)]
pub struct Opaque(String);
impl std::fmt::Display for Opaque {
diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs
index a9dbc3463..2e1714b49 100644
--- a/compiler/stable_mir/src/mir.rs
+++ b/compiler/stable_mir/src/mir.rs
@@ -1,3 +1,6 @@
mod body;
+pub mod mono;
+pub mod visit;
pub use body::*;
+pub use visit::MirVisitor;
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index f93a1a3a9..069337836 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,11 +1,69 @@
-use crate::ty::{AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region};
+use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, Ty};
use crate::Opaque;
-use crate::{ty::Ty, Span};
+use crate::Span;
+/// The SMIR representation of a single function.
#[derive(Clone, Debug)]
pub struct Body {
pub blocks: Vec<BasicBlock>,
- pub locals: Vec<Ty>,
+
+ // Declarations of locals within the function.
+ //
+ // The first local is the return value pointer, followed by `arg_count`
+ // locals for the function arguments, followed by any user-declared
+ // variables and temporaries.
+ pub(super) locals: LocalDecls,
+
+ // The number of arguments this function takes.
+ pub(super) arg_count: usize,
+}
+
+impl Body {
+ /// Constructs a `Body`.
+ ///
+ /// A constructor is required to build a `Body` from outside the crate
+ /// because the `arg_count` and `locals` fields are private.
+ pub fn new(blocks: Vec<BasicBlock>, locals: LocalDecls, arg_count: usize) -> Self {
+ // If locals doesn't contain enough entries, it can lead to panics in
+ // `ret_local`, `arg_locals`, and `inner_locals`.
+ assert!(
+ locals.len() > arg_count,
+ "A Body must contain at least a local for the return value and each of the function's arguments"
+ );
+ Self { blocks, locals, arg_count }
+ }
+
+ /// Return local that holds this function's return value.
+ pub fn ret_local(&self) -> &LocalDecl {
+ &self.locals[RETURN_LOCAL]
+ }
+
+ /// Locals in `self` that correspond to this function's arguments.
+ pub fn arg_locals(&self) -> &[LocalDecl] {
+ &self.locals[1..][..self.arg_count]
+ }
+
+ /// Inner locals for this function. These are the locals that are
+ /// neither the return local nor the argument locals.
+ pub fn inner_locals(&self) -> &[LocalDecl] {
+ &self.locals[self.arg_count + 1..]
+ }
+
+ /// Convenience function to get all the locals in this function.
+ ///
+ /// Locals are typically accessed via the more specific methods `ret_local`,
+ /// `arg_locals`, and `inner_locals`.
+ pub fn locals(&self) -> &[LocalDecl] {
+ &self.locals
+ }
+}
+
+type LocalDecls = Vec<LocalDecl>;
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct LocalDecl {
+ pub ty: Ty,
+ pub span: Span,
}
#[derive(Clone, Debug)]
@@ -14,8 +72,14 @@ pub struct BasicBlock {
pub terminator: Terminator,
}
-#[derive(Clone, Debug)]
-pub enum Terminator {
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Terminator {
+ pub kind: TerminatorKind,
+ pub span: Span,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum TerminatorKind {
Goto {
target: usize,
},
@@ -47,7 +111,7 @@ pub enum Terminator {
target: usize,
unwind: UnwindAction,
},
- GeneratorDrop,
+ CoroutineDrop,
InlineAsm {
template: String,
operands: Vec<InlineAsmOperand>,
@@ -58,7 +122,7 @@ pub enum Terminator {
},
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InlineAsmOperand {
pub in_value: Option<Operand>,
pub out_place: Option<Place>,
@@ -67,7 +131,7 @@ pub struct InlineAsmOperand {
pub raw_rpr: String,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UnwindAction {
Continue,
Unreachable,
@@ -75,19 +139,19 @@ pub enum UnwindAction {
Cleanup(usize),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AssertMessage {
BoundsCheck { len: Operand, index: Operand },
Overflow(BinOp, Operand, Operand),
OverflowNeg(Operand),
DivisionByZero(Operand),
RemainderByZero(Operand),
- ResumedAfterReturn(GeneratorKind),
- ResumedAfterPanic(GeneratorKind),
+ ResumedAfterReturn(CoroutineKind),
+ ResumedAfterPanic(CoroutineKind),
MisalignedPointerDereference { required: Operand, found: Operand },
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BinOp {
Add,
AddUnchecked,
@@ -113,20 +177,21 @@ pub enum BinOp {
Offset,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UnOp {
Not,
Neg,
}
-#[derive(Clone, Debug)]
-pub enum GeneratorKind {
- Async(AsyncGeneratorKind),
- Gen,
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum CoroutineKind {
+ Async(CoroutineSource),
+ Coroutine,
+ Gen(CoroutineSource),
}
-#[derive(Clone, Debug)]
-pub enum AsyncGeneratorKind {
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum CoroutineSource {
Block,
Closure,
Fn,
@@ -139,7 +204,7 @@ pub(crate) type LocalDefId = Opaque;
pub(crate) type Coverage = Opaque;
/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FakeReadCause {
ForMatchGuard,
ForMatchedPlace(LocalDefId),
@@ -149,7 +214,7 @@ pub enum FakeReadCause {
}
/// Describes what kind of retag is to be performed
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum RetagKind {
FnEntry,
TwoPhase,
@@ -157,7 +222,7 @@ pub enum RetagKind {
Default,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Variance {
Covariant,
Invariant,
@@ -165,21 +230,27 @@ pub enum Variance {
Bivariant,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CopyNonOverlapping {
pub src: Operand,
pub dst: Operand,
pub count: Operand,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum NonDivergingIntrinsic {
Assume(Operand),
CopyNonOverlapping(CopyNonOverlapping),
}
-#[derive(Clone, Debug)]
-pub enum Statement {
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Statement {
+ pub kind: StatementKind,
+ pub span: Span,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum StatementKind {
Assign(Place, Rvalue),
FakeRead(FakeReadCause, Place),
SetDiscriminant { place: Place, variant_index: VariantIdx },
@@ -195,7 +266,7 @@ pub enum Statement {
Nop,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Rvalue {
/// Creates a pointer with the indicated mutability to the place.
///
@@ -209,8 +280,8 @@ pub enum Rvalue {
/// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
/// has a destructor.
///
- /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
- /// generator lowering, `Generator` aggregate kinds are disallowed too.
+ /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
+ /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
Aggregate(AggregateKind, Vec<Operand>),
/// * `Offset` has the same semantics as `<*const T>::offset`, except that the second
@@ -307,29 +378,30 @@ pub enum Rvalue {
Use(Operand),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AggregateKind {
Array(Ty),
Tuple,
Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
Closure(ClosureDef, GenericArgs),
- Generator(GeneratorDef, GenericArgs, Movability),
+ Coroutine(CoroutineDef, GenericArgs, Movability),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Operand {
Copy(Place),
Move(Place),
Constant(Constant),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Place {
pub local: Local,
+ /// projection out of a place (access a field, deref a pointer, etc)
pub projection: String,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UserTypeProjection {
pub base: UserTypeAnnotationIndex,
pub projection: String,
@@ -337,6 +409,8 @@ pub struct UserTypeProjection {
pub type Local = usize;
+pub const RETURN_LOCAL: Local = 0;
+
type FieldIdx = usize;
/// The source-order index of a variant in a type.
@@ -344,20 +418,20 @@ pub type VariantIdx = usize;
type UserTypeAnnotationIndex = usize;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Constant {
pub span: Span,
pub user_ty: Option<UserTypeAnnotationIndex>,
pub literal: Const,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SwitchTarget {
pub value: u128,
pub target: usize,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
Shared,
@@ -375,26 +449,26 @@ pub enum BorrowKind {
},
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum MutBorrowKind {
Default,
TwoPhaseBorrow,
ClosureCapture,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Mutability {
Not,
Mut,
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Safety {
Unsafe,
Normal,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PointerCoercion {
/// Go from a fn-item type to a fn-pointer type.
ReifyFnPointer,
@@ -421,7 +495,7 @@ pub enum PointerCoercion {
Unsize,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CastKind {
PointerExposeAddress,
PointerFromExposedAddress,
@@ -436,12 +510,34 @@ pub enum CastKind {
Transmute,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum NullOp {
/// Returns the size of a value of that type.
SizeOf,
/// Returns the minimum alignment of a type.
AlignOf,
/// Returns the offset of a field.
- OffsetOf(Vec<FieldIdx>),
+ OffsetOf(Vec<(VariantIdx, FieldIdx)>),
+}
+
+impl Operand {
+ pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
+ match self {
+ Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
+ Operand::Constant(c) => c.ty(),
+ }
+ }
+}
+
+impl Constant {
+ pub fn ty(&self) -> Ty {
+ self.literal.ty()
+ }
+}
+
+impl Place {
+ pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
+ let _start_ty = locals[self.local].ty;
+ todo!("Implement projection")
+ }
}
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
new file mode 100644
index 000000000..8f5333498
--- /dev/null
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -0,0 +1,102 @@
+use crate::mir::Body;
+use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
+use crate::{with, CrateItem, DefId, Error, Opaque};
+use std::fmt::Debug;
+
+#[derive(Clone, Debug)]
+pub enum MonoItem {
+ Fn(Instance),
+ Static(StaticDef),
+ GlobalAsm(Opaque),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct Instance {
+ /// The type of instance.
+ pub kind: InstanceKind,
+ /// An ID used to get the instance definition from the compiler.
+ /// Do not use this field directly.
+ pub def: InstanceDef,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum InstanceKind {
+ /// A user defined item.
+ Item,
+ /// A compiler intrinsic function.
+ Intrinsic,
+ /// A virtual function definition stored in a VTable.
+ Virtual,
+ /// A compiler generated shim.
+ Shim,
+}
+
+impl Instance {
+ /// Get the body of an Instance. The body will be eagerly monomorphized.
+ pub fn body(&self) -> Body {
+ with(|context| context.instance_body(self.def))
+ }
+
+ /// Get the instance type with generic substitutions applied and lifetimes erased.
+ pub fn ty(&self) -> Ty {
+ with(|context| context.instance_ty(self.def))
+ }
+
+ pub fn mangled_name(&self) -> String {
+ with(|context| context.instance_mangled_name(self.def))
+ }
+
+ /// Resolve an instance starting from a function definition and generic arguments.
+ pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
+ with(|context| {
+ context.resolve_instance(def, args).ok_or_else(|| {
+ crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+ })
+ })
+ }
+}
+
+/// Try to convert a crate item into an instance.
+/// The item cannot be generic in order to be converted into an instance.
+impl TryFrom<CrateItem> for Instance {
+ type Error = crate::Error;
+
+ fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
+ with(|context| {
+ if !context.requires_monomorphization(item.0) {
+ Ok(context.mono_instance(item))
+ } else {
+ Err(Error::new("Item requires monomorphization".to_string()))
+ }
+ })
+ }
+}
+
+/// Try to convert an instance into a crate item.
+/// Only user defined instances can be converted.
+impl TryFrom<Instance> for CrateItem {
+ type Error = crate::Error;
+
+ fn try_from(value: Instance) -> Result<Self, Self::Error> {
+ if value.kind == InstanceKind::Item {
+ Ok(CrateItem(with(|context| context.instance_def_id(value.def))))
+ } else {
+ Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct InstanceDef(usize);
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct StaticDef(pub DefId);
+
+impl IndexedVal for InstanceDef {
+ fn to_val(index: usize) -> Self {
+ InstanceDef(index)
+ }
+ fn to_index(&self) -> usize {
+ self.0
+ }
+}
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
new file mode 100644
index 000000000..806dced71
--- /dev/null
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -0,0 +1,414 @@
+//! # The Stable MIR Visitor
+//!
+//! ## Overview
+//!
+//! We currently only support an immutable visitor.
+//! The structure of this visitor is similar to the ones internal to `rustc`,
+//! and it follows the following conventions:
+//!
+//! For every mir item, the trait has a `visit_<item>` and a `super_<item>` method.
+//! - `visit_<item>`, by default, calls `super_<item>`
+//! - `super_<item>`, by default, destructures the `<item>` and calls `visit_<sub_item>` for
+//! all sub-items that compose the original item.
+//!
+//! In order to implement a visitor, override the `visit_*` methods for the types you are
+//! interested in analyzing, and invoke (within that method call)
+//! `self.super_*` to continue to the traverse.
+//! Avoid calling `super` methods in other circumstances.
+//!
+//! For the most part, we do not destructure things external to the
+//! MIR, e.g., types, spans, etc, but simply visit them and stop.
+//! This avoids duplication with other visitors like `TypeFoldable`.
+//!
+//! ## Updating
+//!
+//! The code is written in a very deliberate style intended to minimize
+//! the chance of things being overlooked.
+//!
+//! Use pattern matching to reference fields and ensure that all
+//! matches are exhaustive.
+//!
+//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
+//! That means you never write `..` to skip over fields, nor do you write `_`
+//! to skip over variants in a `match`.
+//!
+//! The only place that `_` is acceptable is to match a field (or
+//! variant argument) that does not require visiting.
+
+use crate::mir::*;
+use crate::ty::{Const, GenericArgs, Region, Ty};
+use crate::{Opaque, Span};
+
+pub trait MirVisitor {
+ fn visit_body(&mut self, body: &Body) {
+ self.super_body(body)
+ }
+
+ fn visit_basic_block(&mut self, bb: &BasicBlock) {
+ self.super_basic_block(bb)
+ }
+
+ fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
+ self.super_ret_decl(local, decl)
+ }
+
+ fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
+ self.super_arg_decl(local, decl)
+ }
+
+ fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) {
+ self.super_local_decl(local, decl)
+ }
+
+ fn visit_statement(&mut self, stmt: &Statement, location: Location) {
+ self.super_statement(stmt, location)
+ }
+
+ fn visit_terminator(&mut self, term: &Terminator, location: Location) {
+ self.super_terminator(term, location)
+ }
+
+ fn visit_span(&mut self, span: &Span) {
+ self.super_span(span)
+ }
+
+ fn visit_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
+ self.super_place(place, ptx, location)
+ }
+
+ fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) {
+ let _ = (local, ptx, location);
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
+ self.super_rvalue(rvalue, location)
+ }
+
+ fn visit_operand(&mut self, operand: &Operand, location: Location) {
+ self.super_operand(operand, location)
+ }
+
+ fn visit_user_type_projection(&mut self, projection: &UserTypeProjection) {
+ self.super_user_type_projection(projection)
+ }
+
+ fn visit_ty(&mut self, ty: &Ty, location: Location) {
+ let _ = location;
+ self.super_ty(ty)
+ }
+
+ fn visit_constant(&mut self, constant: &Constant, location: Location) {
+ self.super_constant(constant, location)
+ }
+
+ fn visit_const(&mut self, constant: &Const, location: Location) {
+ self.super_const(constant, location)
+ }
+
+ fn visit_region(&mut self, region: &Region, location: Location) {
+ let _ = location;
+ self.super_region(region)
+ }
+
+ fn visit_args(&mut self, args: &GenericArgs, location: Location) {
+ let _ = location;
+ self.super_args(args)
+ }
+
+ fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
+ self.super_assert_msg(msg, location)
+ }
+
+ fn super_body(&mut self, body: &Body) {
+ let Body { blocks, locals: _, arg_count } = body;
+
+ for bb in blocks {
+ self.visit_basic_block(bb);
+ }
+
+ self.visit_ret_decl(RETURN_LOCAL, body.ret_local());
+
+ for (idx, arg) in body.arg_locals().iter().enumerate() {
+ self.visit_arg_decl(idx + 1, arg)
+ }
+
+ let local_start = arg_count + 1;
+ for (idx, arg) in body.arg_locals().iter().enumerate() {
+ self.visit_local_decl(idx + local_start, arg)
+ }
+ }
+
+ fn super_basic_block(&mut self, bb: &BasicBlock) {
+ let BasicBlock { statements, terminator } = bb;
+ for stmt in statements {
+ self.visit_statement(stmt, Location(stmt.span));
+ }
+ self.visit_terminator(terminator, Location(terminator.span));
+ }
+
+ fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) {
+ let _ = local;
+ let LocalDecl { ty, span } = decl;
+ self.visit_ty(ty, Location(*span));
+ }
+
+ fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
+ self.super_local_decl(local, decl)
+ }
+
+ fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
+ self.super_local_decl(local, decl)
+ }
+
+ fn super_statement(&mut self, stmt: &Statement, location: Location) {
+ let Statement { kind, span } = stmt;
+ self.visit_span(span);
+ match kind {
+ StatementKind::Assign(place, rvalue) => {
+ self.visit_place(place, PlaceContext::MUTATING, location);
+ self.visit_rvalue(rvalue, location);
+ }
+ StatementKind::FakeRead(_, place) => {
+ self.visit_place(place, PlaceContext::NON_MUTATING, location);
+ }
+ StatementKind::SetDiscriminant { place, .. } => {
+ self.visit_place(place, PlaceContext::MUTATING, location);
+ }
+ StatementKind::Deinit(place) => {
+ self.visit_place(place, PlaceContext::MUTATING, location);
+ }
+ StatementKind::StorageLive(local) => {
+ self.visit_local(local, PlaceContext::NON_USE, location);
+ }
+ StatementKind::StorageDead(local) => {
+ self.visit_local(local, PlaceContext::NON_USE, location);
+ }
+ StatementKind::Retag(_, place) => {
+ self.visit_place(place, PlaceContext::MUTATING, location);
+ }
+ StatementKind::PlaceMention(place) => {
+ self.visit_place(place, PlaceContext::NON_MUTATING, location);
+ }
+ StatementKind::AscribeUserType { place, projections, variance: _ } => {
+ self.visit_place(place, PlaceContext::NON_USE, location);
+ self.visit_user_type_projection(projections);
+ }
+ StatementKind::Coverage(coverage) => visit_opaque(coverage),
+ StatementKind::Intrinsic(intrisic) => match intrisic {
+ NonDivergingIntrinsic::Assume(operand) => {
+ self.visit_operand(operand, location);
+ }
+ NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+ src,
+ dst,
+ count,
+ }) => {
+ self.visit_operand(src, location);
+ self.visit_operand(dst, location);
+ self.visit_operand(count, location);
+ }
+ },
+ StatementKind::ConstEvalCounter => {}
+ StatementKind::Nop => {}
+ }
+ }
+
+ fn super_terminator(&mut self, term: &Terminator, location: Location) {
+ let Terminator { kind, span } = term;
+ self.visit_span(&span);
+ match kind {
+ TerminatorKind::Goto { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Unreachable
+ | TerminatorKind::CoroutineDrop => {}
+ TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
+ self.visit_operand(cond, location);
+ self.visit_assert_msg(msg, location);
+ }
+ TerminatorKind::Drop { place, target: _, unwind: _ } => {
+ self.visit_place(place, PlaceContext::MUTATING, location);
+ }
+ TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
+ self.visit_operand(func, location);
+ for arg in args {
+ self.visit_operand(arg, location);
+ }
+ self.visit_place(destination, PlaceContext::MUTATING, location);
+ }
+ TerminatorKind::InlineAsm { operands, .. } => {
+ for op in operands {
+ let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
+ if let Some(input) = in_value {
+ self.visit_operand(input, location);
+ }
+ if let Some(output) = out_place {
+ self.visit_place(output, PlaceContext::MUTATING, location);
+ }
+ }
+ }
+ TerminatorKind::Return => {
+ let local = RETURN_LOCAL;
+ self.visit_local(&local, PlaceContext::NON_MUTATING, location);
+ }
+ TerminatorKind::SwitchInt { discr, targets: _, otherwise: _ } => {
+ self.visit_operand(discr, location);
+ }
+ }
+ }
+
+ fn super_span(&mut self, span: &Span) {
+ let _ = span;
+ }
+
+ fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
+ let _ = location;
+ let _ = ptx;
+ visit_opaque(&Opaque(place.projection.clone()));
+ }
+
+ fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
+ match rvalue {
+ Rvalue::AddressOf(mutability, place) => {
+ let pcx = PlaceContext { is_mut: *mutability == Mutability::Mut };
+ self.visit_place(place, pcx, location);
+ }
+ Rvalue::Aggregate(_, operands) => {
+ for op in operands {
+ self.visit_operand(op, location);
+ }
+ }
+ Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
+ self.visit_operand(lhs, location);
+ self.visit_operand(rhs, location);
+ }
+ Rvalue::Cast(_, op, ty) => {
+ self.visit_operand(op, location);
+ self.visit_ty(ty, location);
+ }
+ Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+ self.visit_place(place, PlaceContext::NON_MUTATING, location);
+ }
+ Rvalue::Ref(region, kind, place) => {
+ self.visit_region(region, location);
+ let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
+ self.visit_place(place, pcx, location);
+ }
+ Rvalue::Repeat(op, constant) => {
+ self.visit_operand(op, location);
+ self.visit_const(constant, location);
+ }
+ Rvalue::ShallowInitBox(op, ty) => {
+ self.visit_ty(ty, location);
+ self.visit_operand(op, location)
+ }
+ Rvalue::ThreadLocalRef(_) => {}
+ Rvalue::NullaryOp(_, ty) => {
+ self.visit_ty(ty, location);
+ }
+ Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
+ self.visit_operand(op, location);
+ }
+ }
+ }
+
+ fn super_operand(&mut self, operand: &Operand, location: Location) {
+ match operand {
+ Operand::Copy(place) | Operand::Move(place) => {
+ self.visit_place(place, PlaceContext::NON_MUTATING, location)
+ }
+ Operand::Constant(constant) => {
+ self.visit_constant(constant, location);
+ }
+ }
+ }
+
+ fn super_user_type_projection(&mut self, projection: &UserTypeProjection) {
+ // This is a no-op on mir::Visitor.
+ let _ = projection;
+ }
+
+ fn super_ty(&mut self, ty: &Ty) {
+ let _ = ty;
+ }
+
+ fn super_constant(&mut self, constant: &Constant, location: Location) {
+ let Constant { span, user_ty: _, literal } = constant;
+ self.visit_span(span);
+ self.visit_const(literal, location);
+ }
+
+ fn super_const(&mut self, constant: &Const, location: Location) {
+ let Const { kind: _, ty, id: _ } = constant;
+ self.visit_ty(ty, location);
+ }
+
+ fn super_region(&mut self, region: &Region) {
+ let _ = region;
+ }
+
+ fn super_args(&mut self, args: &GenericArgs) {
+ let _ = args;
+ }
+
+ fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
+ match msg {
+ AssertMessage::BoundsCheck { len, index } => {
+ self.visit_operand(len, location);
+ self.visit_operand(index, location);
+ }
+ AssertMessage::Overflow(_, left, right) => {
+ self.visit_operand(left, location);
+ self.visit_operand(right, location);
+ }
+ AssertMessage::OverflowNeg(op)
+ | AssertMessage::DivisionByZero(op)
+ | AssertMessage::RemainderByZero(op) => {
+ self.visit_operand(op, location);
+ }
+ AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { //nothing to visit
+ }
+ AssertMessage::MisalignedPointerDereference { required, found } => {
+ self.visit_operand(required, location);
+ self.visit_operand(found, location);
+ }
+ }
+ }
+}
+
+/// This function is a no-op that gets used to ensure this visitor is kept up-to-date.
+///
+/// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail
+/// when trying to invoke `visit_opaque`.
+///
+/// If you are here because your compilation is broken, replace the failing call to `visit_opaque()`
+/// by a `visit_<CONSTRUCT>` for your construct.
+fn visit_opaque(_: &Opaque) {}
+
+/// The location of a statement / terminator in the code and the CFG.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Location(Span);
+
+impl Location {
+ pub fn span(&self) -> Span {
+ self.0
+ }
+}
+
+/// Information about a place's usage.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct PlaceContext {
+ /// Whether the access is mutable or not. Keep this private so we can increment the type in a
+ /// backward compatible manner.
+ is_mut: bool,
+}
+
+impl PlaceContext {
+ const MUTATING: Self = PlaceContext { is_mut: true };
+ const NON_MUTATING: Self = PlaceContext { is_mut: false };
+ const NON_USE: Self = PlaceContext { is_mut: false };
+
+ pub fn is_mutating(&self) -> bool {
+ self.is_mut
+ }
+}
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 6029e3c11..5dfaa0fd8 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -3,10 +3,10 @@ use super::{
mir::{Body, Mutability},
with, AllocId, DefId, Symbol,
};
-use crate::Opaque;
+use crate::{Filename, Opaque};
use std::fmt::{self, Debug, Formatter};
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Ty(pub usize);
impl Debug for Ty {
@@ -21,26 +21,45 @@ impl Ty {
}
}
-impl From<TyKind> for Ty {
- fn from(value: TyKind) -> Self {
- with(|context| context.mk_ty(value))
+/// Represents a constant in MIR or from the Type system.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Const {
+ /// The constant kind.
+ pub(crate) kind: ConstantKind,
+ /// The constant type.
+ pub(crate) ty: Ty,
+ /// Used for internal tracking of the internal constant.
+ pub id: ConstId,
+}
+
+impl Const {
+ /// Build a constant. Note that this should only be used by the compiler.
+ pub fn new(kind: ConstantKind, ty: Ty, id: ConstId) -> Const {
+ Const { kind, ty, id }
}
-}
-#[derive(Debug, Clone)]
-pub struct Const {
- pub literal: ConstantKind,
- pub ty: Ty,
+ /// Retrieve the constant kind.
+ pub fn kind(&self) -> &ConstantKind {
+ &self.kind
+ }
+
+ /// Get the constant type.
+ pub fn ty(&self) -> Ty {
+ self.ty
+ }
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct ConstId(pub usize);
+
type Ident = Opaque;
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Region {
pub kind: RegionKind,
}
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RegionKind {
ReEarlyBound(EarlyBoundRegion),
ReLateBound(DebruijnIndex, BoundRegion),
@@ -51,7 +70,7 @@ pub enum RegionKind {
pub(crate) type DebruijnIndex = u32;
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EarlyBoundRegion {
pub def_id: RegionDef,
pub index: u32,
@@ -60,7 +79,7 @@ pub struct EarlyBoundRegion {
pub(crate) type BoundVar = u32;
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BoundRegion {
pub var: BoundVar,
pub kind: BoundRegionKind,
@@ -68,25 +87,47 @@ pub struct BoundRegion {
pub(crate) type UniverseIndex = u32;
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct Span(pub usize);
+pub struct Span(usize);
impl Debug for Span {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Span")
.field("id", &self.0)
- .field("repr", &with(|cx| cx.print_span(*self)))
+ .field("repr", &with(|cx| cx.span_to_string(*self)))
.finish()
}
}
-#[derive(Clone, Debug)]
+impl Span {
+ /// Return filename for diagnostic purposes
+ pub fn get_filename(&self) -> Filename {
+ with(|c| c.get_filename(self))
+ }
+
+ /// Return lines that corespond to this `Span`
+ pub fn get_lines(&self) -> LineInfo {
+ with(|c| c.get_lines(&self))
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+/// Information you get from `Span` in a struct form.
+/// Line and col start from 1.
+pub struct LineInfo {
+ pub start_line: usize,
+ pub start_col: usize,
+ pub end_line: usize,
+ pub end_col: usize,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TyKind {
RigidTy(RigidTy),
Alias(AliasKind, AliasTy),
@@ -94,7 +135,7 @@ pub enum TyKind {
Bound(usize, BoundTy),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RigidTy {
Bool,
Char,
@@ -111,7 +152,7 @@ pub enum RigidTy {
FnDef(FnDef, GenericArgs),
FnPtr(PolyFnSig),
Closure(ClosureDef, GenericArgs),
- Generator(GeneratorDef, GenericArgs, Movability),
+ Coroutine(CoroutineDef, GenericArgs, Movability),
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
Never,
Tuple(Vec<Ty>),
@@ -165,7 +206,7 @@ impl FnDef {
pub struct ClosureDef(pub DefId);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct GeneratorDef(pub DefId);
+pub struct CoroutineDef(pub DefId);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ParamDef(pub DefId);
@@ -194,7 +235,8 @@ pub struct ImplDef(pub DefId);
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RegionDef(pub DefId);
-#[derive(Clone, Debug)]
+/// A list of generic arguments.
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GenericArgs(pub Vec<GenericArgKind>);
impl std::ops::Index<ParamTy> for GenericArgs {
@@ -213,7 +255,7 @@ impl std::ops::Index<ParamConst> for GenericArgs {
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum GenericArgKind {
Lifetime(Region),
Type(Ty),
@@ -242,13 +284,13 @@ impl GenericArgKind {
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TermKind {
Type(Ty),
Const(Const),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AliasKind {
Projection,
Inherent,
@@ -256,7 +298,7 @@ pub enum AliasKind {
Weak,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AliasTy {
pub def_id: AliasDef,
pub args: GenericArgs,
@@ -264,7 +306,7 @@ pub struct AliasTy {
pub type PolyFnSig = Binder<FnSig>;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FnSig {
pub inputs_and_output: Vec<Ty>,
pub c_variadic: bool,
@@ -303,18 +345,18 @@ pub enum Abi {
RiscvInterruptS,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Binder<T> {
pub value: T,
pub bound_vars: Vec<BoundVariableKind>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EarlyBinder<T> {
pub value: T,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BoundVariableKind {
Ty(BoundTyKind),
Region(BoundRegionKind),
@@ -327,46 +369,46 @@ pub enum BoundTyKind {
Param(ParamDef, String),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BoundRegionKind {
BrAnon,
BrNamed(BrNamedDef, String),
BrEnv,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DynKind {
Dyn,
DynStar,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ExistentialPredicate {
Trait(ExistentialTraitRef),
Projection(ExistentialProjection),
AutoTrait(TraitDef),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialTraitRef {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialProjection {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
pub term: TermKind,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParamTy {
pub index: u32,
pub name: String,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BoundTy {
pub var: usize,
pub kind: BoundTyKind,
@@ -382,14 +424,14 @@ pub type Promoted = u32;
pub type InitMaskMaterialized = Vec<u64>;
/// Stores the provenance information of pointers stored in memory.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ProvenanceMap {
/// Provenance in this map applies from the given offset for an entire pointer-size worth of
/// bytes. Two entries in this map are always at least a pointer size apart.
pub ptrs: Vec<(Size, Prov)>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Allocation {
pub bytes: Bytes,
pub provenance: ProvenanceMap,
@@ -397,20 +439,23 @@ pub struct Allocation {
pub mutability: Mutability,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConstantKind {
Allocated(Allocation),
Unevaluated(UnevaluatedConst),
Param(ParamConst),
+ /// Store ZST constants.
+ /// We have to special handle these constants since its type might be generic.
+ ZeroSized,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParamConst {
pub index: u32,
pub name: String,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UnevaluatedConst {
pub def: ConstDef,
pub args: GenericArgs,
@@ -424,7 +469,7 @@ pub enum TraitSpecializationKind {
AlwaysApplicable,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraitDecl {
pub def_id: TraitDef,
pub unsafety: Safety,
@@ -455,13 +500,13 @@ impl TraitDecl {
pub type ImplTrait = EarlyBinder<TraitRef>;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraitRef {
pub def_id: TraitDef,
pub args: GenericArgs,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Generics {
pub parent: Option<GenericDef>,
pub parent_count: usize,
@@ -472,14 +517,14 @@ pub struct Generics {
pub host_effect_index: Option<usize>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum GenericParamDefKind {
Lifetime,
Type { has_default: bool, synthetic: bool },
Const { has_default: bool },
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GenericParamDef {
pub name: super::Symbol,
pub def_id: GenericDef,
@@ -493,7 +538,7 @@ pub struct GenericPredicates {
pub predicates: Vec<(PredicateKind, Span)>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PredicateKind {
Clause(ClauseKind),
ObjectSafe(TraitDef),
@@ -505,7 +550,7 @@ pub enum PredicateKind {
AliasRelate(TermKind, TermKind, AliasRelationDirection),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ClauseKind {
Trait(TraitPredicate),
RegionOutlives(RegionOutlivesPredicate),
@@ -516,52 +561,75 @@ pub enum ClauseKind {
ConstEvaluatable(Const),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ClosureKind {
Fn,
FnMut,
FnOnce,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SubtypePredicate {
pub a: Ty,
pub b: Ty,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CoercePredicate {
pub a: Ty,
pub b: Ty,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AliasRelationDirection {
Equate,
Subtype,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraitPredicate {
pub trait_ref: TraitRef,
pub polarity: ImplPolarity,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OutlivesPredicate<A, B>(pub A, pub B);
pub type RegionOutlivesPredicate = OutlivesPredicate<Region, Region>;
pub type TypeOutlivesPredicate = OutlivesPredicate<Ty, Region>;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ProjectionPredicate {
pub projection_ty: AliasTy,
pub term: TermKind,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ImplPolarity {
Positive,
Negative,
Reservation,
}
+
+pub trait IndexedVal {
+ fn to_val(index: usize) -> Self;
+
+ fn to_index(&self) -> usize;
+}
+
+macro_rules! index_impl {
+ ($name:ident) => {
+ impl IndexedVal for $name {
+ fn to_val(index: usize) -> Self {
+ $name(index)
+ }
+ fn to_index(&self) -> usize {
+ self.0
+ }
+ }
+ };
+}
+
+index_impl!(ConstId);
+index_impl!(Ty);
+index_impl!(Span);
diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs
index 961009581..05e0b9b4d 100644
--- a/compiler/stable_mir/src/visitor.rs
+++ b/compiler/stable_mir/src/visitor.rs
@@ -47,12 +47,12 @@ impl Visitable for Const {
visitor.visit_const(self)
}
fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
- match &self.literal {
+ match &self.kind() {
super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?,
super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?,
- super::ty::ConstantKind::Param(_) => {}
+ super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {}
}
- self.ty.visit(visitor)
+ self.ty().visit(visitor)
}
}
@@ -148,7 +148,7 @@ impl Visitable for RigidTy {
RigidTy::FnDef(_, args) => args.visit(visitor),
RigidTy::FnPtr(sig) => sig.visit(visitor),
RigidTy::Closure(_, args) => args.visit(visitor),
- RigidTy::Generator(_, args, _) => args.visit(visitor),
+ RigidTy::Coroutine(_, args, _) => args.visit(visitor),
RigidTy::Dynamic(pred, r, _) => {
pred.visit(visitor)?;
r.visit(visitor)