diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bc0f0d6dea5da..bc8a0eae0e0ff 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -863,7 +863,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, ) -> Result { - 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) } diff --git a/src/test/incremental/issue-80691-bad-eval-cache.rs b/src/test/incremental/issue-80691-bad-eval-cache.rs new file mode 100644 index 0000000000000..1a644fd88d6ba --- /dev/null +++ b/src/test/incremental/issue-80691-bad-eval-cache.rs @@ -0,0 +1,184 @@ +// revisions: rfail1 rfail2 +// failure-status: 101 +// error-pattern: not implemented + +pub trait Interner { + type InternedVariableKinds; +} + +trait RustIrDatabase { + fn associated_ty_data(&self) -> AssociatedTyDatum; + fn impl_datum(&self) -> ImplDatum; +} + +trait Fold { + type Result; +} +impl Fold for Binders +where + T: HasInterner + Fold, + >::Result: HasInterner, + I: Interner, +{ + type Result = Binders; +} +impl Fold for WhereClause { + type Result = Binders>; +} + +trait HasInterner { + type Interner: Interner; +} +impl HasInterner for Vec { + type Interner = T::Interner; +} +impl HasInterner for &T { + type Interner = T::Interner; +} + +pub struct VariableKind { + _marker: std::marker::PhantomData, +} + +struct VariableKinds { + _interned: I::InternedVariableKinds, +} + +struct WhereClause { + _marker: std::marker::PhantomData, +} +impl HasInterner for WhereClause { + type Interner = I; +} + +struct Binders { + _marker: std::marker::PhantomData, +} +impl HasInterner for Binders { + type Interner = T::Interner; +} +impl Binders<&T> { + fn cloned(self) -> Binders { + unimplemented!() + } +} +impl Binders { + fn map_ref<'a, U, OP>(&'a self, _op: OP) -> Binders + where + OP: FnOnce(&'a T) -> U, + U: HasInterner, + { + unimplemented!() + } +} +impl Binders +where + T: Fold + HasInterner, + I: Interner, +{ + fn substitute(self) -> T::Result { + unimplemented!() + } +} +impl IntoIterator for Binders +where + V: HasInterner + IntoIterator, + U: HasInterner, +{ + type Item = Binders; + type IntoIter = BindersIntoIterator; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } +} +struct BindersIntoIterator { + _binders: VariableKinds, +} +impl Iterator for BindersIntoIterator +where + V: HasInterner + IntoIterator, + ::Item: HasInterner, +{ + type Item = Binders<::Item>; + fn next(&mut self) -> Option { + unimplemented!() + } +} + +struct ImplDatum { + binders: Binders>, +} +struct ImplDatumBound { + where_clauses: Vec>>, +} +impl HasInterner for ImplDatumBound { + type Interner = I; +} + +struct AssociatedTyDatum { + binders: Binders>, +} + +struct AssociatedTyDatumBound { + where_clauses: Vec>>, +} +impl HasInterner for AssociatedTyDatumBound { + type Interner = I; +} + +struct ClauseBuilder<'me, I: Interner> { + db: &'me dyn RustIrDatabase, +} +impl<'me, I: Interner> ClauseBuilder<'me, I> { + fn new() -> Self { + unimplemented!() + } + fn push_clause(&mut self, _conditions: impl Iterator>>>) { + unimplemented!() + } +} + +pub(crate) struct Forest { + _marker: std::marker::PhantomData, +} + +impl Forest { + fn iter_answers<'f>(&'f self) { + let builder = &mut ClauseBuilder::::new(); + let impl_datum = builder.db.impl_datum(); + let impl_where_clauses = impl_datum + .binders + .map_ref(|b| &b.where_clauses) + .into_iter() + .map(|wc| wc.cloned().substitute()); + let associated_ty = builder.db.associated_ty_data(); + let assoc_ty_where_clauses = associated_ty + .binders + .map_ref(|b| &b.where_clauses) + .into_iter() + .map(|wc| wc.cloned().substitute()); + builder.push_clause(impl_where_clauses.chain(assoc_ty_where_clauses)); + } +} + +pub struct SLGSolver { + pub(crate) forest: Forest, +} +impl SLGSolver { + fn new() -> Self { + unimplemented!() + } + fn solve_multiple(&self) { + let _answers = self.forest.iter_answers(); + } +} + +pub struct ChalkIr; +impl Interner for ChalkIr { + type InternedVariableKinds = Vec>; +} + +fn main() { + let solver = SLGSolver::new(); + solver.solve_multiple(); +}