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:
parent
f5fe425c92
commit
102b5789b2
2 changed files with 198 additions and 1 deletions
|
@ -863,7 +863,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
stack: &TraitObligationStack<'o, 'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
candidate: &SelectionCandidate<'tcx>,
|
candidate: &SelectionCandidate<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
let result = self.evaluation_probe(|this| {
|
let mut result = self.evaluation_probe(|this| {
|
||||||
let candidate = (*candidate).clone();
|
let candidate = (*candidate).clone();
|
||||||
match this.confirm_candidate(stack.obligation, candidate) {
|
match this.confirm_candidate(stack.obligation, candidate) {
|
||||||
Ok(selection) => {
|
Ok(selection) => {
|
||||||
|
@ -876,6 +876,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
Err(..) => Ok(EvaluatedToErr),
|
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);
|
debug!(?result);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
184
src/test/incremental/issue-80691-bad-eval-cache.rs
Normal file
184
src/test/incremental/issue-80691-bad-eval-cache.rs
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
// revisions: rfail1 rfail2
|
||||||
|
// failure-status: 101
|
||||||
|
// error-pattern: not implemented
|
||||||
|
|
||||||
|
pub trait Interner {
|
||||||
|
type InternedVariableKinds;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait RustIrDatabase<I: Interner> {
|
||||||
|
fn associated_ty_data(&self) -> AssociatedTyDatum<I>;
|
||||||
|
fn impl_datum(&self) -> ImplDatum<I>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Fold<I: Interner> {
|
||||||
|
type Result;
|
||||||
|
}
|
||||||
|
impl<T, I: Interner> Fold<I> for Binders<T>
|
||||||
|
where
|
||||||
|
T: HasInterner<Interner = I> + Fold<I>,
|
||||||
|
<T as Fold<I>>::Result: HasInterner<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
type Result = Binders<T::Result>;
|
||||||
|
}
|
||||||
|
impl<I: Interner> Fold<I> for WhereClause<I> {
|
||||||
|
type Result = Binders<WhereClause<I>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait HasInterner {
|
||||||
|
type Interner: Interner;
|
||||||
|
}
|
||||||
|
impl<T: HasInterner> HasInterner for Vec<T> {
|
||||||
|
type Interner = T::Interner;
|
||||||
|
}
|
||||||
|
impl<T: HasInterner + ?Sized> HasInterner for &T {
|
||||||
|
type Interner = T::Interner;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VariableKind<I: Interner> {
|
||||||
|
_marker: std::marker::PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VariableKinds<I: Interner> {
|
||||||
|
_interned: I::InternedVariableKinds,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WhereClause<I: Interner> {
|
||||||
|
_marker: std::marker::PhantomData<I>,
|
||||||
|
}
|
||||||
|
impl<I: Interner> HasInterner for WhereClause<I> {
|
||||||
|
type Interner = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Binders<T> {
|
||||||
|
_marker: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
impl<T: HasInterner> HasInterner for Binders<T> {
|
||||||
|
type Interner = T::Interner;
|
||||||
|
}
|
||||||
|
impl<T> Binders<&T> {
|
||||||
|
fn cloned(self) -> Binders<T> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: HasInterner> Binders<T> {
|
||||||
|
fn map_ref<'a, U, OP>(&'a self, _op: OP) -> Binders<U>
|
||||||
|
where
|
||||||
|
OP: FnOnce(&'a T) -> U,
|
||||||
|
U: HasInterner<Interner = T::Interner>,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T, I: Interner> Binders<T>
|
||||||
|
where
|
||||||
|
T: Fold<I> + HasInterner<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
fn substitute(self) -> T::Result {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<V, U> IntoIterator for Binders<V>
|
||||||
|
where
|
||||||
|
V: HasInterner + IntoIterator<Item = U>,
|
||||||
|
U: HasInterner<Interner = V::Interner>,
|
||||||
|
{
|
||||||
|
type Item = Binders<U>;
|
||||||
|
type IntoIter = BindersIntoIterator<V>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct BindersIntoIterator<V: HasInterner> {
|
||||||
|
_binders: VariableKinds<V::Interner>,
|
||||||
|
}
|
||||||
|
impl<V> Iterator for BindersIntoIterator<V>
|
||||||
|
where
|
||||||
|
V: HasInterner + IntoIterator,
|
||||||
|
<V as IntoIterator>::Item: HasInterner<Interner = V::Interner>,
|
||||||
|
{
|
||||||
|
type Item = Binders<<V as IntoIterator>::Item>;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ImplDatum<I: Interner> {
|
||||||
|
binders: Binders<ImplDatumBound<I>>,
|
||||||
|
}
|
||||||
|
struct ImplDatumBound<I: Interner> {
|
||||||
|
where_clauses: Vec<Binders<WhereClause<I>>>,
|
||||||
|
}
|
||||||
|
impl<I: Interner> HasInterner for ImplDatumBound<I> {
|
||||||
|
type Interner = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AssociatedTyDatum<I: Interner> {
|
||||||
|
binders: Binders<AssociatedTyDatumBound<I>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AssociatedTyDatumBound<I: Interner> {
|
||||||
|
where_clauses: Vec<Binders<WhereClause<I>>>,
|
||||||
|
}
|
||||||
|
impl<I: Interner> HasInterner for AssociatedTyDatumBound<I> {
|
||||||
|
type Interner = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClauseBuilder<'me, I: Interner> {
|
||||||
|
db: &'me dyn RustIrDatabase<I>,
|
||||||
|
}
|
||||||
|
impl<'me, I: Interner> ClauseBuilder<'me, I> {
|
||||||
|
fn new() -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn push_clause(&mut self, _conditions: impl Iterator<Item = Binders<Binders<WhereClause<I>>>>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Forest<I: Interner> {
|
||||||
|
_marker: std::marker::PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> Forest<I> {
|
||||||
|
fn iter_answers<'f>(&'f self) {
|
||||||
|
let builder = &mut ClauseBuilder::<I>::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<ChalkIr>,
|
||||||
|
}
|
||||||
|
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<VariableKind<ChalkIr>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let solver = SLGSolver::new();
|
||||||
|
solver.solve_multiple();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue