Use EvaluatedToOkModuloRegions whenever we erase regions

Fixes #80691

When we evaluate a trait predicate, we convert an
`EvaluatedToOk` result to `EvaluatedToOkModuloRegions` if we erased any
regions. We cache the result under a region-erased 'freshened'
predicate, so `EvaluatedToOk` may not be correct for other predicates
that have the same cache key.
This commit is contained in:
Aaron Hill 2021-03-16 19:28:27 -04:00
parent f5fe425c92
commit 102b5789b2
No known key found for this signature in database
GPG key ID: B4087E510E98B164
2 changed files with 198 additions and 1 deletions

View file

@ -863,7 +863,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
stack: &TraitObligationStack<'o, 'tcx>,
candidate: &SelectionCandidate<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
let result = self.evaluation_probe(|this| {
let mut result = self.evaluation_probe(|this| {
let candidate = (*candidate).clone();
match this.confirm_candidate(stack.obligation, candidate) {
Ok(selection) => {
@ -876,6 +876,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(..) => Ok(EvaluatedToErr),
}
})?;
// If we erased any lifetimes, then we want to use
// `EvaluatedToOkModuloRegions` instead of `EvaluatedToOk`
// as your final result. The result will be cached using
// the freshened trait predicate as a key, so we need
// our result to be correct by *any* choice of original lifetimes,
// not just the lifetime choice for this particular (non-erased)
// predicate.
// See issue #80691
if stack.fresh_trait_ref.has_erased_regions() {
result = result.max(EvaluatedToOkModuloRegions);
}
debug!(?result);
Ok(result)
}