Skip to content

Commit f540359

Browse files
authored
Unrolled build for #140643
Rollup merge of #140643 - makai410:smir-refactor-migrate, r=oli-obk,celinval Refactor StableMIR This PR refactors stable-mir according to the guidance in [this doc](https://hackmd.io/jBRkZLqAQL2EVgwIIeNMHg). It reverses the dependency between `rustc_smir` and `stable_mir`, making `rustc_smir` completely agnostic of `stable_mir`. Under the new architecture, the `rustc_smir` crate would retain direct access to rustc queries, while `stable_mir` should proxy all such requests through `rustc_smir` instead of accessing rustc's internals directly. `stable_mir` would only be responsible for the conversion between internal and stable constructs. This PR mainly introduces these changes: - **Bridge / Tables<'tcx, B: Bridge>** ```rust /// A trait defining types that are used to emulate StableMIR components, which is really /// useful when programming in stable_mir-agnostic settings. pub trait Bridge { type DefId: Copy + Debug + PartialEq + IndexedVal; type AllocId: Copy + Debug + PartialEq + IndexedVal; type Span: Copy + Debug + PartialEq + IndexedVal; type Ty: Copy + Debug + PartialEq + IndexedVal; type InstanceDef: Copy + Debug + PartialEq + IndexedVal; type TyConstId: Copy + Debug + PartialEq + IndexedVal; type MirConstId: Copy + Debug + PartialEq + IndexedVal; type Layout: Copy + Debug + PartialEq + IndexedVal; type Error: SmirError; } pub struct Tables<'tcx, B: Bridge> { tcx: TyCtxt<'tcx>, pub(crate) def_ids: IndexMap<DefId, B::DefId>, pub(crate) alloc_ids: IndexMap<AllocId, B::AllocId>, pub(crate) spans: IndexMap<rustc_span::Span, B::Span>, pub(crate) types: IndexMap<Ty<'tcx>, B::Ty>, pub(crate) instances: IndexMap<ty::Instance<'tcx>, B::InstanceDef>, pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, B::TyConstId>, pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, B::MirConstId>, pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, B::Layout>, } ``` Since `rustc_smir` needs these stable types somewhere, using associated types is a good approach. - **SmirContainer / SmirInterface** ```rust /// A container which is used for TLS. pub struct SmirContainer<'tcx, B: Bridge> { pub tables: RefCell<Tables<'tcx, B>>, pub cx: RefCell<SmirCtxt<'tcx, B>>, } impl<'tcx> SmirInterface for SmirContainer<'tcx, BridgeTys> { // ... } /// Provides direct access to rustc's internal queries. /// /// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through /// this context to obtain rustc-level information. pub struct SmirCtxt<'tcx, B: Bridge> { tcx: TyCtxt<'tcx>, _marker: PhantomData<B>, } ``` This PR moves `Tables` from `SmirCtxt` to a new `SmirContainer` struct, since mutable borrows of `tables` should only be managed by `SmirInterface`. This change prevents `SmirCtxt` from holding separate borrows and requires passing `tables` explicitly when needed: ```rust impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> { // ... /// Get the body of an Instance which is already monomorphized. pub fn instance_body( &self, instance: ty::Instance<'tcx>, tables: &mut Tables<'tcx, B>, ) -> Option<Body<'tcx>> { tables .instance_has_body(instance) .then(|| BodyBuilder::new(self.tcx, instance).build(tables)) } // ... } ``` This PR introduces `SmirContainer` as a separate struct rather than bundling it into a `SmirInterface` struct. This separation makes the architecture more modular and easier to reason about. - **context/traits.rs** We use this file to define traits that are used for encapsulating the associated functions in the rustc's internals. This is much easier to use and maintain than directly cramming everything into `SmirCtxt`. Here is a real-world use case: ```rust impl RustcInternal for ExistentialTraitRef { type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; fn internal<'tcx>( &self, tables: &mut Tables<'_, BridgeTys>, cx: &SmirCtxt<'tcx, BridgeTys>, ) -> Self::T<'tcx> { use rustc_smir::context::SmirExistentialTraitRef; cx.new_from_args(self.def_id.0.internal(tables, cx), self.generic_args.internal(tables, cx)) } } ``` - **Separation of `rustc_smir::alloc`** The previous `rustc_smir::alloc` had many direct calls to rustc queries. This PR splits it into two parts: `rustc_smir::alloc` and `stable_mir::alloc`. Following the same pattern as `SmirCtxt` and `SmirInterface`, the `rustc_smir::alloc` handles all direct interactions with rustc queries and performs the actual memory allocations, while the `stable_mir::alloc` is responsible for constructing stable components. - **Removal of `convert/error.rs`** We use `SmirError::from_internal` instead, since implementing `Stable` for these internal errors would be redundant—`tables` is not actually used. If we later need to add something like `LayoutError` to `stable_mir`, we could implement it as follows: ```rust impl SmirError for stable_mir::LayoutError { fn from_internal<T: Debug>(err: T) -> Self { // ... } } ``` **Unresolved questions:** - There are still a few direct calls to rustc's internals scattered across `impl Stable`s, but most of them appear to be relatively stable, e.g., `mir::interpret::ConstAllocation::inner(self)` and `mir::syntax::SwitchTargets::otherwise(self)`. r? `@celinval`
2 parents 556d20a + e26ae60 commit f540359

