diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2021-05-31 13:22:40 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2021-09-02 11:10:40 -0500 |
| commit | f2d9ee9c342104880dd978e85260243d2dcedc9a (patch) | |
| tree | 452d87442da559a12d1780d92c594a36b9bda1c3 /compiler/rustc_trait_selection/src/traits | |
| parent | 64929313f53181636e4dd37e25836973205477e4 (diff) | |
Preserve most sub-obligations in the projection cache
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
3 files changed, 26 insertions, 49 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 91b9ad0af35..7038f16a2c9 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -10,6 +10,7 @@ use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; +use super::TraitQueryMode; use super::{ ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData, @@ -18,7 +19,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::error_reporting::InferCtxtExt as _; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; @@ -912,6 +913,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( } let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); + match project_type(selcx, &obligation) { Ok(ProjectedTy::Progress(Progress { ty: projected_ty, @@ -925,7 +927,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_ty = selcx.infcx().resolve_vars_if_possible(projected_ty); debug!(?projected_ty, ?depth, ?projected_obligations); - let result = if projected_ty.has_projections() { + let mut result = if projected_ty.has_projections() { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, @@ -942,8 +944,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( Normalized { value: projected_ty, obligations: projected_obligations } }; - let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value); + let mut canonical = + SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical); + result.obligations.drain_filter(|projected_obligation| { + // If any global obligations always apply, considering regions, then we don't + // need to include them. The `is_global` check rules out inference variables, + // so there's no need for the caller of `opt_normalize_projection_type` + // to evaluate them. + // Note that we do *not* discard obligations that evaluate to + // `EvaluatedtoOkModuloRegions`. Evaluating these obligations + // inside of a query (e.g. `evaluate_obligation`) can change + // the result to `EvaluatedToOkModuloRegions`, while an + // `EvaluatedToOk` obligation will never change the result. + // See #85360 for more details + projected_obligation.is_global(canonical.tcx()) + && canonical + .evaluate_root_obligation(projected_obligation) + .map_or(false, |res| res.must_apply_considering_regions()) + }); + + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); obligations.extend(result.obligations); Ok(Some(result.value)) } @@ -974,49 +994,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( } } -/// If there are unresolved type variables, then we need to include -/// any subobligations that bind them, at least until those type -/// variables are fully resolved. -fn prune_cache_value_obligations<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - result: &NormalizedTy<'tcx>, -) -> NormalizedTy<'tcx> { - if infcx.unresolved_type_vars(&result.value).is_none() { - return NormalizedTy { value: result.value, obligations: vec![] }; - } - - let mut obligations: Vec<_> = result - .obligations - .iter() - .filter(|obligation| { - let bound_predicate = obligation.predicate.kind(); - match bound_predicate.skip_binder() { - // We found a `T: Foo<X = U>` predicate, let's check - // if `U` references any unresolved type - // variables. In principle, we only care if this - // projection can help resolve any of the type - // variables found in `result.value` -- but we just - // check for any type variables here, for fear of - // indirect obligations (e.g., we project to `?0`, - // but we have `T: Foo<X = ?1>` and `?1: Bar<X = - // ?0>`). - ty::PredicateKind::Projection(data) => { - infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some() - } - - // We are only interested in `T: Foo<X = U>` predicates, whre - // `U` references one of `unresolved_type_vars`. =) - _ => false, - } - }) - .cloned() - .collect(); - - obligations.shrink_to_fit(); - - NormalizedTy { value: result.value, obligations } -} - /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not /// hold. In various error cases, we cannot generate a valid /// normalized projection. Therefore, we create an inference variable diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 2dc48e47efc..032d402fec0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -71,7 +71,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. - self.tcx.evaluate_obligation(c_pred) + self.tcx.at(obligation.cause.span(self.tcx)).evaluate_obligation(c_pred) } // Helper function that canonicalizes and runs the query. If an diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5214277a37d..22013fb79cf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -682,7 +682,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }); - debug!(?result); + debug!("finished: {:?} from {:?}", result, obligation); result } |
