Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ where
| ty::Placeholder(..)
| ty::Alias(ty::IsRigid::No, _)
| ty::Bound(..)
| ty::Infer(_) => {
| ty::Infer(_)
| ty::Alias(ty::IsRigid::Yes, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
panic!("unexpected type `{ty:?}`")
}

Expand Down Expand Up @@ -106,15 +107,6 @@ where
.map(Unnormalized::skip_norm_wip)
.collect(),
)),

ty::Alias(ty::IsRigid::Yes, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
Ok(ty::Binder::dummy(vec![
cx.type_of(def_id.into()).instantiate(cx, args).skip_norm_wip(),
]))
}
}
}

Expand Down
58 changes: 48 additions & 10 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,19 +236,11 @@ where
// when merging candidates anyways.
//
// See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
if let ty::Alias(is_rigid, ty::AliasTy { kind: ty::Opaque { def_id }, .. }) =
if let ty::Alias(is_rigid, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) =
Comment thread
bit-aloo marked this conversation as resolved.
goal.predicate.self_ty().kind()
{
debug_assert!(is_rigid == ty::IsRigid::Yes);

for item_bound in cx.item_self_bounds(def_id.into()).skip_binder() {
if item_bound
.as_trait_clause()
.is_some_and(|b| b.def_id() == goal.predicate.def_id())
{
return Err(NoSolution.into());
}
}
return ecx.consider_auto_trait_candidate_for_opaque_ty(goal, def_id, args);
}

// We need to make sure to stall any coroutines we are inferring to avoid query cycles.
Expand Down Expand Up @@ -1286,6 +1278,52 @@ where
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
}

fn consider_auto_trait_candidate_for_opaque_ty(
&mut self,
goal: Goal<I, TraitClause<I>>,
def_id: I::OpaqueTyId,
args: I::GenericArgs,
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
let cx = self.cx();
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
if self.opaque_accesses.might_rerun() {
match self.opaque_accesses.rerun_always(RerunReason::AutoTraitLeakage)? {}
}

for item_bound in cx.item_self_bounds(def_id.into()).skip_binder() {
if item_bound.as_trait_clause().is_some_and(|b| b.def_id() == goal.predicate.def_id()) {
return Err(NoSolution.into());
}
}

let candidate = self.probe_trait_candidate(source).enter(|ecx| {
let hidden_ty = cx.type_of(def_id.into()).instantiate(cx, args).skip_norm_wip();
ecx.add_goal(
GoalSource::ImplWhereBound,
goal.with(cx, goal.predicate.with_replaced_self_ty(cx, hidden_ty)),
)?;
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
});

let opaque_types_may_leak = match self.typing_mode() {
TypingMode::PostTypeckUntilBorrowck { .. } => false,
TypingMode::Coherence
| TypingMode::Typeck { .. }
| TypingMode::PostBorrowck { .. }
| TypingMode::Reflection
| TypingMode::PostAnalysis
| TypingMode::Codegen
| TypingMode::ErasedNotCoherence(MayBeErased) => true,
};

match candidate {
Ok(candidate) if has_only_region_constraints(candidate.result) => Ok(candidate),
Ok(candidate) if !opaque_types_may_leak => Ok(candidate),
Ok(_) => self.forced_ambiguity(MaybeInfo::AMBIGUOUS),
Err(err) => Err(err),
}
}

// Return `Some` if there is an impl (built-in or user provided) that may
// hold for the self type of the goal, which for coherence and soundness
// purposes must disqualify the built-in auto impl assembled by considering
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pub struct WaddupGamers<T, U>(Option<T>, U);

impl<T: Leak<Assoc = U>, U> Unpin for WaddupGamers<T, U> {}

pub trait Leak {
type Assoc;
}

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

pub fn define<T>() -> impl Sized {
WaddupGamers(None::<T>, || ())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//@ ignore-compare-mode-next-solver
//@ compile-flags: -Znext-solver
//@ aux-build:opaque-auto-trait-leakage.rs

Comment thread
lcnr marked this conversation as resolved.
//! Regression test for https://github.com/rust-lang/rust/issues/134578.
//! Leaking the auto traits of a foreign opaque must not constrain inference
//! variables in the caller, as that would leak the hidden type itself. Here
//! that would constrain `NameMe<T>` to a closure from the auxiliary crate and
//! ICE in typeck. The hidden type may still show up in the diagnostic.

#![feature(type_alias_impl_trait)]
#![allow(unused)]

extern crate opaque_auto_trait_leakage as dep;

use dep::*;

fn require_auto<T: Unpin>(x: T) -> T {
x
}

type NameMe<T> = impl Sized;

#[define_opaque(NameMe)]
fn leak<T>() -> NameMe<T>
where
T: Leak<Assoc = NameMe<T>>,
{
// Proving `impl Sized: Unpin` must not constrain `NameMe<T>`
// to the foreign closure hidden inside `define`.
let opaque = require_auto(define::<T>());
//~^ ERROR type mismatch resolving `<T as Leak>::Assoc == {closure@define<T>::{closure#0}}`
let closure;
loop {}
return closure;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error[E0271]: type mismatch resolving `<T as Leak>::Assoc == {closure@define<T>::{closure#0}}`
--> $DIR/opaque-hidden-ty-inference.rs:31:31
|
LL | let opaque = require_auto(define::<T>());
| ------------ ^^^^^^^^^^^^^ expected closure, found `!`
| |
| required by a bound introduced by this call
|
::: $DIR/auxiliary/opaque-auto-trait-leakage.rs:14:29
|
LL | WaddupGamers(None::<T>, || ())
| -- the expected closure
|
= note: expected closure `{closure@dep::define<T>::{closure#0}}`
found type `!`
= note: required for `WaddupGamers<T, {closure@dep::define<T>::{closure#0}}>` to implement `Unpin`
note: required because it appears within the type `impl Sized`
--> $DIR/auxiliary/opaque-auto-trait-leakage.rs:13:23
|
LL | pub fn define<T>() -> impl Sized {
| ^^^^^^^^^^
note: required by a bound in `require_auto`
--> $DIR/opaque-hidden-ty-inference.rs:18:20
|
LL | fn require_auto<T: Unpin>(x: T) -> T {
| ^^^^^ required by this bound in `require_auto`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0271`.
Loading