debug!(?result, "CACHE MISS");
self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
- stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
- self.insert_evaluation_cache(
- param_env,
- fresh_trait_pred,
- dep_node,
- provisional_result.max(result),
- );
- });
+ stack.cache().on_completion(
+ stack.dfn,
+ |fresh_trait_pred, provisional_result, provisional_dep_node| {
+ // Create a new `DepNode` that has dependencies on:
+ // * The `DepNode` for the original evaluation that resulted in a provisional cache
+ // entry being crated
+ // * The `DepNode` for the *current* evaluation, which resulted in us completing
+ // provisional caches entries and inserting them into the evaluation cache
+ //
+ // This ensures that when a query reads this entry from the evaluation cache,
+ // it will end up (transitively) dependening on all of the incr-comp dependencies
+ // created during the evaluation of this trait. For example, evaluating a trait
+ // will usually require us to invoke `type_of(field_def_id)` to determine the
+ // constituent types, and we want any queries reading from this evaluation
+ // cache entry to end up with a transitive `type_of(field_def_id`)` dependency.
+ //
+ // By using `in_task`, we're also creating an edge from the *current* query
+ // to the newly-created `combined_dep_node`. This is probably redundant,
+ // but it's better to add too many dep graph edges than to add too few
+ // dep graph edges.
+ let ((), combined_dep_node) = self.in_task(|this| {
+ this.tcx().dep_graph.read_index(provisional_dep_node);
+ this.tcx().dep_graph.read_index(dep_node);
+ });
+ self.insert_evaluation_cache(
+ param_env,
+ fresh_trait_pred,
+ combined_dep_node,
+ provisional_result.max(result),
+ );
+ },
+ );
} else {
debug!(?result, "PROVISIONAL");
debug!(
fresh_trait_pred, stack.depth, reached_depth,
);
- stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
+ stack.cache().insert_provisional(
+ stack.dfn,
+ reached_depth,
+ fresh_trait_pred,
+ result,
+ dep_node,
+ );
}
Ok(result)
ImplCandidate(def_id)
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
- ParamCandidate(trait_pred)
- if trait_pred.skip_binder().constness
- == ty::BoundConstness::ConstIfConst => {}
+ ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
// auto trait impl
AutoImplCandidate(..) => {}
// generator, this will raise error in other places
// chain. Ideally, we should have a way to configure this either
// by using -Z verbose or just a CLI argument.
let derived_cause = DerivedObligationCause {
- parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
+ parent_trait_pred: obligation.predicate,
parent_code: obligation.cause.clone_code(),
};
let derived_code = variant(derived_cause);
from_dfn: usize,
reached_depth: usize,
result: EvaluationResult,
+ /// The `DepNodeIndex` created for the `evaluate_stack` call for this provisional
+ /// evaluation. When we create an entry in the evaluation cache using this provisional
+ /// cache entry (see `on_completion`), we use this `dep_node` to ensure that future reads from
+ /// the cache will have all of the necessary incr comp dependencies tracked.
+ dep_node: DepNodeIndex,
}
impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
reached_depth: usize,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
result: EvaluationResult,
+ dep_node: DepNodeIndex,
) {
debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
}
}
- map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
+ map.insert(
+ fresh_trait_pred,
+ ProvisionalEvaluation { from_dfn, reached_depth, result, dep_node },
+ );
}
/// Invoked when the node with dfn `dfn` does not get a successful
fn on_completion(
&self,
dfn: usize,
- mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
+ mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult, DepNodeIndex),
) {
debug!(?dfn, "on_completion");
{
debug!(?fresh_trait_pred, ?eval, "on_completion");
- op(fresh_trait_pred, eval.result);
+ op(fresh_trait_pred, eval.result, eval.dep_node);
}
}
}