Rollup merge of #117010 - celinval:smir-internal, r=oli-obk

Add method to convert internal to stable constructs

This is an alternative implementation to https://github.com/rust-lang/rust/pull/116999. I believe we can still improve the logic a bit here, but I wanted to see which direction we should go first.

In this implementation, the API is simpler and we keep Tables somewhat private. The definition is still public though, since we have to expose the Stable trait. However, there's a cost of keeping another thread-local and using `Rc`, but I'm hoping it will be a small cost.

r? ``@oli-obk``
r? ``@spastorino``
This commit is contained in:
Matthias Krüger 2023-10-24 19:29:56 +02:00 committed by GitHub
commit f131a0a771
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 281 additions and 141 deletions

View File

@ -4525,6 +4525,7 @@ dependencies = [
"rustc_middle",
"rustc_span",
"rustc_target",
"scoped-tls",
"stable_mir",
"tracing",
]

View File

@ -9,6 +9,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_middle = { path = "../rustc_middle" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
scoped-tls = "1.0"
stable_mir = {path = "../stable_mir" }
tracing = "0.1"

View File

@ -3,7 +3,7 @@
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
//! until stable MIR is complete.
use crate::rustc_smir::Tables;
use crate::rustc_smir::{Stable, Tables, TablesWrapper};
use rustc_data_structures::fx;
use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::mir::interpret::AllocId;
@ -11,13 +11,24 @@ use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Span;
use scoped_tls::scoped_thread_local;
use stable_mir::ty::IndexedVal;
use std::cell::Cell;
use std::cell::RefCell;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Index;
mod internal;
pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
with_tables(|tables| item.stable(tables))
}
pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
with_tables(|tables| item.internal(tables))
}
impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
type Output = DefId;
@ -125,18 +136,41 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
item.id.into()
}
// 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<*const ()>);
pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
assert!(!TLV.is_set());
let ptr = tables as *const _ as *const ();
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(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R {
assert!(TLV.is_set());
TLV.with(|tlv| {
let ptr = tlv.get();
assert!(!ptr.is_null());
let wrapper = ptr as *const TablesWrapper<'tcx>;
let mut tables = unsafe { (*wrapper).0.borrow_mut() };
f(&mut *tables)
})
}
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
stable_mir::run(
Tables {
tcx,
def_ids: IndexMap::default(),
alloc_ids: IndexMap::default(),
spans: IndexMap::default(),
types: vec![],
instances: IndexMap::default(),
},
f,
);
let tables = TablesWrapper(RefCell::new(Tables {
tcx,
def_ids: IndexMap::default(),
alloc_ids: IndexMap::default(),
spans: IndexMap::default(),
types: vec![],
instances: IndexMap::default(),
}));
stable_mir::run(&tables, || init(&tables, f));
}
#[macro_export]
@ -251,7 +285,7 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
/// Trait used to translate a stable construct to its rustc counterpart.
///
/// This is basically a mirror of [crate::rustc_smir::Stable].
pub(crate) trait RustcInternal<'tcx> {
pub trait RustcInternal<'tcx> {
type T;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
}

View File

