From 1bc6ae44014f953844a61123b7984f39b683ad78 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 13 Oct 2023 09:42:51 +0000 Subject: [PATCH] explicitly handle auto trait leakage in coherence --- .../src/solve/trait_goals.rs | 5 +-- .../src/traits/select/candidate_assembly.rs | 33 +++++++++++-------- ...tderr => auto-trait-coherence.next.stderr} | 2 +- .../auto-trait-coherence.old.stderr | 12 +++++++ ...{auto-trait.rs => auto-trait-coherence.rs} | 3 ++ 5 files changed, 38 insertions(+), 17 deletions(-) rename tests/ui/impl-trait/{auto-trait.stderr => auto-trait-coherence.next.stderr} (91%) create mode 100644 tests/ui/impl-trait/auto-trait-coherence.old.stderr rename tests/ui/impl-trait/{auto-trait.rs => auto-trait-coherence.rs} (90%) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8055c63b9f301..d87e05ad02f36 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -136,12 +136,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `assemble_candidates_after_normalizing_self_ty`, and we'd // just be registering an identical candidate here. // - // Returning `Err(NoSolution)` here is ok in `SolverMode::Coherence` - // since we'll always be registering an ambiguous candidate in + // We always return `Err(NoSolution)` here in `SolverMode::Coherence` + // since we'll always register an ambiguous candidate in // `assemble_candidates_after_normalizing_self_ty` due to normalizing // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { if matches!(goal.param_env.reveal(), Reveal::All) + || matches!(ecx.solver_mode(), SolverMode::Coherence) || opaque_ty .def_id .as_local() diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index bead8758ad604..f08cf6cef5b33 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -492,7 +492,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this trait and type. } ty::Param(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Placeholder(..) | ty::Bound(..) => { // In these cases, we don't know what the actual @@ -536,20 +536,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } - ty::Alias(_, _) - if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) => - { - // We do not generate an auto impl candidate for `impl Trait`s which already - // reference our auto trait. - // - // For example during candidate assembly for `impl Send: Send`, we don't have - // to look at the constituent types for this opaque types to figure out that this - // trivially holds. - // - // Note that this is only sound as projection candidates of opaque types - // are always applicable for auto traits. + ty::Alias(ty::Opaque, _) => { + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) { + // We do not generate an auto impl candidate for `impl Trait`s which already + // reference our auto trait. + // + // For example during candidate assembly for `impl Send: Send`, we don't have + // to look at the constituent types for this opaque types to figure out that this + // trivially holds. + // + // Note that this is only sound as projection candidates of opaque types + // are always applicable for auto traits. + } else if self.infcx.intercrate { + // We do not emit auto trait candidates for opaque types in coherence. + // Doing so can result in weird dependency cycles. + candidates.ambiguous = true; + } else { + candidates.vec.push(AutoImplCandidate) + } } - ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate), ty::Bool | ty::Char diff --git a/tests/ui/impl-trait/auto-trait.stderr b/tests/ui/impl-trait/auto-trait-coherence.next.stderr similarity index 91% rename from tests/ui/impl-trait/auto-trait.stderr rename to tests/ui/impl-trait/auto-trait-coherence.next.stderr index 81009413c9a26..7833ac688babf 100644 --- a/tests/ui/impl-trait/auto-trait.stderr +++ b/tests/ui/impl-trait/auto-trait-coherence.next.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D` - --> $DIR/auto-trait.rs:21:1 + --> $DIR/auto-trait-coherence.rs:24:1 | LL | impl AnotherTrait for T {} | -------------------------------- first implementation here diff --git a/tests/ui/impl-trait/auto-trait-coherence.old.stderr b/tests/ui/impl-trait/auto-trait-coherence.old.stderr new file mode 100644 index 0000000000000..7833ac688babf --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-coherence.old.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D` + --> $DIR/auto-trait-coherence.rs:24:1 + | +LL | impl AnotherTrait for T {} + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/auto-trait.rs b/tests/ui/impl-trait/auto-trait-coherence.rs similarity index 90% rename from tests/ui/impl-trait/auto-trait.rs rename to tests/ui/impl-trait/auto-trait-coherence.rs index 35994e4a5ba3f..a5cd01a87ffc9 100644 --- a/tests/ui/impl-trait/auto-trait.rs +++ b/tests/ui/impl-trait/auto-trait-coherence.rs @@ -1,3 +1,6 @@ +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + // Tests that type alias impls traits do not leak auto-traits for // the purposes of coherence checking #![feature(type_alias_impl_trait)]