Skip to content

Commit

Permalink
Unrolled build for rust-lang#117394
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#117394 - lcnr:proof-tree-cache4, r=compiler-errors

use global cache when computing proof trees

we're writing the solver while relying on the existence of the global cache to avoid exponential blowup. By disabling the global cache when building proof trees, it is easy to get hangs, e.g. when computing intercrate ambiguity causes.

Removes the unstable `-Zdump_solver_proof_tree_use_cache` option, as we now always return a full proof tree.

r? `@compiler-errors`
  • Loading branch information
rust-timer authored Nov 2, 2023
2 parents b800c30 + 15ae59b commit abc07d8
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 126 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ macro_rules! arena_types {
[] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>,
[] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
[] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
[] canonical_goal_evaluation: rustc_middle::traits::solve::inspect::GoalEvaluationStep<'tcx>,
[] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>,
[] type_op_subtype:
rustc_middle::infer::canonical::Canonical<'tcx,
Expand Down
47 changes: 36 additions & 11 deletions compiler/rustc_middle/src/traits/solve/cache.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{CanonicalInput, QueryResult};
use super::{inspect, CanonicalInput, QueryResult};
use crate::ty::TyCtxt;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lock;
Expand All @@ -14,8 +14,10 @@ pub struct EvaluationCache<'tcx> {
map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
}

#[derive(PartialEq, Eq)]
pub struct CacheData<'tcx> {
pub result: QueryResult<'tcx>,
pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
pub reached_depth: usize,
pub encountered_overflow: bool,
}
Expand All @@ -24,22 +26,33 @@ impl<'tcx> EvaluationCache<'tcx> {
/// Insert a final result into the global cache.
pub fn insert(
&self,
tcx: TyCtxt<'tcx>,
key: CanonicalInput<'tcx>,
proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
reached_depth: usize,
did_overflow: bool,
encountered_overflow: bool,
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
dep_node: DepNodeIndex,
result: QueryResult<'tcx>,
) {
let mut map = self.map.borrow_mut();
let entry = map.entry(key).or_default();
let data = WithDepNode::new(dep_node, result);
let data = WithDepNode::new(dep_node, QueryData { result, proof_tree });
entry.cycle_participants.extend(cycle_participants);
if did_overflow {
if encountered_overflow {
entry.with_overflow.insert(reached_depth, data);
} else {
entry.success = Some(Success { data, reached_depth });
}

if cfg!(debug_assertions) {
drop(map);
if Some(CacheData { result, proof_tree, reached_depth, encountered_overflow })
!= self.get(tcx, key, |_| false, Limit(reached_depth))
{
bug!("unable to retrieve inserted element from cache: {key:?}");
}
}
}

/// Try to fetch a cached result, checking the recursion limit
Expand All @@ -62,27 +75,39 @@ impl<'tcx> EvaluationCache<'tcx> {

if let Some(ref success) = entry.success {
if available_depth.value_within_limit(success.reached_depth) {
let QueryData { result, proof_tree } = success.data.get(tcx);
return Some(CacheData {
result: success.data.get(tcx),
result,
proof_tree,
reached_depth: success.reached_depth,
encountered_overflow: false,
});
}
}

entry.with_overflow.get(&available_depth.0).map(|e| CacheData {
result: e.get(tcx),
reached_depth: available_depth.0,
encountered_overflow: true,
entry.with_overflow.get(&available_depth.0).map(|e| {
let QueryData { result, proof_tree } = e.get(tcx);
CacheData {
result,
proof_tree,
reached_depth: available_depth.0,
encountered_overflow: true,
}
})
}
}

struct Success<'tcx> {
data: WithDepNode<QueryResult<'tcx>>,
data: WithDepNode<QueryData<'tcx>>,
reached_depth: usize,
}

#[derive(Clone, Copy)]
pub struct QueryData<'tcx> {
pub result: QueryResult<'tcx>,
pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
}

/// The cache entry for a goal `CanonicalInput`.
///
/// This contains results whose computation never hit the
Expand All @@ -96,5 +121,5 @@ struct CacheEntry<'tcx> {
/// See the doc comment of `StackEntry::cycle_participants` for more
/// details.
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
with_overflow: FxHashMap<usize, WithDepNode<QueryResult<'tcx>>>,
with_overflow: FxHashMap<usize, WithDepNode<QueryData<'tcx>>>,
}
10 changes: 2 additions & 8 deletions compiler/rustc_middle/src/traits/solve/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ pub struct State<'tcx, T> {

pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;

#[derive(Debug, Eq, PartialEq)]
pub enum CacheHit {
Provisional,
Global,
}

/// When evaluating the root goals we also store the
/// original values for the `CanonicalVarValues` of the
/// canonicalized goal. We use this to map any [CanonicalState]
Expand Down Expand Up @@ -78,8 +72,8 @@ pub struct CanonicalGoalEvaluation<'tcx> {
#[derive(Eq, PartialEq)]
pub enum CanonicalGoalEvaluationKind<'tcx> {
Overflow,
CacheHit(CacheHit),
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
CycleInStack,
Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] },
}
impl Debug for GoalEvaluation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_middle/src/traits/solve/inspect/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,10 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
CanonicalGoalEvaluationKind::Overflow => {
writeln!(self.f, "OVERFLOW: {:?}", eval.result)
}
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
CanonicalGoalEvaluationKind::CycleInStack => {
writeln!(self.f, "CYCLE IN STACK: {:?}", eval.result)
}
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
}
CanonicalGoalEvaluationKind::Uncached { revisions } => {
CanonicalGoalEvaluationKind::Evaluation { revisions } => {
for (n, step) in revisions.iter().enumerate() {
writeln!(self.f, "REVISION {n}")?;
self.nested(|this| this.format_evaluation_step(step))?;
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1529,8 +1529,6 @@ options! {
dump_solver_proof_tree: DumpSolverProofTree = (DumpSolverProofTree::Never, parse_dump_solver_proof_tree, [UNTRACKED],
"dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it
then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."),
dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
"determines whether dumped proof trees use the global cache"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
Expand Down
16 changes: 1 addition & 15 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,25 +119,11 @@ impl NestedGoals<'_> {

#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum GenerateProofTree {
Yes(UseGlobalCache),
Yes,
IfEnabled,
Never,
}

#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum UseGlobalCache {
Yes,
No,
}
impl UseGlobalCache {
pub fn from_bool(use_cache: bool) -> Self {
match use_cache {
true => UseGlobalCache::Yes,
false => UseGlobalCache::No,
}
}
}

pub trait InferCtxtEvalExt<'tcx> {
/// Evaluates a goal from **outside** of the trait solver.
///
Expand Down
12 changes: 5 additions & 7 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::ty;

use crate::solve::inspect::ProofTreeBuilder;
use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
use crate::solve::{GenerateProofTree, InferCtxtEvalExt};

pub struct InspectGoal<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
Expand Down Expand Up @@ -82,8 +82,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
}

for &goal in &instantiated_goals {
let (_, proof_tree) =
infcx.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No));
let (_, proof_tree) = infcx.evaluate_root_goal(goal, GenerateProofTree::Yes);
let proof_tree = proof_tree.unwrap();
visitor.visit_goal(&InspectGoal::new(
infcx,
Expand Down Expand Up @@ -169,11 +168,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
let mut candidates = vec![];
let last_eval_step = match self.evaluation.evaluation.kind {
inspect::CanonicalGoalEvaluationKind::Overflow
| inspect::CanonicalGoalEvaluationKind::CacheHit(_) => {
| inspect::CanonicalGoalEvaluationKind::CycleInStack => {
warn!("unexpected root evaluation: {:?}", self.evaluation);
return vec![];
}
inspect::CanonicalGoalEvaluationKind::Uncached { ref revisions } => {
inspect::CanonicalGoalEvaluationKind::Evaluation { ref revisions } => {
if let Some(last) = revisions.last() {
last
} else {
Expand Down Expand Up @@ -227,8 +226,7 @@ impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
goal: Goal<'tcx, ty::Predicate<'tcx>>,
visitor: &mut V,
) -> ControlFlow<V::BreakTy> {
let (_, proof_tree) =
self.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No));
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
let proof_tree = proof_tree.unwrap();
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
}
Expand Down
Loading

0 comments on commit abc07d8

Please sign in to comment.