@ -23,27 +23,31 @@ use stable_mir::ty::{
FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
};
use stable_mir::{self, opaque, Context, Filename};
use std::cell::RefCell;
use tracing::debug;
mod alloc;
mod builder;
impl<'tcx> Context for Tables<'tcx> {
impl<'tcx> Context for TablesWrapper<'tcx> {
fn local_crate(&self) -> stable_mir::Crate {
smir_crate(self.tcx, LOCAL_CRATE)
let tables = self.0.borrow();
smir_crate(tables.tcx, LOCAL_CRATE)
}
fn external_crates(&self) -> Vec<stable_mir::Crate> {
self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
let tables = self.0.borrow();
tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
}
fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
let tables = self.0.borrow();
let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
.iter()
.chain(self.tcx.crates(()).iter())
.chain(tables.tcx.crates(()).iter())
.map(|crate_num| {
let crate_name = self.tcx.crate_name(*crate_num).to_string();
(name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
let crate_name = tables.tcx.crate_name(*crate_num).to_string();
(name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
})
.into_iter()
.filter_map(|c| c)
@ -52,163 +56,197 @@ impl<'tcx> Context for Tables<'tcx> {
}
fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
self.tcx.def_path_str(self[def_id])
let tables = self.0.borrow();
tables.tcx.def_path_str(tables[def_id])
}
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
self.tcx.sess.source_map().span_to_diagnostic_string(self[span])
let tables = self.0.borrow();
tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
}
fn get_filename(&self, span: &Span) -> Filename {
let tables = self.0.borrow();
opaque(
&self
&tables
.tcx
.sess
.source_map()
.span_to_filename(self[*span])
.span_to_filename(tables[*span])
.display(rustc_span::FileNameDisplayPreference::Local)
.to_string(),
)
}
fn get_lines(&self, span: &Span) -> LineInfo {
let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]);
let tables = self.0.borrow();
let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
}
fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
self.tcx.def_kind(self[def_id]).stable(self)
fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
let mut tables = self.0.borrow_mut();
tables.tcx.def_kind(tables[def_id]).stable(&mut *tables)
}
fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> Span {
self.tcx.def_span(self[def_id]).stable(self)
fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
let mut tables = self.0.borrow_mut();
tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
}
fn all_local_items(&mut self) -> stable_mir::CrateItems {
self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
fn all_local_items(&self) -> stable_mir::CrateItems {
let mut tables = self.0.borrow_mut();
tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
}
fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
Some(self.crate_item(self.tcx.entry_fn(())?.0))
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
Some(tables.crate_item(tcx.entry_fn(())?.0))
}
fn all_trait_decls(&mut self) -> stable_mir::TraitDecls {
self.tcx
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
let mut tables = self.0.borrow_mut();
tables
.tcx
.traits(LOCAL_CRATE)
.iter()
.map(|trait_def_id| self.trait_def(*trait_def_id))
.map(|trait_def_id| tables.trait_def(*trait_def_id))
.collect()
}
fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
let def_id = self[trait_def.0];
let trait_def = self.tcx.trait_def(def_id);
trait_def.stable(self)
fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
let mut tables = self.0.borrow_mut();
let def_id = tables[trait_def.0];
let trait_def = tables.tcx.trait_def(def_id);
trait_def.stable(&mut *tables)
}
fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls {
self.tcx
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
let mut tables = self.0.borrow_mut();
tables
.tcx
.trait_impls_in_crate(LOCAL_CRATE)
.iter()
.map(|impl_def_id| self.impl_def(*impl_def_id))
.map(|impl_def_id| tables.impl_def(*impl_def_id))
.collect()
}
fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
let def_id = self[impl_def.0];
let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap();
impl_trait.stable(self)
fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
let mut tables = self.0.borrow_mut();
let def_id = tables[impl_def.0];
let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
impl_trait.stable(&mut *tables)
}
fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
let def_id = self[item];
self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self)
fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
let mut tables = self.0.borrow_mut();
let def_id = tables[item];
tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables)
}
fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind {
self.types[ty.0].clone().stable(self)
fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
let mut tables = self.0.borrow_mut();
tables.types[ty.0].clone().stable(&mut *tables)
}
fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty {
let n = self.types.len();
self.types.push(MaybeStable::Stable(kind));
fn mk_ty(&self, kind: TyKind) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let n = tables.types.len();
tables.types.push(MaybeStable::Stable(kind));
stable_mir::ty::Ty(n)
}
fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
let def_id = self[def_id];
let generics = self.tcx.generics_of(def_id);
generics.stable(self)
fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let generics = tables.tcx.generics_of(def_id);
generics.stable(&mut *tables)
}
fn predicates_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let def_id = self[def_id];
let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id);
fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| self.trait_def(did)),
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates
.iter()
.map(|(clause, span)| {
(clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
(
clause.as_predicate().kind().skip_binder().stable(&mut *tables),
span.stable(&mut *tables),
)
})
.collect(),
}
}
fn explicit_predicates_of(
&mut self,
&self,
def_id: stable_mir::DefId,
) -> stable_mir::ty::GenericPredicates {
let def_id = self[def_id];
let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id);
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let ty::GenericPredicates { parent, predicates } =
tables.tcx.explicit_predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| self.trait_def(did)),
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates
.iter()
.map(|(clause, span)| {
(clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
(
clause.as_predicate().kind().skip_binder().stable(&mut *tables),
span.stable(&mut *tables),
)
})
.collect(),
}
}
fn instance_body(&mut self, def: InstanceDef) -> Body {
let instance = self.instances[def];
builder::BodyBuilder::new(self.tcx, instance).build(self)
fn instance_body(&self, def: InstanceDef) -> Body {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
}
fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
let instance = self.instances[def];
let ty = instance.ty(self.tcx, ParamEnv::empty());
self.intern_ty(ty)
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
let ty = instance.ty(tables.tcx, ParamEnv::empty());
tables.intern_ty(ty)
}
fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId {
let def_id = self.instances[def].def_id();
self.create_def_id(def_id)
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
let mut tables = self.0.borrow_mut();
let def_id = tables.instances[def].def_id();
tables.create_def_id(def_id)
}
fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
let def_id = self[item.0];
Instance::mono(self.tcx, def_id).stable(self)
fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
let mut tables = self.0.borrow_mut();
let def_id = tables[item.0];
Instance::mono(tables.tcx, def_id).stable(&mut *tables)
}
fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
let def_id = self[def_id];
let generics = self.tcx.generics_of(def_id);
let result = generics.requires_monomorphization(self.tcx);
let tables = self.0.borrow();
let def_id = tables[def_id];
let generics = tables.tcx.generics_of(def_id);
let result = generics.requires_monomorphization(tables.tcx);
result
}
fn resolve_instance(
&mut self,
&self,
def: stable_mir::ty::FnDef,
args: &stable_mir::ty::GenericArgs,
) -> Option<stable_mir::mir::mono::Instance> {
let def_id = def.0.internal(self);
let args_ref = args.internal(self);
match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
Ok(Some(instance)) => Some(instance.stable(self)),
let mut tables = self.0.borrow_mut();
let def_id = def.0.internal(&mut *tables);
let args_ref = args.internal(&mut *tables);
match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
Ok(None) | Err(_) => None,
}
}
@ -241,13 +279,15 @@ impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
}
}
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
pub struct Tables<'tcx> {
pub tcx: TyCtxt<'tcx>,
pub def_ids: IndexMap<DefId, stable_mir::DefId>,
pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
pub spans: IndexMap<rustc_span::Span, Span>,
pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
pub(crate) spans: IndexMap<rustc_span::Span, Span>,
pub(crate) types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
}
impl<'tcx> Tables<'tcx> {
@ -270,7 +310,7 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
}
/// Trait used to convert between an internal MIR type to a Stable MIR type.
pub(crate) trait Stable<'tcx> {
pub trait Stable<'tcx> {
/// The stable representation of the type implementing Stable.
type T;
/// Converts an object to the equivalent Stable MIR representation.

