diff options
Diffstat (limited to 'compiler/stable_mir')
-rw-r--r-- | compiler/stable_mir/src/error.rs | 76 | ||||
-rw-r--r-- | compiler/stable_mir/src/fold.rs | 245 | ||||
-rw-r--r-- | compiler/stable_mir/src/lib.rs | 150 | ||||
-rw-r--r-- | compiler/stable_mir/src/mir.rs | 3 | ||||
-rw-r--r-- | compiler/stable_mir/src/mir/body.rs | 184 | ||||
-rw-r--r-- | compiler/stable_mir/src/mir/mono.rs | 102 | ||||
-rw-r--r-- | compiler/stable_mir/src/mir/visit.rs | 414 | ||||
-rw-r--r-- | compiler/stable_mir/src/ty.rs | 182 | ||||
-rw-r--r-- | compiler/stable_mir/src/visitor.rs | 8 |
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) |