diff options
6 files changed, 46 insertions, 19 deletions
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e1d6982f164..8b99db06891 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -10,7 +10,7 @@ pub mod util; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Const, Ty}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_span::Span; pub use self::FulfillmentErrorCode::*; @@ -55,6 +55,17 @@ pub struct Obligation<'tcx, T> { pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; +impl PredicateObligation<'tcx> { + pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> { + Some(PredicateObligation { + cause: self.cause.clone(), + param_env: self.param_env, + predicate: self.predicate.flip_polarity(tcx)?, + recursion_depth: self.recursion_depth, + }) + } +} + // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(PredicateObligation<'_>, 32); diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 6720493cd3c..83a2278d8ba 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_query_system::cache::Cache; pub type SelectionCache<'tcx> = Cache< - ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, + (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity), SelectionResult<'tcx, SelectionCandidate<'tcx>>, >; @@ -101,7 +101,7 @@ pub enum SelectionCandidate<'tcx> { /// `false` if there are no *further* obligations. has_nested: bool, }, - ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>), + ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 668a74bd697..b34d0f0f78c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -5,6 +5,7 @@ //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt}; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::SkipLeakCheck; use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; @@ -186,6 +187,7 @@ fn overlap_within_probe( // Are any of the obligations unsatisfiable? If so, no overlap. let infcx = selcx.infcx(); + let tcx = infcx.tcx; let opt_failing_obligation = a_impl_header .predicates .iter() @@ -199,7 +201,13 @@ fn overlap_within_probe( predicate: p, }) .chain(obligations) - .find(|o| !selcx.predicate_may_hold_fatal(o)); + .find(|o| { + !selcx.predicate_may_hold_fatal(o) + || o.flip_polarity(tcx) + .as_ref() + .map(|o| selcx.infcx().predicate_must_hold_considering_regions(o)) + .unwrap_or(false) + }); // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported // to the canonical trait query form, `infcx.predicate_may_hold`, once // the new system supports intercrate mode (which coherence needs). 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 f0761975c19..d532c951212 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -376,7 +376,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for bound in matching_bounds { let wc = self.evaluate_where_clause(stack, bound.value)?; if wc.may_apply() { - candidates.vec.push(ParamCandidate(bound)); + candidates.vec.push(ParamCandidate(( + bound, + stack.obligation.predicate.skip_binder().polarity, + ))); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a36cb1358b6..84721922c8d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -58,8 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param.value); - Ok(ImplSource::Param(obligations, param.constness)) + let obligations = self.confirm_param_candidate(obligation, param.0.value); + Ok(ImplSource::Param(obligations, param.0.constness)) } ImplCandidate(impl_def_id) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 85502a399de..ce90440748f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1107,10 +1107,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // const impl ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {} // const param - ParamCandidate(ty::ConstnessAnd { - constness: ty::BoundConstness::ConstIfConst, - .. - }) => {} + ParamCandidate(( + ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. }, + _, + )) => {} // auto trait impl AutoImplCandidate(..) => {} // generator, this will raise error in other places @@ -1219,14 +1219,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.can_use_global_caches(param_env) { if let Some(res) = tcx .selection_cache - .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx) + .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx) { return Some(res); } } self.infcx .selection_cache - .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx) + .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx) } /// Determines whether can we safely cache the result @@ -1286,7 +1286,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?trait_ref, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. tcx.selection_cache.insert( - param_env.and(trait_ref).with_constness(pred.constness), + (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), dep_node, candidate, ); @@ -1297,7 +1297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?trait_ref, ?candidate, "insert_candidate_cache local"); self.infcx.selection_cache.insert( - param_env.and(trait_ref).with_constness(pred.constness), + (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), dep_node, candidate, ); @@ -1523,10 +1523,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ConstDropCandidate, ) => false, - (ParamCandidate(other), ParamCandidate(victim)) => { + ( + ParamCandidate((other, other_polarity)), + ParamCandidate((victim, victim_polarity)), + ) => { let same_except_bound_vars = other.value.skip_binder() == victim.value.skip_binder() && other.constness == victim.constness + && other_polarity == victim_polarity && !other.value.skip_binder().has_escaping_bound_vars(); if same_except_bound_vars { // See issue #84398. In short, we can generate multiple ParamCandidates which are @@ -1537,6 +1541,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { other.value.bound_vars().len() <= victim.value.bound_vars().len() } else if other.value == victim.value && victim.constness == ty::BoundConstness::NotConst + && other_polarity == victim_polarity { // Drop otherwise equivalent non-const candidates in favor of const candidates. true @@ -1566,11 +1571,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitAliasCandidate(..) | ObjectCandidate(_) | ProjectionCandidate(_), - ) => !is_global(&cand.value), + ) => !is_global(&cand.0.value), (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(&cand.value) + is_global(&cand.0.value) } ( ImplCandidate(_) @@ -1586,7 +1591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(&cand.value) && other.evaluation.must_apply_modulo_regions() + is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions() } (ProjectionCandidate(i), ProjectionCandidate(j)) |