File tree

26 files changed

+3598
-2224
lines changed

26 files changed

+3598
-2224
lines changed

compiler/rustc_smir/src/rustc_internal/mod.rs

Lines changed: 19 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,17 @@
44
//! until stable MIR is complete.
55
66
use std::cell::{Cell, RefCell};
7-
use std::fmt::Debug;
8-
use std::hash::Hash;
9-
use std::ops::Index;
107

11-
use rustc_data_structures::fx;
12-
use rustc_data_structures::fx::FxIndexMap;
13-
use rustc_middle::mir::interpret::AllocId;
14-
use rustc_middle::ty;
158
use rustc_middle::ty::TyCtxt;
16-
use rustc_span::Span;
17-
use rustc_span::def_id::{CrateNum, DefId};
9+
use rustc_span::def_id::CrateNum;
1810
use scoped_tls::scoped_thread_local;
1911
use stable_mir::Error;
20-
use stable_mir::abi::Layout;
21-
use stable_mir::compiler_interface::SmirInterface;
22-
use stable_mir::ty::IndexedVal;
12+
use stable_mir::unstable::{RustcInternal, Stable};
2313

2414
use crate::rustc_smir::context::SmirCtxt;
25-
use crate::rustc_smir::{Stable, Tables};
15+
use crate::rustc_smir::{Bridge, SmirContainer, Tables};
2616
use crate::stable_mir;
2717

28-
mod internal;
2918
pub mod pretty;
3019

3120
/// Convert an internal Rust compiler item into its stable counterpart, if one exists.
@@ -40,7 +29,7 @@ pub mod pretty;
4029
///
4130
/// This function will panic if StableMIR has not been properly initialized.
4231
pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T {
43-
with_tables(|tables| item.stable(tables))
32+
with_container(|tables, cx| item.stable(tables, cx))
4433
}
4534

