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` |
||
|---|---|---|
| .github | ||
| compiler | ||
| library | ||
| LICENSES | ||
| src | ||
| tests | ||
| .clang-format | ||
| .editorconfig | ||
| .git-blame-ignore-revs | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| .ignore | ||
| .mailmap | ||
| bootstrap.example.toml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| configure | ||
| CONTRIBUTING.md | ||
| COPYRIGHT | ||
| INSTALL.md | ||
| LICENSE-APACHE | ||
| license-metadata.json | ||
| LICENSE-MIT | ||
| README.md | ||
| RELEASES.md | ||
| REUSE.toml | ||
| rust-bors.toml | ||
| rustfmt.toml | ||
| triagebot.toml | ||
| typos.toml | ||
| x | ||
| x.ps1 | ||
| x.py | ||
This is the main source code repository for Rust. It contains the compiler, standard library, and documentation.
Why Rust?
-
Performance: Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages.
-
Reliability: Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
-
Productivity: Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool (Cargo), auto-formatter (rustfmt), linter (Clippy) and editor support (rust-analyzer).
Quick Start
Read "Installation" from The Book.
Installing from Source
If you really want to install from source (though this is not recommended), see INSTALL.md.
Getting Help
See https://www.rust-lang.org/community for a list of chat platforms and forums.
Contributing
See CONTRIBUTING.md.
License
Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.
See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.
Trademark
The Rust Foundation owns and protects the Rust and Cargo trademarks and logos (the "Rust Trademarks").
If you want to use these names or brands, please read the Rust language trademark policy.
Third-party logos may be subject to third-party copyrights and trademarks. See Licenses for details.