diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 126bffb720dbc..2f56056449779 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -164,13 +164,16 @@ where // this is the defining scope, and otherwise treat it as rigid. // However, in `ErasedNotcoherence` we *always* treat it as rigid. // This is the same as other modes if def_id is None, but wrong if we do have a DefId. - // So, if we have one, we register in the EvalCtxt that we may need that defid. - // We might then decide to rerun in the correct typing mode. - if let Some(def_id) = def_id.as_local() { - self.opaque_accesses.rerun_if_opaque_in_opaque_type_storage( - RerunReason::NormalizeOpaqueType, - def_id, - )?; + // Thus we should rerun if the opaque is in the defining scope. And we should do + // so immediately, otherwise we might continue evaluating with rigid opaques that + // should be revealed and trigger query cycle when leaking it for auto trait. + // See `tests/ui/traits/next-solver/normalize/always-rerun-normalizing-opaques.rs`. + // + // FIXME: verify that we can get away with not rerunning immediately when + // normalizing foreign opaques. Currently we don't do so because that would greatly + // worsen the compilation time of `wg-grammar`. + if def_id.as_local().is_some() { + match self.opaque_accesses.rerun_always(RerunReason::NormalizeOpaqueType)? {} } else { self.opaque_accesses .rerun_if_in_post_analysis(RerunReason::NormalizeOpaqueTypeRemoteCrate)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 902ad882f2123..51ec0bcbf5ec2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -240,9 +240,6 @@ where goal.predicate.self_ty().kind() { debug_assert!(is_rigid == ty::IsRigid::Yes); - if ecx.opaque_accesses.might_rerun() { - match ecx.opaque_accesses.rerun_always(RerunReason::AutoTraitLeakage)? {} - } for item_bound in cx.item_self_bounds(def_id.into()).skip_binder() { if item_bound diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 8e0fe21b46c65..31fe3cf99d88c 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -154,6 +154,10 @@ pub enum TypingMode { /// we bail out, setting a field on `EvalCtxt` that indicates the canonicalization must be /// rerun in the original typing mode. /// + /// Specifically, we always reveal auto traits for rigid aliases and thus we don't allow + /// incorrectly marked rigid local opaques. We ensure this by immediately bailing out + /// when normalizing local opaques. + /// /// `TypingMode::Coherence` is not replaced by this and is always kept as-is. ErasedNotCoherence(S), } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index abedc4d079e37..248ba00348749 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -118,6 +118,10 @@ impl AliasTyKind { /// if the param env is the same, e.g., `Typeck/PostTypeckUntilBorrowck` and /// `PostAnalysis/Codegen`. /// +/// We always reveal auto traits for rigid aliases and this can cause query cycle in +/// `TypingMode::ErasedNotCoherence`. Thus we don't allow incorrectly marked rigid local +/// opaques. We achieve this by immediately bailing out when normalizing local opaques. +/// /// FIXME(#155345): Alias handling is currently still in flux for the new trait /// solver and this is currently somewhat messy. Please reach out on /// #t-types/trait-system-refactor-initiative if you encounter this and it isn't diff --git a/tests/ui/traits/next-solver/normalize/always_rerun_normalizing_opaques.rs b/tests/ui/traits/next-solver/normalize/always_rerun_normalizing_opaques.rs new file mode 100644 index 0000000000000..46387fa6f2bb6 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/always_rerun_normalizing_opaques.rs @@ -0,0 +1,29 @@ +//@ edition: 2024 +//@ compile-flags: -Znext-solver +//@ check-pass + +// Previously we update the rerun flag when we normalize opaques and don't immedidately bail. +// We normalize goals when adding them which is separate from their evaluation. +// So we don't have the `might_rerun` flag when evaluating them. +// This leads to query cycle in code where we need to leak opaque types for auto traits. + +fn is_send(_: T) {} + +fn inner() -> impl Sized { + is_send(outer()); +} + +fn outer() -> impl Sized { + inner() +} + +// From #135062 which was fixed but broken again. +async fn foo() { + is_send(bar()) +} + +async fn bar() { + foo().await; +} + +fn main() {}