4635
/// Convert a stable item into its internal Rust compiler counterpart, if one exists.
@@ -59,134 +48,9 @@ where
5948
S: RustcInternal,
6049
{
6150
// The tcx argument ensures that the item won't outlive the type context.
62-
with_tables(|tables| item.internal(tables, tcx))
63-
}
64-
65-
impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
66-
type Output = DefId;
67-
68-
#[inline(always)]
69-
fn index(&self, index: stable_mir::DefId) -> &Self::Output {
70-
&self.def_ids[index]
71-
}
72-
}
73-
74-
impl<'tcx> Index<stable_mir::ty::Span> for Tables<'tcx> {
75-
type Output = Span;
76-
77-
#[inline(always)]
78-
fn index(&self, index: stable_mir::ty::Span) -> &Self::Output {
79-
&self.spans[index]
80-
}
81-
}
82-
83-
impl<'tcx> Tables<'tcx> {
84-
pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
85-
stable_mir::CrateItem(self.create_def_id(did))
86-
}
87-
88-
pub fn adt_def(&mut self, did: DefId) -> stable_mir::ty::AdtDef {
89-
stable_mir::ty::AdtDef(self.create_def_id(did))
90-
}
91-
92-
pub fn foreign_module_def(&mut self, did: DefId) -> stable_mir::ty::ForeignModuleDef {
93-
stable_mir::ty::ForeignModuleDef(self.create_def_id(did))
94-
}
95-
96-
pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef {
97-
stable_mir::ty::ForeignDef(self.create_def_id(did))
98-
}
99-
100-
pub fn fn_def(&mut self, did: DefId) -> stable_mir::ty::FnDef {
101-
stable_mir::ty::FnDef(self.create_def_id(did))
102-
}
103-
104-
pub fn closure_def(&mut self, did: DefId) -> stable_mir::ty::ClosureDef {
105-
stable_mir::ty::ClosureDef(self.create_def_id(did))
106-
}
107-
108-
pub fn coroutine_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineDef {
109-
stable_mir::ty::CoroutineDef(self.create_def_id(did))
110-
}
111-
112-
pub fn coroutine_closure_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineClosureDef {
113-
stable_mir::ty::CoroutineClosureDef(self.create_def_id(did))
114-
}
115-
116-
pub fn alias_def(&mut self, did: DefId) -> stable_mir::ty::AliasDef {
117-
stable_mir::ty::AliasDef(self.create_def_id(did))
118-
}
119-
120-
pub fn param_def(&mut self, did: DefId) -> stable_mir::ty::ParamDef {
121-
stable_mir::ty::ParamDef(self.create_def_id(did))
122-
}
123-
124-
pub fn br_named_def(&mut self, did: DefId) -> stable_mir::ty::BrNamedDef {
125-
stable_mir::ty::BrNamedDef(self.create_def_id(did))
126-
}
127-
128-
pub fn trait_def(&mut self, did: DefId) -> stable_mir::ty::TraitDef {
129-
stable_mir::ty::TraitDef(self.create_def_id(did))
130-
}
131-
132-
pub fn generic_def(&mut self, did: DefId) -> stable_mir::ty::GenericDef {
133-
stable_mir::ty::GenericDef(self.create_def_id(did))
134-
}
135-
136-
pub fn const_def(&mut self, did: DefId) -> stable_mir::ty::ConstDef {
137-
stable_mir::ty::ConstDef(self.create_def_id(did))
138-
}
139-
140-
pub fn impl_def(&mut self, did: DefId) -> stable_mir::ty::ImplDef {
141-
stable_mir::ty::ImplDef(self.create_def_id(did))
142-
}
143-
144-
pub fn region_def(&mut self, did: DefId) -> stable_mir::ty::RegionDef {
145-
stable_mir::ty::RegionDef(self.create_def_id(did))
146-
}
147-
148-
pub fn coroutine_witness_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineWitnessDef {
149-
stable_mir::ty::CoroutineWitnessDef(self.create_def_id(did))
150-
}
151-
152-
pub fn assoc_def(&mut self, did: DefId) -> stable_mir::ty::AssocDef {
153-
stable_mir::ty::AssocDef(self.create_def_id(did))
154-
}
155-
156-
pub fn opaque_def(&mut self, did: DefId) -> stable_mir::ty::OpaqueDef {
157-
stable_mir::ty::OpaqueDef(self.create_def_id(did))
158-
}
159-
160-
pub fn prov(&mut self, aid: AllocId) -> stable_mir::ty::Prov {
161-
stable_mir::ty::Prov(self.create_alloc_id(aid))
162-
}
163-
164-
pub(crate) fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
165-
self.def_ids.create_or_fetch(did)
166-
}
167-
168-
pub(crate) fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId {
169-
self.alloc_ids.create_or_fetch(aid)
170-
}
171-
172-
pub(crate) fn create_span(&mut self, span: Span) -> stable_mir::ty::Span {
173-
self.spans.create_or_fetch(span)
174-
}
175-
176-
pub(crate) fn instance_def(
177-
&mut self,
178-
instance: ty::Instance<'tcx>,
179-
) -> stable_mir::mir::mono::InstanceDef {
180-
self.instances.create_or_fetch(instance)
181-
}
182-
183-
pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
184-
stable_mir::mir::mono::StaticDef(self.create_def_id(did))
185-
}
186-
187-
pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout {
188-
self.layouts.create_or_fetch(layout)
189-
}
51+
// See https://github.com/rust-lang/rust/pull/120128/commits/9aace6723572438a94378451793ca37deb768e72
52+
// for more details.
53+
with_container(|tables, _| item.internal(tables, tcx))
19054
}
19155

