Skip to content

Commit 102b578

Browse files
committed
Use EvaluatedToOkModuloRegions whenever we erase regions
Fixes rust-lang#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.
1 parent f5fe425 commit 102b578

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
863863
stack: &TraitObligationStack<'o, 'tcx>,
864864
candidate: &SelectionCandidate<'tcx>,
865865
) -> Result<EvaluationResult, OverflowError> {
866-
let result = self.evaluation_probe(|this| {
866+
let mut result = self.evaluation_probe(|this| {
867867
let candidate = (*candidate).clone();
868868
match this.confirm_candidate(stack.obligation, candidate) {
869869
Ok(selection) => {
@@ -876,6 +876,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
876876
Err(..) => Ok(EvaluatedToErr),
877877
}
878878
})?;
879+
880+
// If we erased any lifetimes, then we want to use
881+
// `EvaluatedToOkModuloRegions` instead of `EvaluatedToOk`
882+
// as your final result. The result will be cached using
883+
// the freshened trait predicate as a key, so we need
884+
// our result to be correct by *any* choice of original lifetimes,
885+
// not just the lifetime choice for this particular (non-erased)
886+
// predicate.
887+
// See issue #80691
888+
if stack.fresh_trait_ref.has_erased_regions() {
889+
result = result.max(EvaluatedToOkModuloRegions);
890+
}
891+
879892
debug!(?result);
880893
Ok(result)
881894
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// revisions: rfail1 rfail2
2+
// failure-status: 101
3+
// error-pattern: not implemented
4+
5+
pub trait Interner {
6+
type InternedVariableKinds;
7+
}
8+
9+
trait RustIrDatabase<I: Interner> {
10+
fn associated_ty_data(&self) -> AssociatedTyDatum<I>;
11+
fn impl_datum(&self) -> ImplDatum<I>;
12+
}
13+
14+
trait Fold<I: Interner> {
15+
type Result;
16+
}
17+
impl<T, I: Interner> Fold<I> for Binders<T>
18+
where
19+
T: HasInterner<Interner = I> + Fold<I>,
20+
<T as Fold<I>>::Result: HasInterner<Interner = I>,
21+
I: Interner,
22+
{
23+
type Result = Binders<T::Result>;
24+
}
25+
impl<I: Interner> Fold<I> for WhereClause<I> {
26+
type Result = Binders<WhereClause<I>>;
27+
}
28+
29+
trait HasInterner {
30+
type Interner: Interner;
31+
}
32+
impl<T: HasInterner> HasInterner for Vec<T> {
33+
type Interner = T::Interner;
34+
}
35+
impl<T: HasInterner + ?Sized> HasInterner for &T {
36+
type Interner = T::Interner;
37+
}
38+
39+
pub struct VariableKind<I: Interner> {
40+
_marker: std::marker::PhantomData<I>,
41+
}
42+
43+
struct VariableKinds<I: Interner> {
44+
_interned: I::InternedVariableKinds,
45+
}
46+
47+
struct WhereClause<I: Interner> {
48+
_marker: std::marker::PhantomData<I>,
49+
}
50+
impl<I: Interner> HasInterner for WhereClause<I> {
51+
type Interner = I;
52+
}
53+
54+
struct Binders<T> {
55+
_marker: std::marker::PhantomData<T>,
56+
}
57+
impl<T: HasInterner> HasInterner for Binders<T> {
58+
type Interner = T::Interner;
59+
}
60+
impl<T> Binders<&T> {
61+
fn cloned(self) -> Binders<T> {
62+
unimplemented!()
63+
}
64+
}
65+
impl<T: HasInterner> Binders<T> {
66+
fn map_ref<'a, U, OP>(&'a self, _op: OP) -> Binders<U>
67+
where
68+
OP: FnOnce(&'a T) -> U,
69+
U: HasInterner<Interner = T::Interner>,
70+
{
71+
unimplemented!()
72+
}
73+
}
74+
impl<T, I: Interner> Binders<T>
75+
where
76+
T: Fold<I> + HasInterner<Interner = I>,
77+
I: Interner,
78+
{
79+
fn substitute(self) -> T::Result {
80+
unimplemented!()
81+
}
82+
}
83+
impl<V, U> IntoIterator for Binders<V>
84+
where
85+
V: HasInterner + IntoIterator<Item = U>,
86+
U: HasInterner<Interner = V::Interner>,
87+
{
88+
type Item = Binders<U>;
89+
type IntoIter = BindersIntoIterator<V>;
90+
fn into_iter(self) -> Self::IntoIter {
91+
unimplemented!()
92+
}
93+
}
94+
struct BindersIntoIterator<V: HasInterner> {
95+
_binders: VariableKinds<V::Interner>,
96+
}
97+
impl<V> Iterator for BindersIntoIterator<V>
98+
where
99+
V: HasInterner + IntoIterator,
100+
<V as IntoIterator>::Item: HasInterner<Interner = V::Interner>,
101+
{
102+
type Item = Binders<<V as IntoIterator>::Item>;
103+
fn next(&mut self) -> Option<Self::Item> {
104+
unimplemented!()
105+
}
106+
}
107+
108+
struct ImplDatum<I: Interner> {
109+
binders: Binders<ImplDatumBound<I>>,
110+
}
111+
struct ImplDatumBound<I: Interner> {
112+
where_clauses: Vec<Binders<WhereClause<I>>>,
113+
}
114+
impl<I: Interner> HasInterner for ImplDatumBound<I> {
115+
type Interner = I;
116+
}
117+
118+
struct AssociatedTyDatum<I: Interner> {
119+
binders: Binders<AssociatedTyDatumBound<I>>,
120+
}
121+
122+
struct AssociatedTyDatumBound<I: Interner> {
123+
where_clauses: Vec<Binders<WhereClause<I>>>,
124+
}
125+
impl<I: Interner> HasInterner for AssociatedTyDatumBound<I> {
126+
type Interner = I;
127+
}
128+
129+
struct ClauseBuilder<'me, I: Interner> {
130+
db: &'me dyn RustIrDatabase<I>,
131+
}
132+
impl<'me, I: Interner> ClauseBuilder<'me, I> {
133+
fn new() -> Self {
134+
unimplemented!()
135+
}
136+
fn push_clause(&mut self, _conditions: impl Iterator<Item = Binders<Binders<WhereClause<I>>>>) {
137+
unimplemented!()
138+
}
139+
}
140+
141+
pub(crate) struct Forest<I: Interner> {
142+
_marker: std::marker::PhantomData<I>,
143+
}
144+
145+
impl<I: Interner> Forest<I> {
146+
fn iter_answers<'f>(&'f self) {
147+
let builder = &mut ClauseBuilder::<I>::new();
148+
let impl_datum = builder.db.impl_datum();
149+
let impl_where_clauses = impl_datum
150+
.binders
151+
.map_ref(|b| &b.where_clauses)
152+
.into_iter()
153+
.map(|wc| wc.cloned().substitute());
154+
let associated_ty = builder.db.associated_ty_data();
155+
let assoc_ty_where_clauses = associated_ty
156+
.binders
157+
.map_ref(|b| &b.where_clauses)
158+
.into_iter()
159+
.map(|wc| wc.cloned().substitute());
160+
builder.push_clause(impl_where_clauses.chain(assoc_ty_where_clauses));
161+
}
162+
}
163+
164+
pub struct SLGSolver {
165+
pub(crate) forest: Forest<ChalkIr>,
166+
}
167+
impl SLGSolver {
168+
fn new() -> Self {
169+
unimplemented!()
170+
}
171+
fn solve_multiple(&self) {
172+
let _answers = self.forest.iter_answers();
173+
}
174+
}
175+
176+
pub struct ChalkIr;
177+
impl Interner for ChalkIr {
178+
type InternedVariableKinds = Vec<VariableKind<ChalkIr>>;
179+
}
180+
181+
fn main() {
182+
let solver = SLGSolver::new();
183+
solver.solve_multiple();
184+
}

0 commit comments

Comments
 (0)