The Rust project is currently working towards a slate of 4 project goals, with 1 of them designated as Flagship Goals. This post provides selected updates on our progress towards these goals (or, in some cases, lack thereof). The full details for any particular goal are available in its associated tracking issue on the rust-project-goals repository.
Flagship goals
"Flexible, fast(er) compilation"
| Progress | |
| Point of contact | |
| Champions | cargo (Eric Huss), compiler (David Wood), libs (Amanieu d'Antras) |
| Task owners |
1 detailed update available.
We've now opened our first batch of RFCs: rust-lang/rfcs#3873, rust-lang/rfcs#3874 and rust-lang/rfcs#3875
Goals looking for help
Other goal updates
| Progress | |
| Point of contact | |
| Champions | compiler (Oliver Scherer), lang (Tyler Mandry), libs (David Tolnay) |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | compiler (Oliver Scherer), lang (Scott McMurray), libs (Josh Triplett) |
| Task owners | oli-obk |
1 detailed update available.
I implemented an initial MVP supporting only tuples and primitives (tho those are just opaque things you can't interact with further), and getting offsets for the tuple fields as well as the size of the tuple: https://github.com/rust-lang/rust/pull/146923
There are two designs of how to expose this from a libs perspective, but after a sync meeting with scottmcm yesterday we came to the conclusion that neither is objectively better at this stage so we're just going to go with the nice end-user UX version for now. For details see the PR description.
Once the MVP lands, I will mentor various interested contributors who will keep adding fields to the Type struct and variants the TypeKind enum.
The next major step is restricting what information you can get from structs outside of the current module or crate. We want to honor visibility, so an initial step would be to just never show private fields, but we want to explore allowing private fields to be shown either just within the current module or via some opt-in marker trait
| Progress | |
| Point of contact | |
| Champions | compiler (David Wood), lang (Niko Matsakis), libs (Amanieu d'Antras) |
| Task owners |
1 detailed update available.
Sized hierarchy
The focus right now is on the "non-const" parts of the proposal, as the "const" parts are blocked on the new trait solver (https://github.com/rust-lang/rust-project-goals/issues/113). Now that the types team FCP https://github.com/rust-lang/rust/pull/144064 has completed, work can proceed to land the implementation PRs. David Wood plans to split the RFC to separate out the "non-const" parts of the proposal so it can move independently, which will enable extern types.
To that end, there are three interesting T-lang design questions to be considered.
Naming of the traits
The RFC currently proposes the following names
SizedMetaSizedPointeeSized
However, these names do not follow the "best practice" of naming the trait after the capability that it provides. As champion Niko is recommending we shift to the following names:
Sized-- should righly be calledSizeOf, but oh well, not worth changing.SizeOfVal-- named after the methodsize_of_valthat you get access to.Pointee-- the only thing you can do is point at it.
The last trait name is already used by the (unstable) std::ptr::Pointee trait. We do not want to have these literally be the same trait because that trait adds a Metadata associated type which would be backwards incompatible; if existing code uses T::Metadata to mean <T as SomeOtherTrait>::Metadata, it could introduce ambiguity if now T: Pointee due to defaults. My proposal is to rename std::ptr::Pointee to std::ptr::PointeeMetadata for now, since that trait is unstable and the design remains under some discussion. The two traits could either be merged eventually or remain separate.
Note that PointeeMetadata would be implemented automatically by the compiler for anything that implements Pointee.
Syntax opt-in
The RFC proposes that an explicit bound like T: MetaSized disabled the default T: Sized bound. However, this gives no signal that this trait bound is "special" or different than any other trait bound. Naming conventions can help here, signalling to users that these are special traits, but that leads to constraints on naming and may not scale as we consider using this mechanism to relax other defaults as proposed in my recent blog post. One idea is to use some form of syntax, so that T: MetaSized is just a regular bound, but (for example) T: =MetaSized indicates that this bound "disables" the default Sized bound. This gives users some signal that something special is going on. This = syntax is borrowing from semver constraints, although it's not a precise match (it does not mean that T: Sized doesn't hold, after all). Other proposals would be some other sigil (T: ?MetaSized, but it means "opt out from the traits above you"; T: #MetaSized, ...) or a keyword (no idea).
To help us get a feel for it, I'll use T: =Foo throughout this post.
Implicit trait supertrait bounds, edition interaction
In Rust 2024, a trait is implicitly ?Sized which gets mapped to =SizeOfVal:
#![allow(unused)] fn main() { trait Marker {} // cannot be implemented by extern types }
This is not desirable but changing it would be backwards incompatible if traits have default methods that take advantage of this bound:
#![allow(unused)] fn main() { trait NotQuiteMarker { fn dummy(&self) { let s = size_of_val(self); } } }
We need to decide how to handle this. Options are
- Just change it, breakage will be small (have to test that).
- Default to
=SizeOfValbut let users explicitly write=Pointeeif they want that. Bad because all traits will be incompatible with extern types. - Default to
=SizeOfValonly if defaulted methods are present. Bad because it's a backwards incompatible change to add a defaulted method now. - Default to
=Pointeebut addwhere Self: =SizeOfValimplicitly to defaulted methods. Now it's not backwards incompatible to add a new defaulted method, but it is backwards incompatible to change an existing method to have a default.
If we go with one of the latter options, Niko proposes that we should relax this in the next Edition (Rust 2026?) so that the default becomes Pointee (or maybe not even that, if we can).
Relaxing associated type bounds
Under the RFC, existing ?Sized bounds would be equivalent to =SizeOfVal. This is mostly fine but will cause problems in (at least) two specific cases: closure bounds and the Deref trait. For closures, we can adjust the bound since the associated type is unstable and due to the peculiarities of our Fn() -> T syntax. Failure to adjust the Deref bound in particular would prohibit the use of Rc<E> where E is an extern type, etc.
For deref bounds, David Wood is preparing a PR that simply changes the bound in a backwards incompatible way to assess breakage on crater. There is some chance the breakage will be small.
If the breakage proves problematic, or if we find other traits that need to be relaxed in a similar fashion, we do have the option of:
- In Rust 2024,
T: Derefbecomes equivalent toT: Deref<Target: SizeOfVal>unless written likeT: Deref<Target: =Pointee>. We add that annotation throughout stdlib. - In Rust 202X, we change the default, so that
T: Derefdoes not add any special bounds, and existing Rust 2024T: Derefis rewritten toT: Deref<Target: SizeOfVal>as needed.
Other notes
One topic that came up in discussion is that we may eventually wish to add a level "below" Pointee, perhaps Value, that signifies webassembly external values which cannot be pointed at. That is not currently under consideration but should be backwards compatible.