19256
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -197,49 +61,39 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
19761
// datastructures and stable MIR datastructures
19862
scoped_thread_local! (static TLV: Cell<*const ()>);
19963

200-
pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T
64+
pub(crate) fn init<'tcx, F, T, B: Bridge>(container: &SmirContainer<'tcx, B>, f: F) -> T
20165
where
20266
F: FnOnce() -> T,
20367
{
20468
assert!(!TLV.is_set());
205-
let ptr = cx as *const _ as *const ();
69+
let ptr = container as *const _ as *const ();
20670
TLV.set(&Cell::new(ptr), || f())
20771
}
20872

20973
/// Loads the current context and calls a function with it.
21074
/// Do not nest these, as that will ICE.
211-
pub(crate) fn with_tables<R>(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) -> R {
75+
pub(crate) fn with_container<R, B: Bridge>(
76+
f: impl for<'tcx> FnOnce(&mut Tables<'tcx, B>, &SmirCtxt<'tcx, B>) -> R,
77+
) -> R {
21278
assert!(TLV.is_set());
21379
TLV.with(|tlv| {
21480
let ptr = tlv.get();
21581
assert!(!ptr.is_null());
216-
let context = ptr as *const SmirCtxt<'_>;
217-
let mut tables = unsafe { (*context).0.borrow_mut() };
218-
f(&mut *tables)
82+
let container = ptr as *const SmirContainer<'_, B>;
83+
let mut tables = unsafe { (*container).tables.borrow_mut() };
84+
let cx = unsafe { (*container).cx.borrow() };
85+
f(&mut *tables, &*cx)
21986
})
22087
}
22188

22289
pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
22390
where
22491
F: FnOnce() -> T,
22592
{
226-
let tables = SmirCtxt(RefCell::new(Tables {
227-
tcx,
228-
def_ids: IndexMap::default(),
229-
alloc_ids: IndexMap::default(),
230-
spans: IndexMap::default(),
231-
types: IndexMap::default(),
232-
instances: IndexMap::default(),
233-
ty_consts: IndexMap::default(),
234-
mir_consts: IndexMap::default(),
235-
layouts: IndexMap::default(),
236-
}));
93+
let smir_cx = RefCell::new(SmirCtxt::new(tcx));
94+
let container = SmirContainer { tables: RefCell::new(Tables::default()), cx: smir_cx };
23795

238-
let interface = SmirInterface { cx: tables };
239-
240-
// Pass the `SmirInterface` to compiler_interface::run
241-
// and initialize the rustc-specific TLS with tables.
242-
stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f))
96+
stable_mir::compiler_interface::run(&container, || init(&container, f))
24397
}
24498

24599
/// Instantiate and run the compiler with the provided arguments and callback.
@@ -417,43 +271,3 @@ macro_rules! run_driver {
417271
StableMir::new($callback).run($args)
418272
}};
419273
}
420-
421-
/// Similar to rustc's `FxIndexMap`, `IndexMap` with extra
422-
/// safety features added.
423-
pub struct IndexMap<K, V> {
424-
index_map: fx::FxIndexMap<K, V>,
425-
}
426-
427-
impl<K, V> Default for IndexMap<K, V> {
428-
fn default() -> Self {
429-
Self { index_map: FxIndexMap::default() }
430-
}
431-
}
432-
433-
impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> {
434-
pub fn create_or_fetch(&mut self, key: K) -> V {
435-
let len = self.index_map.len();
436-
let v = self.index_map.entry(key).or_insert(V::to_val(len));
437-
*v
438-
}
439-
}
440-
441-
impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V>
442-
for IndexMap<K, V>
443-
{
444-
type Output = K;
445-
446-
fn index(&self, index: V) -> &Self::Output {
447-
let (k, v) = self.index_map.get_index(index.to_index()).unwrap();
448-
assert_eq!(*v, index, "Provided value doesn't match with indexed value");
449-
k
450-
}
451-
}
452-
453-
/// Trait used to translate a stable construct to its rustc counterpart.
454-
///
455-
/// This is basically a mirror of [crate::rustc_smir::Stable].
456-
pub trait RustcInternal {
457-
type T<'tcx>;
458-
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx>;
459-
}

0 commit comments

Comments
 (0)