Preserve most sub-obligations in the projection cache
This commit is contained in:
parent
64929313f5
commit
f2d9ee9c34
@ -10,6 +10,7 @@
|
|||||||
use super::Selection;
|
use super::Selection;
|
||||||
use super::SelectionContext;
|
use super::SelectionContext;
|
||||||
use super::SelectionError;
|
use super::SelectionError;
|
||||||
|
use super::TraitQueryMode;
|
||||||
use super::{
|
use super::{
|
||||||
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
|
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
|
||||||
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
|
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
|
||||||
@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
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_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir::def_id::DefId;
|
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);
|
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
|
||||||
|
|
||||||
match project_type(selcx, &obligation) {
|
match project_type(selcx, &obligation) {
|
||||||
Ok(ProjectedTy::Progress(Progress {
|
Ok(ProjectedTy::Progress(Progress {
|
||||||
ty: projected_ty,
|
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);
|
let projected_ty = selcx.infcx().resolve_vars_if_possible(projected_ty);
|
||||||
debug!(?projected_ty, ?depth, ?projected_obligations);
|
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(
|
let mut normalizer = AssocTypeNormalizer::new(
|
||||||
selcx,
|
selcx,
|
||||||
param_env,
|
param_env,
|
||||||
@ -942,8 +944,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
Normalized { value: projected_ty, obligations: projected_obligations }
|
Normalized { value: projected_ty, obligations: projected_obligations }
|
||||||
};
|
};
|
||||||
|
|
||||||
let cache_value = prune_cache_value_obligations(infcx, &result);
|
let mut canonical =
|
||||||
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value);
|
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);
|
obligations.extend(result.obligations);
|
||||||
Ok(Some(result.value))
|
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
|
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
||||||
/// hold. In various error cases, we cannot generate a valid
|
/// hold. In various error cases, we cannot generate a valid
|
||||||
/// normalized projection. Therefore, we create an inference variable
|
/// normalized projection. Therefore, we create an inference variable
|
||||||
|
@ -71,7 +71,7 @@ fn evaluate_obligation(
|
|||||||
// Run canonical query. If overflow occurs, rerun from scratch but this time
|
// Run canonical query. If overflow occurs, rerun from scratch but this time
|
||||||
// in standard trait query mode so that overflow is handled appropriately
|
// in standard trait query mode so that overflow is handled appropriately
|
||||||
// within `SelectionContext`.
|
// 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
|
// Helper function that canonicalizes and runs the query. If an
|
||||||
|
@ -682,7 +682,7 @@ fn evaluate_predicate_recursively<'o>(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!(?result);
|
debug!("finished: {:?} from {:?}", result, obligation);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ note: ...which requires building MIR for `cycle1`...
|
|||||||
LL | fn cycle1() -> impl Clone {
|
LL | fn cycle1() -> impl Clone {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
note: ...which requires type-checking `cycle1`...
|
note: ...which requires type-checking `cycle1`...
|
||||||
--> $DIR/auto-trait-leak.rs:12:1
|
--> $DIR/auto-trait-leak.rs:14:5
|
||||||
|
|
|
|
||||||
LL | fn cycle1() -> impl Clone {
|
LL | send(cycle2().clone());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^
|
||||||
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
||||||
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
||||||
--> $DIR/auto-trait-leak.rs:19:16
|
--> $DIR/auto-trait-leak.rs:19:16
|
||||||
@ -66,10 +66,10 @@ note: ...which requires building MIR for `cycle2`...
|
|||||||
LL | fn cycle2() -> impl Clone {
|
LL | fn cycle2() -> impl Clone {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
note: ...which requires type-checking `cycle2`...
|
note: ...which requires type-checking `cycle2`...
|
||||||
--> $DIR/auto-trait-leak.rs:19:1
|
--> $DIR/auto-trait-leak.rs:20:5
|
||||||
|
|
|
|
||||||
LL | fn cycle2() -> impl Clone {
|
LL | send(cycle1().clone());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^
|
||||||
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
||||||
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
|
@ -25,6 +25,7 @@ struct Runtime<DB: Database> {
|
|||||||
}
|
}
|
||||||
struct SalsaStorage {
|
struct SalsaStorage {
|
||||||
_parse: <ParseQuery as Query<RootDatabase>>::Data,
|
_parse: <ParseQuery as Query<RootDatabase>>::Data,
|
||||||
|
//~^ ERROR overflow evaluating the requirement `RootDatabase: SourceDatabase`
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database for RootDatabase {
|
impl Database for RootDatabase {
|
||||||
@ -67,7 +68,6 @@ pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 {
|
|||||||
// we used to fail to report an error here because we got the
|
// we used to fail to report an error here because we got the
|
||||||
// caching wrong.
|
// caching wrong.
|
||||||
SourceDatabase::parse(db);
|
SourceDatabase::parse(db);
|
||||||
//~^ ERROR overflow
|
|
||||||
22
|
22
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +1,14 @@
|
|||||||
error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe`
|
error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
|
||||||
--> $DIR/cycle-cache-err-60010.rs:69:5
|
--> $DIR/cycle-cache-err-60010.rs:27:13
|
||||||
|
|
|
|
||||||
LL | SourceDatabase::parse(db);
|
LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: required because it appears within the type `*const SalsaStorage`
|
note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
|
||||||
= note: required because it appears within the type `Unique<SalsaStorage>`
|
--> $DIR/cycle-cache-err-60010.rs:37:10
|
||||||
= note: required because it appears within the type `Box<SalsaStorage>`
|
|
||||||
note: required because it appears within the type `Runtime<RootDatabase>`
|
|
||||||
--> $DIR/cycle-cache-err-60010.rs:23:8
|
|
||||||
|
|
|
|
||||||
LL | struct Runtime<DB: Database> {
|
LL | impl<DB> Query<DB> for ParseQuery
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^ ^^^^^^^^^^
|
||||||
note: required because it appears within the type `RootDatabase`
|
|
||||||
--> $DIR/cycle-cache-err-60010.rs:20:8
|
|
||||||
|
|
|
||||||
LL | struct RootDatabase {
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
note: required because of the requirements on the impl of `SourceDatabase` for `RootDatabase`
|
|
||||||
--> $DIR/cycle-cache-err-60010.rs:43:9
|
|
||||||
|
|
|
||||||
LL | impl<T> SourceDatabase for T
|
|
||||||
| ^^^^^^^^^^^^^^ ^
|
|
||||||
note: required by `SourceDatabase::parse`
|
|
||||||
--> $DIR/cycle-cache-err-60010.rs:14:5
|
|
||||||
|
|
|
||||||
LL | fn parse(&self) {
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user