Skip to content

Instantly share code, notes, and snippets.

@nikomatsakis
Created September 1, 2017 23:52
Show Gist options
  • Save nikomatsakis/389081d10444601bca9d8b33883b087f to your computer and use it in GitHub Desktop.
Save nikomatsakis/389081d10444601bca9d8b33883b087f to your computer and use it in GitHub Desktop.
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 512cfee12b..dcb9507fc0 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -416,7 +416,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
// bounds. It might be the case that we want two distinct caches,
// or else another kind of cache entry.
- match infcx.projection_cache.borrow_mut().try_start(cache_key) {
+ let cache_result = infcx.projection_cache.borrow_mut().try_start(cache_key);
+ match cache_result {
Ok(()) => { }
Err(ProjectionCacheEntry::Ambiguous) => {
// If we found ambiguity the last time, that generally
@@ -466,7 +467,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
projection_ty);
selcx.infcx().report_overflow_error(&obligation, false);
}
- Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
+ Err(ProjectionCacheEntry::NormalizedTy(mut ty)) => {
// If we find the value in the cache, then return it along
// with the obligations that went along with it. Note
// that, when using a fulfillment context, these
@@ -479,6 +480,15 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
debug!("opt_normalize_projection_type: \
found normalized ty `{:?}`",
ty);
+ ty.value = infcx.resolve_type_vars_if_possible(&ty.value);
+
+ // Once we have inferred everything we need to know, we
+ // can ignore the `obligations` from that point on.
+ if !ty.value.has_infer_types() {
+ infcx.projection_cache.borrow_mut().complete(cache_key);
+ ty.obligations = vec![];
+ }
+
return Some(ty);
}
Err(ProjectionCacheEntry::Error) => {
@@ -504,7 +514,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
depth,
obligations);
- let result = if projected_ty.has_projection_types() {
+ let mut result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
param_env,
cause,
@@ -527,7 +537,27 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
obligations,
}
};
- infcx.projection_cache.borrow_mut().insert_ty(cache_key, &result);
+ result.value = infcx.resolve_type_vars_if_possible(&result.value);
+
+ if !result.value.has_infer_types() {
+ // If there are no unresolved type variables in the
+ // output, then there is no need to cache the
+ // subobligations (though we do return them here, so
+ // that they can be registered and verified). In
+ // particular, the only thing that can happen with
+ // those subobligations is that one of them will fail
+ // to be verified, yielding a compilation error.
+ infcx.projection_cache.borrow_mut().insert_ty(cache_key, &Normalized {
+ value: result.value,
+ obligations: vec![]
+ });
+ } else {
+ // If there *are* unresolved type variables, then we
+ // need the subobligations, at least until those type
+ // variables are fully resolved.
+ infcx.projection_cache.borrow_mut().insert_ty(cache_key, &result);
+ }
+
Some(result)
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment