From 48cb4871d0eb1aceb977975cc1b3076005828e1a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Jun 2024 11:36:07 +0000 Subject: [PATCH] Do not look in ParamEnv for opaque type bounds that could be satisfied --- .../src/traits/select/candidate_assembly.rs | 51 +++++++++++++------ .../type-alias-impl-trait/in-where-clause.rs | 2 +- .../in-where-clause.stderr | 27 +++++----- 3 files changed, 50 insertions(+), 30 deletions(-) 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 e36a9ca8bd1c2..935daf4c21aba 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -40,21 +40,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { predicate: self.infcx.resolve_vars_if_possible(obligation.predicate), }; - if obligation.predicate.skip_binder().self_ty().is_ty_var() { - debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type"); - // Self is a type variable (e.g., `_: AsRef`). - // - // This is somewhat problematic, as the current scheme can't really - // handle it turning to be a projection. This does end up as truly - // ambiguous in most cases anyway. - // - // Take the fast path out - this also improves - // performance by preventing assemble_candidates_from_impls from - // matching every impl for this trait. - return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); - } - let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + let def_id = obligation.predicate.def_id(); + let tcx = self.tcx(); + + match obligation.predicate.skip_binder().self_ty().kind() { + // Opaque types in their defining scope are just like inference vars... + ty::Alias(ty::Opaque, alias) if self.infcx.can_define_opaque_ty(alias.def_id) => { + if tcx.is_lang_item(def_id, LangItem::Unsize) { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } + self.assemble_candidates_from_impls(obligation, &mut candidates); + // .. unless we are looking for candidates just on the opaque signature, ... + self.assemble_candidates_from_projected_tys(obligation, &mut candidates); + // .. or for auto traits, which look at the hidden type. + // Auto traits must be collected after projected tys, because opaque types + // do not emit auto trait candidates if a projection for the same auto trait + // already exists (e.g. due to the bounds on the opaque). + self.assemble_candidates_from_auto_impls(obligation, &mut candidates); + return Ok(candidates); + } + ty::Infer(ty::TyVar(vid)) => { + debug!(?vid, "ambiguous inference var"); + // Self is a type variable (e.g., `_: AsRef`). + // + // This is somewhat problematic, as the current scheme can't really + // handle it turning to be a projection. This does end up as truly + // ambiguous in most cases anyway. + // + // Take the fast path out - this also improves + // performance by preventing assemble_candidates_from_impls from + // matching every impl for this trait. + candidates.ambiguous = true; + return Ok(candidates); + } + _ => {} + } // Negative trait predicates have different rules than positive trait predicates. if obligation.polarity() == ty::PredicatePolarity::Negative { @@ -66,8 +87,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); - let tcx = self.tcx(); if tcx.is_lang_item(def_id, LangItem::Copy) { debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs index 7c0de39c7c91c..64ed84eee6d42 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.rs +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -4,13 +4,13 @@ #![feature(type_alias_impl_trait)] type Bar = impl Sized; //~^ ERROR: cycle -//~| ERROR: cycle fn foo() -> Bar where Bar: Send, { [0; 1 + 2] + //~^ ERROR: cannot check whether the hidden type } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 9c08b8f127d27..21853b6d40906 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -10,7 +10,7 @@ note: ...which requires computing type of opaque `Bar::{opaque#0}`... LL | type Bar = impl Sized; | ^^^^^^^^^^ note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:9:1 + --> $DIR/in-where-clause.rs:8:1 | LL | / fn foo() -> Bar LL | | where @@ -25,25 +25,26 @@ LL | type Bar = impl Sized; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:13:9 +error: cannot check whether the hidden type of `in_where_clause[cb1b]::Bar::{opaque#0}` satisfies auto traits + --> $DIR/in-where-clause.rs:12:9 | LL | [0; 1 + 2] | ^^^^^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`... - = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Bar::{opaque#0}` + | + = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule +note: opaque type is declared here --> $DIR/in-where-clause.rs:5:12 | LL | type Bar = impl Sized; | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +note: required by a bound in `foo` + --> $DIR/in-where-clause.rs:10:10 + | +LL | fn foo() -> Bar + | --- required by a bound in this function +LL | where +LL | Bar: Send, + | ^^^^ required by this bound in `foo` error: aborting due to 2 previous errors