Skip to content

-Znext-solver: fix opaque type implied bounds unsoundness - #160425

Closed
lcnr wants to merge 1 commit into
rust-lang:mainfrom
lcnr:fix-implied-bounds
Closed

-Znext-solver: fix opaque type implied bounds unsoundness#160425
lcnr wants to merge 1 commit into
rust-lang:mainfrom
lcnr:fix-implied-bounds

Conversation

@lcnr

@lcnr lcnr commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This fixes rust-lang/trait-system-refactor-initiative#159 for RPIT and RPITIT. It does not fix the issue for TAIT and RTN, this is blocked on the proper fix as implemented in #152051. This is sufficient to unblock the stabilization of the new trait solver.

The core idea is to explicitly mark in the signature as rigid, even if we're in their defining scope. With RPITIT we can also get opaque types in the ParamEnv via Projection(synthetic_assoc_ty, opaque_ty) clauses. We also need to mark the opaque_ty from these as rigid. We do this by manually modifying the ParamEnv used by normalization and implied bounds computation.

This is very similar to actually being outside of the defining scope as we never try to renormalize rigid aliases. However, reasoning about its correctness is quite subtle!

On stable, the only place where we encounter opaque types is in the return type of methods. Either directly, or hidden behind the synthetic assoc type for RPITIT. There is no way you get an opaque type into a function signature without it being in the ParamEnv or the signature itself. This isn't actually correct. We can get opaque types via item bounds of other opaques

use std::any::Any;

trait Trait {
    type Assoc;
}

impl<T> Trait for T {
    type Assoc = T;
}

struct Project<T: Trait, U = <T as Trait>::Assoc>(T, U);
struct Outlives<T: 'static>(Option<T>);
fn foo<T>(x: T) -> (Box<dyn Any>, Project<impl Trait<Assoc = impl Sized>>) {
    (Box::new(x), Project(Outlives::<T>(None), Outlives::<T>(None)))
}

fn main() {
    let any = foo(String::from("temporary").as_str()).0;
    println!("{}", any.downcast_ref::<&str>().unwrap());
}

We could get implied bounds using opaques from the signature of a closure. However, closure signatures are already fully normalized so it doesn't reference any potentially normalizeable opaque types directly.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Aug 3, 2026
@lcnr
lcnr force-pushed the fix-implied-bounds branch from ef7abd9 to 253845d Compare August 3, 2026 09:57
@rust-log-analyzer

This comment has been minimized.

@lcnr
lcnr force-pushed the fix-implied-bounds branch from 253845d to 99d2b02 Compare August 3, 2026 10:05
@rust-log-analyzer

This comment has been minimized.

@lcnr

lcnr commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

proper fix in #160443

@lcnr lcnr closed this Aug 4, 2026
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-compiler Relevant to the compiler 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.

normalizing opaques while computing implied bounds

3 participants