View File

@ -175,17 +175,17 @@ 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.
@ -207,61 +207,58 @@ pub trait Context {
fn get_lines(&self, span: &Span) -> LineInfo;
/// Returns the `kind` of given `DefId`
fn def_kind(&mut self, def_id: DefId) -> DefKind;
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;
/// Create a new `Ty` from scratch without information from rustc.
fn mk_ty(&mut self, kind: TyKind) -> Ty;
fn mk_ty(&self, kind: TyKind) -> Ty;
/// Get the body of an Instance.
/// FIXME: Monomorphize the body.
fn instance_body(&mut self, instance: InstanceDef) -> Body;
fn instance_body(&self, instance: InstanceDef) -> Body;
/// Get the instance type with generic substitutions applied and lifetimes erased.
fn instance_ty(&mut self, instance: InstanceDef) -> Ty;
fn instance_ty(&self, instance: InstanceDef) -> Ty;
/// Get the instance.
fn instance_def_id(&mut self, instance: InstanceDef) -> DefId;
fn instance_def_id(&self, instance: InstanceDef) -> DefId;
/// Convert a non-generic crate item into an instance.
/// This function will panic if the item is generic.
fn mono_instance(&mut self, item: CrateItem) -> Instance;
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(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
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) })
})
}

View File

@ -1,5 +1,5 @@
// run-pass
// Test that users are able to use stable mir APIs to retrieve monomorphized instances
//! Test that users are able to use stable mir APIs to retrieve monomorphized instances
// ignore-stage1
// ignore-cross-compile
@ -14,15 +14,15 @@
extern crate rustc_middle;
#[macro_use]
extern crate rustc_smir;
extern crate stable_mir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use rustc_middle::ty::TyCtxt;
use mir::{mono::Instance, TerminatorKind::*};
use stable_mir::ty::{TyKind, RigidTy};
use stable_mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::ty::{RigidTy, TyKind};
use stable_mir::*;
use std::io::Write;
use std::ops::ControlFlow;
@ -33,16 +33,16 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
let items = stable_mir::all_local_items();
// Get all items and split generic vs monomorphic items.
let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| {
item.requires_monomorphization()
});
let (generic, mono): (Vec<_>, Vec<_>) =
items.into_iter().partition(|item| item.requires_monomorphization());
assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant");
assert_eq!(generic.len(), 2, "Expected 2 generic functions");
// For all monomorphic items, get the correspondent instances.
let instances = mono.iter().filter_map(|item| {
mir::mono::Instance::try_from(*item).ok()
}).collect::<Vec<mir::mono::Instance>>();
let instances = mono
.iter()
.filter_map(|item| mir::mono::Instance::try_from(*item).ok())
.collect::<Vec<mir::mono::Instance>>();
assert_eq!(instances.len(), mono.len());
// For all generic items, try_from should fail.
@ -58,19 +58,22 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
fn test_body(body: mir::Body) {
for term in body.blocks.iter().map(|bb| &bb.terminator) {
match &term.kind {
Call{ func, .. } => {
Call { func, .. } => {
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
let result = Instance::resolve(def, &args);
assert!(result.is_ok());
}
Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */}
_ => { unreachable!("Unexpected terminator {term:?}") }
Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
/* Do nothing */
}
_ => {
unreachable!("Unexpected terminator {term:?}")
}
}
}
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then

View File

@ -0,0 +1,64 @@
// run-pass
//! Test that users are able to use retrieve internal constructs from stable ones to help with
//! the migration.
// ignore-stage1
// ignore-cross-compile
// ignore-remote
// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
// edition: 2021
#![feature(rustc_private)]
#![feature(assert_matches)]
#![feature(control_flow_enum)]
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate stable_mir;
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use std::io::Write;
use std::ops::ControlFlow;
const CRATE_NAME: &str = "input";
fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
let main_fn = stable_mir::entry_fn().unwrap();
let body = main_fn.body();
let orig_ty = body.locals[0].ty;
let rustc_ty = rustc_internal::internal(&orig_ty);
assert!(rustc_ty.is_unit());
ControlFlow::Continue(())
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
/// it will run the compiler.
fn main() {
let path = "internal_input.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run!(args, tcx, test_translation(tcx)).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
pub fn main() {{
}}
"#
)?;
Ok(())
}