Skip to content

Bounded Trait Casting#155624

Draft
DiamondLovesYou wants to merge 1 commit intorust-lang:mainfrom
DiamondLovesYou:trait-casting
Draft

Bounded Trait Casting#155624
DiamondLovesYou wants to merge 1 commit intorust-lang:mainfrom
DiamondLovesYou:trait-casting

Conversation

@DiamondLovesYou
Copy link
Copy Markdown
Contributor

Summary

This PR implements the compiler- and library-side plumbing for the bounded trait casting proposal in rust-lang/rfcs#3952. It adds a mechanism for casting between dyn Trait objects that share an explicitly-declared common root supertrait, resolved at runtime in O(1) via a per-root metadata table — no 'static bound, no TypeId, and no global registry.

Surface

#![feature(trait_cast)]
use core::marker::TraitMetadataTable;

trait Animal: TraitMetadataTable<dyn Animal> {}  // declares `Animal` as a cast root
trait Dog: Animal { fn bark(&self); }

fn maybe_bark(a: &dyn Animal) {
    if let Ok(d) = core::cast!(in dyn Animal, a => dyn Dog) {
        d.bark();
    }
}

A trait becomes a cast root by naming TraitMetadataTable<dyn Self> as a supertrait. Every subtrait of a root inherits the TraitMetadataTable<dyn Root> bound and is eligible as a cast target within that root's graph. core::cast!, core::try_cast!, and core::unchecked_cast! macros (in a new core::trait_cast module) dispatch through the TraitCast<I, U> trait implemented for &T, &mut T, Box<T>, Rc<T>, and Arc<T>.

Runtime cost per cast: two loads and a branch against the table for the root's graph.

