GSoC 2025 Final Report
I love making holes in stuff.
Overview
My project this summer is about stable_mir
, a crate that is being developed to be the public API of the Rust compiler.
stable_mir
has undergone many changes so far. We even renamed stable_mir
to a cooler name: rustc_public
, which better reflects the project's scope, because nowadays our APIs coverage goes beyond MIR, and we don't aim to provide stability in the common sense, e.g., Rust 1.0, that is not what we aim at.
The high-level goal for this summer is to prepare the rustc_public
(a.k.a. stable_mir
) crate for publishing. Speaking of which, we aim to publish this crate on crates.io, allowing users to explicitly select it.
My work
Refactoring the crates structure
The previous crate structure is the main blocker for publishing. For context, there were two crates in the Rust compiler: stable_mir
and rustc_smir
. We intend to invert the dependency between them, making rustc_smir
completely agnostic of stable_mir
. For the full background and the reasons why we want to do that, please refer to this proposal for more details. Here I'd like to directly walk through the PRs related to this work.
Firstly, given that our goal is to reverse the dependency order, which requires a sequence of PRs, we had to figure out a strategy to resolve the circular dependency that would arise during development. For some reason the word "parasitism" came to mind: what if we make stable_mir
parasitic on rustc_smir
? Therefore:
- rust-lang/rust#139319
This PR moved
stable_mir
into therustc_smir
crate as a module, which was a temporary tweak to resolve the circular dependency that would arise if we directly invert the dependency order betweenrustc_smir
andstable_mir
.
Okay, now we can let stable_mir
grow freely. Next up:
Implement CompilerInterface
- rust-lang/rust#139852
This PR split the previous
Context
struct into two parts:SmirInterface
andSmirCtxt
. See this section for more details. After this PR was merged, our code was like:
// stable_mir/compiler_interface.rs
/// Stable public API for querying compiler information.
///
/// All queries are delegated to an internal [`SmirCtxt`] that provides
/// similar APIs but based on internal rustc constructs.
///
/// Do not use this directly. This is currently used in the macro expansion.
pub
// rustc_smir/context.rs
/// 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.
;
This was getting close to what we anticipated. xD
Refactor StableMIR
- rust-lang/rust#140643 This was a huge PR that completed most of the refactoring and introduced many implementation details. I don't want to list them one by one here. By the way, the most painful part of this work was manually rewriting nearly a hundred APIs .
Now that we've finished the refactoring, let's move it back!
- rust-lang/rust#143524
This PR moved
stable_mir
back to its own crate.
Finally, we renamed stable_mir
to rustc_public
, and rustc_smir
to rustc_public_bridge
.
At the end of the day, the code above now looks like:
// rustc_public/compiler_interface.rs
// rustc_public_bridge/context/mod.rs
/// Provides direct access to rustc's internal queries.
///
/// `CompilerInterface` must go through
/// this context to obtain internal information.
// rustc_public_bridge/lib.rs
/// A container which is used for TLS.
Establishing infrastructure
For context, we'd maintain two versions of rustc_public
, the crates.io version and the rustc version. The first will be published on crates.io and follow semantic versioning, while the second will track internal changes and serve as the base for each new major release.
For this to happen, we leverage rustc-josh-sync to sync changes as we see fit. We've cloned rustc_public
into our own repo in rust-lang/project-stable-mir#104. We'd enable the josh cronjob in rust-lang/project-stable-mir#107.
Devtool
- rust-lang/project-stable-mir#105
This is a development helper for maintaining
rustc_public
. Currently it supports commands likebuild
,test [--bless] [--verbose]
,clean
,fmt [--check]
,githook install/uninstall
, andhelp
. To stay consistent with the rustc development experience, I named our shell script x, so contributors can simply run commands like./x build
or./x test
.
Build-time check
- also in rust-lang/project-stable-mir#105
I write a simple
build.rs
to warn the user if they are using an unsupported rustc version and makes the build fail, while providing some suggestions.
Compiletest
- also in rust-lang/project-stable-mir#105
This is a test script leveraging the
ui_test
crate to run all test suites we now have.
That said, at the time I wrote this, rust-lang/project-stable-mir#105 was still under review.
Misc
- Removed a FIXME from
rustc_public
: rust-lang/rust#144392. - Fixed a missing parenthesis in pretty printing: rust-lang/rust#145119
- Fix book deployment CI: rust-lang/project-stable-mir#106
- Fix the rustc_public demo: rust-lang/project-stable-mir#108
Future work
Release automation
I plan to implement a release automation CI that runs cargo-semver-checks, automatically bumps the crate version, and update the rustc_public
to crates.io.
Documentation
rustc_public
currently lacks proper documentation. I'd love to help create a dedicated section for rustc_public
on rustc-dev-guide.rust-lang.org, and write the contributing guide for it.
A stable rustc_public driver
At the moment, there is no stable way to drive rustc_public. We only have a rustc_internal::run!()
macro to drive it, which is however in the unstable/
. We’d really like to have a more fully-featured, stable driver.
Thanks to
- My mentor Celina Val, who’s been very patient and helped me learn a lot.
- oli-obk, who suggested setting up the josh sync and reviewed many of my PRs.
- beef :3
- Jakub Beránek, who helped me understand the josh sync better.
- Jieyou Xu, I don't know but I just want to say thanks :3
- The infra team.
- Everyone I've chatted with on Zulip so far.
- The Rust Foundation.
- Google, definitely.