generalization incorrectly handled higher-ranked aliases
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I've found an unsoundess bug in rustc with some LLM-driven analysis. As discussed on zulip (t-types/trait-system-refactor thread), @theemathas produced the minimization below; filing here at @lcnr's request since the underlying issue also affects stable.
I tried this code:
#![forbid(unsafe_code)]
struct Wrap<T>(T);
trait Id {
type Out;
}
impl<T> Id for T {
type Out = u16;
}
trait Probe {}
// impl Probe for &'_ fn(u16) {}
impl<'c> Probe for &'c Wrap<for<'a> fn(<&'a &'c u64 as Id>::Out)> {}
trait Indirect {}
// impl Indirect for &'_ fn(u16) {}
impl<P: Probe> Indirect for P {}
trait Mark {}
impl Mark for fn(u16) {}
trait Select {}
impl<X> Select for X
// where X = fn(u16)
where
for<'d> &'d Wrap<X>: Indirect,
{
}
// where Z = fn(u16)
impl<Z: Mark> Select for Z {}
I expected to see this happen: rejected with E0119
Instead, this happened: it compiles, on stable, nightly, and nightly with -Znext-solver.
Meta
stable: rustc 1.97.1 (8bab26f4f 2026-07-14)
nightly: rustc 1.100.0-nightly (8fa1c96cf 2026-08-17)
ICE variant (by @theemathas; stable + nightly + -Znext-solver)
#![forbid(unsafe_code)]
struct Wrap<T>(T);
trait Id {
type Out;
}
impl<T> Id for T {
type Out = u16;
}
trait Probe {}
impl<'c> Probe for &'c Wrap<for<'a> fn(<&'a &'c u64 as Id>::Out)> {}
trait Indirect {}
impl<P: Probe> Indirect for P {}
trait Mark {}
impl Mark for fn(u16) {}
trait Select {
type Assoc;
}
impl<X> Select for X
where
for<'d> &'d Wrap<X>: Indirect,
{
type Assoc = usize;
}
impl<Z: Mark> Select for Z {
type Assoc = &'static i32;
}
trait Same<U> {
fn convert(x: <Self as Select>::Assoc) -> <U as Select>::Assoc
where
Self: Select,
U: Select;
}
impl<T> Same<T> for T {
fn convert(x: <T as Select>::Assoc) -> <T as Select>::Assoc
where
Self: Select,
{
x
}
}
fn put<T>(x: usize) -> <T as Select>::Assoc
where
for<'a> &'a Wrap<T>: Indirect,
{
x
}
fn get<T>(x: <T as Select>::Assoc) -> &'static i32
where
T: Mark,
{
x
}
fn put_get<T, U>(x: usize) -> &'static i32
where
for<'a> &'a Wrap<T>: Indirect,
U: Mark,
T: Same<U>,
{
get::<U>(<T as Same<U>>::convert(put::<T>(x)))
}
fn foo<T, U>(x: usize) -> &'static i32
where
for<'a> &'a Wrap<T>: Indirect,
T: Mark,
{
put_get::<T, T>(x)
}
fn main() {
foo::<fn(u16), fn(u16)>(1_usize);
}
error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:201:13:
Failed to normalize Alias(AliasTy { args: [Binder { value: fn(u16), bound_vars: [] }],
kind: Projection { def_id: DefId(... Select::Assoc) }, .. }) in typing_env=... PostAnalysis ...
Original -Znext-solver soundness reproducer (rejected E0284 by the old solver; accepted by -Znext-solver; compiled program will segfault)
#![forbid(unsafe_code)]
trait Overlap {
type T;
}
impl<S, V> Overlap for S
where
S: Select<Pick = V>,
for<'d> &'d [V]: Indirect,
{
type T = usize;
}
impl Overlap for fn(u16) {
type T = &'static u8;
}
trait Id {
type Out;
}
impl<T> Id for T {
type Out = u16;
}
trait Probe {}
impl<'c> Probe for &'c [for<'a> fn(<&'a &'c u8 as Id>::Out)] {}
trait Indirect {}
impl<P: Probe> Indirect for P {}
trait Select {
type Pick;
}
impl<X> Select for X
where
for<'d> &'d [X]: Indirect,
{
type Pick = X;
}
impl<Z: Copy> Select for Z {
type Pick = u8;
}
fn g<X>() -> <X as Overlap>::T
where
for<'d> &'d [X]: Indirect,
{
1usize
}
fn main() {
println!("{}", *g::<fn(u16)>());
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the minimized reproducer on stable, nightly, and nightly with -Znext-solver, then compare the reported acceptance with the expected E0119 rejection. Use the trait and higher-ranked alias interactions in the reproducer as the entry point; done means the unsound example is rejected without the reported ICE or accepted compilation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100