Library additions (core/alloc)

  • core::marker::TraitMetadataTable<SuperTrait> — the marker/lang-item that declares a cast root; blanket impl for all Sized types (the actual root-supertrait obligation is enforced by the supertrait relationship itself, not the where-clauses, to break a cycle through Unsize).
  • core::trait_castTraitCast/TraitCastError and the cast! / try_cast! / unchecked_cast! macros.
  • alloc::{boxed, rc, sync} — owned-cast impls.
  • New intrinsics in core::intrinsics:
    • trait_metadata_index<SuperTrait, Trait>() -> (&'static u8, usize)
    • trait_metadata_table<SuperTrait, ConcreteType>() -> (&'static u8, NonNull<Option<NonNull<()>>>)
    • trait_metadata_table_len<SuperTrait>() -> usize
    • trait_cast_is_lifetime_erasure_safe<SuperTrait, TargetTrait>() -> bool

The &'static u8 returned alongside each index/table pointer is a per-global-crate sentinel used to detect the ForeignTraitGraph case when two independently-built artifacts are linked into one binary.

Compiler additions

New passes / modules (all under rustc_monomorphize unless noted):

  • trait_graph.rs — per-root TraitGraph built from gathered trait_metadata_index / trait_metadata_table requests.
  • table_layout.rs — assigns slots for (sub_trait, outlives_class) pairs with condensation (BitMatrix row-grouping) to collapse classes admitting identical impl sets.
  • erasure_safe.rs — resolves trait_cast_is_lifetime_erasure_safe by DFS-walking binder vars of the target dyn type and checking each is expressible through the root's binder.
  • cast_sensitivity.rs — SCC-based batch computation of per-Instance CastRelevantLifetimes (direct + transitive via call-graph).
  • resolved_bodies.rs, trait_cast_requests.rs — request gathering and delayed-codegen queue.
  • partitioning.rs — cascade-canonicalization of augmented callees so sensitive subgraphs are emitted once per signature group.

MIR: TerminatorKind::{Call, TailCall} grows a call_id: &'tcx List<(DefId, u32, GenericArgsRef<'tcx>)> recording the full inlining chain. TerminatorKind size assertion goes from 80 → 88. Before inlining each list has length 1; the inliner prepends the caller's chain to each inlined callee's.

Borrowck: new region_summary.rs publishes a
BorrowckRegionSummary per fn (walk-position → RegionVid, call-site region mappings keyed on the u32 counter) consumed by the sensitivity pass after typeck but before mono.

Generic args: new GenericArgKind::Outlives(OutlivesArg) variant (tag 0b11) carrying (longer, shorter) region-index pairs. Appended to an Instance's args when a sensitive callee must be specialized for a given caller's outlives environment. Wired through interning, encode/decode, folding/visiting, symbol mangling, and all the usual suspects.

New lang item: TraitMetadataTable (sym::trait_metadata_table).

HIR analysis (wfcheck.rs, dyn_trait.rs): eagerly diagnoses at trait-definition time when a root-connected trait introduces a lifetime not expressible through the root (would be manufactured at downcast time — unsound).

Diagnostics

  • UNUSED_CAST_TARGET lint — cast to a target no concrete type in the final binary implements (always Err at runtime).
  • trait graph rooted at {root} is not downcast-safe — erased-lifetime manufacturability check.
  • TraitMetadataTable type argument must be a trait object — non-dyn T arg.
  • TraitMetadataTable type argument does not match a cast rootdyn X where X isn't Self or a transitive cast-root supertrait.
  • cast target not reachable in graph / non-dyn-compat target / tmt-arg-* — various ill-formed roots and targets.

Debugging / inspection flags

All -Z, all dump to stderr:

  • -Z dump-trait-graph[=FILTER], -Z dump-trait-cast-sensitivity[=FILTER], -Z dump-trait-cast-augmentation[=FILTER], -Z dump-trait-cast-canonicalization, -Z dump-trait-cast-chain-composition[=FILTER], -Z dump-trait-cast-erasure-safety[=FILTER]
  • -Z print-trait-cast-stats

Each has a matching tests/run-make/dump-* test.

Rustc Perf

Perf was evaluated with rustc-perf and the impact on crates that do not use trait casting (as-in, all of them) was found to be minimal. The mono-level SCC + Floyd-Warshall pass only runs over directly- and transitively-sensitive call graphs and stops at the ground-level caller, so crates with no cast graph pay effectively nothing. Perf is from slightly better to neutral on average across rustc-perf, with modest rmeta bloat at ~2.5% for typical crates.

Known caveats for review

  • Heavy trait-casting usage has not yet been benched as no suitable public crates exist yet.

Not in this PR

  • Stabilization / rustc_deny_explicit_impl on TraitMetadataTable.
  • cast! on Pin<P> or user smart pointers.
  • rustdoc surfacing of cast graphs.

## Summary

This PR implements the compiler- and library-side plumbing for the **bounded intertrait casting** proposal in rust-lang/rfcs#3952. It adds a mechanism for casting between `dyn Trait` objects that share an explicitly-declared common root supertrait, resolved at runtime in `O(1)` via a per-root metadata table — no `'static` bound, no `TypeId`, and no global registry.

## Surface

```rust
#![feature(trait_cast)]
use core::marker::TraitMetadataTable;

trait Animal: TraitMetadataTable<dyn Animal> {}  // declares `Animal` as a cast root
trait Dog: Animal { fn bark(&self); }

fn maybe_bark(a: &dyn Animal) {
    if let Ok(d) = core::cast!(in dyn Animal, a => dyn Dog) {
        d.bark();
    }
}
```

A trait becomes a **cast root** by naming `TraitMetadataTable<dyn Self>` as a supertrait. Every subtrait of a root inherits the `TraitMetadataTable<dyn Root>` bound and is eligible as a cast target within that root's graph. `core::cast!`, `core::try_cast!`, and `core::unchecked_cast!` macros (in a new `core::trait_cast` module) dispatch through the `TraitCast<I, U>` trait implemented for `&T`, `&mut T`, `Box<T>`, `Rc<T>`, and `Arc<T>`.

Runtime cost per cast: two loads and a branch against the table for the root's graph.

## Library additions (`core`/`alloc`)

- `core::marker::TraitMetadataTable<SuperTrait>` — the marker/lang-item that declares a cast root; blanket impl for all `Sized` types (the actual root-supertrait obligation is enforced by the supertrait relationship itself, not the where-clauses, to break a cycle through `Unsize`).
- `core::trait_cast` — `TraitCast`/`TraitCastError` and the `cast!` / `try_cast!` / `unchecked_cast!` macros.
- `alloc::{boxed, rc, sync}` — owned-cast impls.
- New intrinsics in `core::intrinsics`:
  - `trait_metadata_index<SuperTrait, Trait>() -> (&'static u8, usize)`
  - `trait_metadata_table<SuperTrait, ConcreteType>() -> (&'static u8, NonNull<Option<NonNull<()>>>)`
  - `trait_metadata_table_len<SuperTrait>() -> usize`
  - `trait_cast_is_lifetime_erasure_safe<SuperTrait, TargetTrait>() -> bool`

The `&'static u8` returned alongside each index/table pointer is a per-global-crate sentinel used to detect the `ForeignTraitGraph` case when two independently-built artifacts are linked into one binary.

## Compiler additions

**New passes / modules** (all under `rustc_monomorphize` unless noted):

- `trait_graph.rs` — per-root `TraitGraph` built from gathered `trait_metadata_index` / `trait_metadata_table` requests.
- `table_layout.rs` — assigns slots for `(sub_trait, outlives_class)` pairs with condensation (`BitMatrix` row-grouping) to collapse classes admitting identical impl sets.
- `erasure_safe.rs` — resolves `trait_cast_is_lifetime_erasure_safe` by DFS-walking binder vars of the target dyn type and checking each is expressible through the root's binder.
- `cast_sensitivity.rs` — SCC-based batch computation of per-`Instance` `CastRelevantLifetimes` (direct + transitive via call-graph).
- `resolved_bodies.rs`, `trait_cast_requests.rs` — request gathering and delayed-codegen queue.
- `partitioning.rs` — cascade-canonicalization of augmented callees so sensitive subgraphs are emitted once per signature group.

**MIR**: `TerminatorKind::{Call, TailCall}` grows a `call_id: &'tcx List<(DefId, u32, GenericArgsRef<'tcx>)>` recording the full inlining chain. `TerminatorKind` size assertion goes from 80 → 88. Before inlining each list has length 1; the inliner prepends the caller's chain to each inlined callee's.

**Borrowck**: new `region_summary.rs` publishes a
`BorrowckRegionSummary` per fn (walk-position → `RegionVid`, call-site region mappings keyed on the `u32` counter) consumed by the sensitivity pass after typeck but before mono.

**Generic args**: new `GenericArgKind::Outlives(OutlivesArg)` variant (tag `0b11`) carrying `(longer, shorter)` region-index pairs. Appended to an `Instance`'s args when a sensitive callee must be specialized for a given caller's outlives environment. Wired through interning, encode/decode, folding/visiting, symbol mangling, and all the usual suspects.

**New lang item**: `TraitMetadataTable` (`sym::trait_metadata_table`).

**HIR analysis** (`wfcheck.rs`, `dyn_trait.rs`): eagerly diagnoses at trait-definition time when a root-connected trait introduces a lifetime not expressible through the root (would be manufactured at downcast time — unsound).

## Diagnostics

- `UNUSED_CAST_TARGET` lint — cast to a target no concrete type in the final binary implements (always `Err` at runtime).
- `trait graph rooted at {root} is not downcast-safe` — erased-lifetime manufacturability check.
- `TraitMetadataTable type argument must be a trait object` — non-`dyn T` arg.
- `TraitMetadataTable type argument does not match a cast root` — `dyn X` where `X` isn't `Self` or a transitive cast-root supertrait.
- `cast target not reachable in graph` / `non-dyn-compat target` / `tmt-arg-*` — various ill-formed roots and targets.

## Debugging / inspection flags

All `-Z`, all dump to stderr:

- `-Z dump-trait-graph[=FILTER]`, `-Z dump-trait-cast-sensitivity[=FILTER]`, `-Z dump-trait-cast-augmentation[=FILTER]`, `-Z dump-trait-cast-canonicalization`, `-Z dump-trait-cast-chain-composition[=FILTER]`, `-Z dump-trait-cast-erasure-safety[=FILTER]`
- `-Z print-trait-cast-stats`

Each has a matching `tests/run-make/dump-*` test.

## Known caveats for review

- Perf was evaluated with rustc-perf and the impact on crates that do not use trait casting was found to be minimal. The SCC + Floyd-Warshall pass only runs over directly- and transitively-sensitive call graphs and stops at the ground-level caller, so crates with no cast graph pay effectively nothing. Heavy trait-casting usage has not yet been benched as no suitable public crates exist yet.

## Not in this PR

- Stabilization / `rustc_deny_explicit_impl` on `TraitMetadataTable`.
- `cast!` on `Pin<P>` or user smart pointers.
- `rustdoc` surfacing of cast graphs.
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 21, 2026

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred in compiler/rustc_sanitizers

cc @rcvalle

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

These commits modify the Cargo.lock file. Unintentional changes to Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred in need_type_info.rs

cc @lcnr

HIR ty lowering was modified

cc @fmease

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred in coverage instrumentation.

cc @Zalathar

This PR changes rustc_public

cc @oli-obk, @celinval, @ouz-a, @makai410

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

This PR changes MIR

cc @oli-obk, @RalfJung, @JakobDegen, @vakaras

Some changes occurred in match lowering

cc @Nadrieril

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs PG-exploit-mitigations Project group: Exploit mitigations S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 21, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 21, 2026

r? @jieyouxu

rustbot has assigned @jieyouxu.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 72 candidates
  • Random selection from 18 candidates

@rustbot rustbot added T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Apr 21, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 21, 2026

⚠️ Warning ⚠️

  • There are issue links (such as #123) in the commit messages of the following commits.
    Please move them to the PR description, to avoid spamming the issues with references to the commit, and so this bot can automatically canonicalize them to avoid issues with subtree.

@rust-log-analyzer
Copy link
Copy Markdown
Collaborator

The job x86_64-gnu-gcc failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
---- [run-make] tests/run-make/dump-trait-cast-augmentation stdout ----

error: rmake recipe failed to complete
status: exit status: 101
command: cd "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-make/dump-trait-cast-augmentation/rmake_out" && env -u RUSTFLAGS -u __RUSTC_DEBUG_ASSERTIONS_ENABLED -u __STD_DEBUG_ASSERTIONS_ENABLED -u __STD_REMAP_DEBUGINFO_ENABLED AR="ar" BUILD_ROOT="/checkout/obj/build/x86_64-unknown-linux-gnu" CC="cc" CC_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC -m64" CXX="c++" CXX_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC -m64" HOST_RUSTC_DYLIB_PATH="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" LD_LIBRARY_PATH="/checkout/obj/build/x86_64-unknown-linux-gnu/bootstrap-tools/x86_64-unknown-linux-gnu/release/deps:/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/lib/rustlib/x86_64-unknown-linux-gnu/lib" LD_LIB_PATH_ENVVAR="LD_LIBRARY_PATH" LLVM_BIN_DIR="/checkout/obj/build/x86_64-unknown-linux-gnu/ci-llvm/bin" LLVM_COMPONENTS="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassembler aarch64info aarch64utils abi aggressiveinstcombine all all-targets amdgpu amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler amdgpuinfo amdgputargetmca amdgpuutils analysis arm armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser asmprinter avr avrasmparser avrcodegen avrdesc avrdisassembler avrinfo binaryformat bitreader bitstreamreader bitwriter bpf bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo cas cfguard cgdata codegen codegentypes core coroutines coverage csky cskyasmparser cskycodegen cskydesc cskydisassembler cskyinfo debuginfobtf debuginfocodeview debuginfodwarf debuginfodwarflowlevel debuginfogsym debuginfologicalview debuginfomsf debuginfopdb demangle dlltooldriver dtlto dwarfcfichecker dwarflinker dwarflinkerclassic dwarflinkerparallel dwp engine executionengine extensions filecheck frontendatomic frontenddirective frontenddriver frontendhlsl frontendoffloading frontendopenacc frontendopenmp fuzzercli fuzzmutate globalisel hexagon hexagonasmparser hexagoncodegen hexagondesc hexagondisassembler hexagoninfo hipstdpar instcombine instrumentation interfacestub interpreter ipo irprinter irreader jitlink libdriver lineeditor linker loongarch loongarchasmparser loongarchcodegen loongarchdesc loongarchdisassembler loongarchinfo lto m68k m68kasmparser m68kcodegen m68kdesc m68kdisassembler m68kinfo mc mca mcdisassembler mcjit mcparser mips mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo mirparser msp430 msp430asmparser msp430codegen msp430desc msp430disassembler msp430info native nativecodegen nvptx nvptxcodegen nvptxdesc nvptxinfo objcarcopts objcopy object objectyaml option orcdebugging orcjit orcshared orctargetprocess passes plugins powerpc powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo profiledata remarks riscv riscvasmparser riscvcodegen riscvdesc riscvdisassembler riscvinfo riscvtargetmca runtimedyld sandboxir scalaropts selectiondag sparc sparcasmparser sparccodegen sparcdesc sparcdisassembler sparcinfo support supportlsp symbolize systemz systemzasmparser systemzcodegen systemzdesc systemzdisassembler systemzinfo tablegen target targetparser telemetry textapi textapibinaryreader transformutils vectorize webassembly webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo webassemblyutils windowsdriver windowsmanifest x86 x86asmparser x86codegen x86desc x86disassembler x86info x86targetmca xray xtensa xtensaasmparser xtensacodegen xtensadesc xtensadisassembler xtensainfo" LLVM_FILECHECK="/checkout/obj/build/x86_64-unknown-linux-gnu/ci-llvm/bin/FileCheck" PYTHON="/usr/bin/python3" RUSTC="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" RUSTDOC="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustdoc" SOURCE_ROOT="/checkout" TARGET="x86_64-unknown-linux-gnu" TARGET_EXE_DYLIB_PATH="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" __BOOTSTRAP_JOBS="4" __RMAKE_VERBOSE_SUBPROCESS_OUTPUT="1" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-make/dump-trait-cast-augmentation/rmake"
stdout: none
--- stderr -------------------------------
LD_LIBRARY_PATH="/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-make/dump-trait-cast-augmentation/rmake_out:/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib:/checkout/obj/build/x86_64-unknown-linux-gnu/bootstrap-tools/x86_64-unknown-linux-gnu/release/deps:/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-make/dump-trait-cast-augmentation/rmake_out" "test.rs" "-Zdump-trait-cast-augmentation=all" "--target=x86_64-unknown-linux-gnu"
output status: `exit status: 0`
=== STDOUT ===



=== STDERR ===
=== Augmentation: <&dyn GraphRoot as std::trait_cast::TraitCast<dyn GraphRoot, dyn GraphSubA>>::cast ->
                  <&dyn GraphRoot as std::trait_cast::TraitCast<dyn GraphRoot, dyn GraphSubA>>::checked_cast ===

For more information how to resolve CI failures of this job, visit this link.

@jieyouxu
Copy link
Copy Markdown
Member

AFAIK this is a PoC for the RFC, removing my assignment.

@jieyouxu jieyouxu removed their assignment Apr 21, 2026
@Kivooeo
Copy link
Copy Markdown
Member

Kivooeo commented Apr 22, 2026

Hi,

Two things before any code review happens on this:

  1. RFC isn't accepted. The RFC is still under discussion and hasn't entered FCP. Opening a 16k-lines impl PR two days after creating the RFC inverts the standard process -- RFC discussion exists precisely to settle design before implementation time get spent, and design changes during that discussion are very likely given the scope. Work landed ahead of acceptance tends to be work done twice.
  2. Scope. Even if the RFC lands exactly as written, this PR touches parts of compiler that are normally reviewed by different teams. A new GenericArgKind, a post-monomorphization global phase with cross-crate DelayedInstance rmeta exchange, call_id chain in MIR, and much more even including a lot library/ changes which is completely different team with different processes, API changes must go through ACP and acceptance from libs-api.

A single 16k-lines PR is not a reviewable unit for changes that cross a lot of different boundaries

Please, consider closing this PR (or convert to draft). Once the RFC is accepted, land the work as a stacked series of focused PRs -- each small enough that a single reviewer can handle at a time.

A diff of this size landed as one commit is not something anyone, author included, can meaningfully (self-)review before submitting -- which means the entire burden of catching issues falls on reviewers from the first pass onward. This is exactly the situation our burdensome policy was written for. Splitting the work into reviewable pieces ins't just a process preference here, it's the minimum baseline for the time reviewers can reasonably be asked to commit.

@jieyouxu jieyouxu marked this pull request as draft April 22, 2026 01:31
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 22, 2026
@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Apr 22, 2026

☔ The latest upstream changes (presumably #155392) made this pull request unmergeable. Please resolve the merge conflicts.

@apiraino
Copy link
Copy Markdown
Contributor

apiraino commented Apr 22, 2026

@DiamondLovesYou Hi, this is the moderation team of the Rust project. As @Kivooeo says, please understand the burden you're giving on the Rust project by subtmitting a patch of more than 16K lines of code.

Please take some time to get yourself familiar with our contribution guidelines, specifically our etiquette.

If you need further support on how to contribute to the Rust project, feel free to either reach out to us on Zulip.

@DiamondLovesYou
Copy link
Copy Markdown
Contributor Author

DiamondLovesYou commented Apr 23, 2026

@apiraino With my sincerest apologies, I must insist. Contribution guidelines notwithstanding, this PR is not a draft, and has been engineered in whole to support trait-casting. It is large, yes, and I'm fully aware of the gravity of reviewing such a large diff, but also: there is no rush. To be blunt: there is not much "wiggle room" left that I have not already explored - the RFC, while not technically accepted yet, is a desired feature and cannot practically change much in substance between now and acceptance.

@jackh726
Copy link
Copy Markdown
Member

Hey @DiamondLovesYou

Just wanted to chime here. First, I want to say: I appreciate your enthusiasm about this feature. The RFC seems quite comprehensive and having a reference implementation can sometimes be helpful for this type of feature.

That being said, I want to give you a heads-up that this PR as-is will almost certainly never get assigned a reviewer. It's simply too large. Moreover, even the RFC likely is "too much" to get merged.

If you want to get this moved forward, I would suggest chatting on Zulip. As you said, this intersects a lot of teams, so it's probably good to start building up from the foundations.

If I were in your position, this is roughly the order that I would take it:

  • Start with t-lang, discuss the problem trying to be solved. And a "high-level" idea of a potential solution. Get general positive vibes.
  • Discuss with t-types about implementation details and feasibility. This will need a dedicated reviewer from the team. I'll note that it also looks similar to other specialization-like things we have in-progress (i.e. try_as_dyn and "maybe specialization"), so be prepared to answer questions about how/why this is different.
  • Once you have an idea that this is feasible and there is sufficient interest and review capacity on this, go back to t-lang and get approval for a lang experiment
  • If a lang experiment is approved, then you would want to take this implementation and break it into smaller pieces
    • For example, you could land just a feature gate to start. But there are likely many opportunities to split this.
  • After all the implementation is in, the lang team will likely want some time before approving the RFC itself.

Again, I'm not trying to discourage you or say that you can't do these things. But I am saying that it's not just that there is "no rush" about getting this reviewed - it is simply not the process that we use to get features of this size into the compiler. Even RFCs for this size of feature today will likely not get merged without significant prior discussion and experimentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs PG-exploit-mitigations Project group: Exploit mitigations S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants