Skip to content

Commit c8dae10

Browse files
committed
Check for overflow in evaluate_canonical_goal
1 parent 826bee7 commit c8dae10

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

compiler/rustc_trait_selection/src/solve/mod.rs

+6-17
Original file line numberDiff line numberDiff line change
@@ -211,27 +211,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
211211
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
212212
canonical_goal: CanonicalGoal<'tcx>,
213213
) -> QueryResult<'tcx> {
214-
match search_graph.try_push_stack(tcx, canonical_goal) {
215-
Ok(()) => {}
216-
// Our goal is already on the stack, eager return.
217-
Err(response) => return response,
218-
}
219-
220-
// We may have to repeatedly recompute the goal in case of coinductive cycles,
221-
// check out the `cache` module for more information.
214+
// Deal with overflow, caching, and coinduction.
222215
//
223-
// FIXME: Similar to `evaluate_all`, this has to check for overflow.
224-
loop {
216+
// The actual solver logic happens in `ecx.compute_goal`.
217+
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
225218
let (ref infcx, goal, var_values) =
226219
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
227220
let mut ecx =
228221
EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false };
229-
let result = ecx.compute_goal(goal);
230-
231-
if search_graph.try_finalize_goal(tcx, canonical_goal, result) {
232-
return result;
233-
}
234-
}
222+
ecx.compute_goal(goal)
223+
})
235224
}
236225

237226
fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
@@ -487,7 +476,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
487476
) -> Result<Certainty, NoSolution> {
488477
let mut new_goals = Vec::new();
489478
self.repeat_while_none(
490-
|_| Certainty::Maybe(MaybeCause::Overflow),
479+
|_| Ok(Certainty::Maybe(MaybeCause::Overflow)),
491480
|this| {
492481
let mut has_changed = Err(Certainty::Yes);
493482
for goal in goals.drain(..) {

compiler/rustc_trait_selection/src/solve/search_graph/mod.rs

+38-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub(crate) mod overflow;
33

44
use self::cache::ProvisionalEntry;
55
use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
6+
use crate::solve::search_graph::overflow::OverflowHandler;
67
use cache::ProvisionalCache;
78
use overflow::OverflowData;
89
use rustc_index::vec::IndexVec;
@@ -13,7 +14,7 @@ rustc_index::newtype_index! {
1314
pub struct StackDepth {}
1415
}
1516

16-
struct StackElem<'tcx> {
17+
pub(crate) struct StackElem<'tcx> {
1718
goal: CanonicalGoal<'tcx>,
1819
has_been_used: bool,
1920
}
@@ -127,7 +128,8 @@ impl<'tcx> SearchGraph<'tcx> {
127128
actual_goal: CanonicalGoal<'tcx>,
128129
response: QueryResult<'tcx>,
129130
) -> bool {
130-
let StackElem { goal, has_been_used } = self.stack.pop().unwrap();
131+
let stack_elem = self.stack.pop().unwrap();
132+
let StackElem { goal, has_been_used } = stack_elem;
131133
assert_eq!(goal, actual_goal);
132134

133135
let cache = &mut self.provisional_cache;
@@ -156,18 +158,19 @@ impl<'tcx> SearchGraph<'tcx> {
156158
self.stack.push(StackElem { goal, has_been_used: false });
157159
false
158160
} else {
159-
self.try_move_finished_goal_to_global_cache(tcx, &goal);
161+
self.try_move_finished_goal_to_global_cache(tcx, stack_elem);
160162
true
161163
}
162164
}
163165

164166
pub(super) fn try_move_finished_goal_to_global_cache(
165167
&mut self,
166168
tcx: TyCtxt<'tcx>,
167-
goal: &CanonicalGoal<'tcx>,
169+
stack_elem: StackElem<'tcx>,
168170
) {
171+
let StackElem { goal, .. } = stack_elem;
169172
let cache = &mut self.provisional_cache;
170-
let provisional_entry_index = *cache.lookup_table.get(goal).unwrap();
173+
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
171174
let provisional_entry = &mut cache.entries[provisional_entry_index];
172175
let depth = provisional_entry.depth;
173176

@@ -193,4 +196,34 @@ impl<'tcx> SearchGraph<'tcx> {
193196
}
194197
}
195198
}
199+
200+
pub(super) fn with_new_goal(
201+
&mut self,
202+
tcx: TyCtxt<'tcx>,
203+
canonical_goal: CanonicalGoal<'tcx>,
204+
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
205+
) -> QueryResult<'tcx> {
206+
match self.try_push_stack(tcx, canonical_goal) {
207+
Ok(()) => {}
208+
// Our goal is already on the stack, eager return.
209+
Err(response) => return response,
210+
}
211+
212+
self.repeat_while_none(
213+
|this| {
214+
let result = this.deal_with_overflow(tcx, canonical_goal);
215+
let stack_elem = this.stack.pop().unwrap();
216+
this.try_move_finished_goal_to_global_cache(tcx, stack_elem);
217+
result
218+
},
219+
|this| {
220+
let result = loop_body(this);
221+
if this.try_finalize_goal(tcx, canonical_goal, result) {
222+
Some(result)
223+
} else {
224+
None
225+
}
226+
},
227+
)
228+
}
196229
}

compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub(crate) trait OverflowHandler<'tcx> {
5555

5656
fn repeat_while_none<T>(
5757
&mut self,
58-
on_overflow: impl FnOnce(&mut Self) -> T,
58+
on_overflow: impl FnOnce(&mut Self) -> Result<T, NoSolution>,
5959
mut loop_body: impl FnMut(&mut Self) -> Option<Result<T, NoSolution>>,
6060
) -> Result<T, NoSolution> {
6161
let start_depth = self.search_graph().overflow_data.additional_depth;
@@ -70,7 +70,7 @@ pub(crate) trait OverflowHandler<'tcx> {
7070
}
7171
self.search_graph().overflow_data.additional_depth = start_depth;
7272
self.search_graph().overflow_data.deal_with_overflow();
73-
Ok(on_overflow(self))
73+
on_overflow(self)
7474
}
7575
}
7676

0 commit comments

Comments
 (0)