Skip to content

Commit d231eec

Browse files
committed
Use all projection sub-obligations during trait evaluation
1 parent b5a2cce commit d231eec

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

compiler/rustc_infer/src/traits/project.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub enum ProjectionCacheEntry<'tcx> {
9292
Ambiguous,
9393
Recur,
9494
Error,
95-
NormalizedTy(NormalizedTy<'tcx>),
95+
NormalizedTy { value: NormalizedTy<'tcx>, full_obligations: Vec<PredicateObligation<'tcx>> },
9696
}
9797

9898
impl<'tcx> ProjectionCacheStorage<'tcx> {
@@ -139,7 +139,12 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
139139
}
140140

141141
/// Indicates that `key` was normalized to `value`.
142-
pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
142+
pub fn insert_ty(
143+
&mut self,
144+
key: ProjectionCacheKey<'tcx>,
145+
value: NormalizedTy<'tcx>,
146+
full_obligations: Vec<PredicateObligation<'tcx>>,
147+
) {
143148
debug!(
144149
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
145150
key, value
@@ -149,7 +154,8 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
149154
debug!("Not overwriting Recur");
150155
return;
151156
}
152-
let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
157+
let fresh_key =
158+
map.insert(key, ProjectionCacheEntry::NormalizedTy { value, full_obligations });
153159
assert!(!fresh_key, "never started projecting `{:?}`", key);
154160
}
155161

@@ -160,7 +166,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
160166
pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
161167
let mut map = self.map();
162168
let ty = match map.get(&key) {
163-
Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
169+
Some(&ProjectionCacheEntry::NormalizedTy { value: ref ty, .. }) => {
164170
debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
165171
ty.value
166172
}
@@ -174,7 +180,10 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
174180

175181
map.insert(
176182
key,
177-
ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
183+
ProjectionCacheEntry::NormalizedTy {
184+
value: Normalized { value: ty, obligations: vec![] },
185+
full_obligations: vec![],
186+
},
178187
);
179188
}
180189

@@ -186,10 +195,10 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
186195
if !ty.obligations.is_empty() {
187196
self.map().insert(
188197
key,
189-
ProjectionCacheEntry::NormalizedTy(Normalized {
190-
value: ty.value,
191-
obligations: vec![],
192-
}),
198+
ProjectionCacheEntry::NormalizedTy {
199+
value: Normalized { value: ty.value, obligations: vec![] },
200+
full_obligations: vec![],
201+
},
193202
);
194203
}
195204
}

compiler/rustc_trait_selection/src/traits/project.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
516516
Err(ProjectionCacheEntry::Recur) => {
517517
return Err(InProgress);
518518
}
519-
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
519+
Err(ProjectionCacheEntry::NormalizedTy { value: ty, full_obligations }) => {
520520
// This is the hottest path in this function.
521521
//
522522
// If we find the value in the cache, then return it along
@@ -529,7 +529,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
529529
// evaluation this is not the case, and dropping the trait
530530
// evaluations can causes ICEs (e.g., #43132).
531531
debug!(?ty, "found normalized ty");
532-
obligations.extend(ty.obligations);
532+
if selcx.skip_projection_cache() {
533+
obligations.extend(full_obligations);
534+
} else {
535+
obligations.extend(ty.obligations);
536+
}
533537
return Ok(Some(ty.value));
534538
}
535539
Err(ProjectionCacheEntry::Error) => {
@@ -571,14 +575,22 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
571575
};
572576

573577
let cache_value = prune_cache_value_obligations(infcx, &result);
574-
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value);
578+
infcx.inner.borrow_mut().projection_cache().insert_ty(
579+
cache_key,
580+
cache_value,
581+
result.obligations.clone(),
582+
);
575583
obligations.extend(result.obligations);
576584
Ok(Some(result.value))
577585
}
578586
Ok(ProjectedTy::NoProgress(projected_ty)) => {
579587
debug!(?projected_ty, "opt_normalize_projection_type: no progress");
580588
let result = Normalized { value: projected_ty, obligations: vec![] };
581-
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
589+
infcx.inner.borrow_mut().projection_cache().insert_ty(
590+
cache_key,
591+
result.clone(),
592+
vec![],
593+
);
582594
// No need to extend `obligations`.
583595
Ok(Some(result.value))
584596
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub struct SelectionContext<'cx, 'tcx> {
133133
/// policy. In essence, canonicalized queries need their errors propagated
134134
/// rather than immediately reported because we do not have accurate spans.
135135
query_mode: TraitQueryMode,
136+
skip_projection_cache: bool,
136137
}
137138

138139
// A stack that walks back up the stack frame.
@@ -221,6 +222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
221222
intercrate_ambiguity_causes: None,
222223
allow_negative_impls: false,
223224
query_mode: TraitQueryMode::Standard,
225+
skip_projection_cache: false,
224226
}
225227
}
226228

@@ -232,6 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
232234
intercrate_ambiguity_causes: None,
233235
allow_negative_impls: false,
234236
query_mode: TraitQueryMode::Standard,
237+
skip_projection_cache: false,
235238
}
236239
}
237240

@@ -247,6 +250,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
247250
intercrate_ambiguity_causes: None,
248251
allow_negative_impls,
249252
query_mode: TraitQueryMode::Standard,
253+
skip_projection_cache: false,
250254
}
251255
}
252256

@@ -262,9 +266,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
262266
intercrate_ambiguity_causes: None,
263267
allow_negative_impls: false,
264268
query_mode,
269+
skip_projection_cache: false,
265270
}
266271
}
267272

273+
pub fn skip_projection_cache(&self) -> bool {
274+
self.skip_projection_cache
275+
}
276+
268277
/// Enables tracking of intercrate ambiguity causes. These are
269278
/// used in coherence to give improved diagnostics. We don't do
270279
/// this until we detect a coherence error because it can lead to
@@ -379,12 +388,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
379388
&mut self,
380389
obligation: &PredicateObligation<'tcx>,
381390
) -> Result<EvaluationResult, OverflowError> {
382-
self.evaluation_probe(|this| {
391+
let old = std::mem::replace(&mut self.skip_projection_cache, true);
392+
let res = self.evaluation_probe(|this| {
383393
this.evaluate_predicate_recursively(
384394
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
385395
obligation.clone(),
386396
)
387-
})
397+
});
398+
self.skip_projection_cache = old;
399+
res
388400
}
389401

390402
fn evaluation_probe(

0 commit comments

Comments
 (0)