Skip to content

Commit 9b85e1c

Browse files
committedJul 7, 2017
Auto merge of rust-lang#42840 - arielb1:poison-smoke-and-mirrors, r=nikomatsakis
Replace the global fulfillment cache with the evaluation cache This uses the new "Chalk" ParamEnv refactoring to check "global" predicates in an empty environment, which should be correct because global predicates aren't affected by a consistent environment. Fixes rust-lang#39970. Fixes rust-lang#42796. r? @nikomatsakis
2 parents 13157c4 + b7b965a commit 9b85e1c

File tree

6 files changed

+239
-169
lines changed

6 files changed

+239
-169
lines changed
 

‎src/librustc/traits/fulfill.rs

+19-112
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use dep_graph::DepGraph;
1211
use infer::{InferCtxt, InferOk};
13-
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
12+
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
1413
use ty::error::ExpectedFound;
1514
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
1615
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
1716
use std::marker::PhantomData;
1817
use syntax::ast;
19-
use util::nodemap::{FxHashSet, NodeMap};
18+
use util::nodemap::NodeMap;
2019
use hir::def_id::DefId;
2120

2221
use super::CodeAmbiguity;
@@ -34,11 +33,6 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
3433
fn as_predicate(&self) -> &Self::Predicate { &self.obligation.predicate }
3534
}
3635

37-
pub struct GlobalFulfilledPredicates<'tcx> {
38-
set: FxHashSet<ty::PolyTraitPredicate<'tcx>>,
39-
dep_graph: DepGraph,
40-
}
41-
4236
/// The fulfillment context is used to drive trait resolution. It
4337
/// consists of a list of obligations that must be (eventually)
4438
/// satisfied. The job is to track which are satisfied, which yielded
@@ -183,13 +177,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
183177

184178
assert!(!infcx.is_in_snapshot());
185179

186-
let tcx = infcx.tcx;
187-
188-
if tcx.fulfilled_predicates.borrow().check_duplicate(tcx, &obligation.predicate) {
189-
debug!("register_predicate_obligation: duplicate");
190-
return
191-
}
192-
193180
self.predicates.register_obligation(PendingPredicateObligation {
194181
obligation,
195182
stalled_on: vec![]
@@ -264,13 +251,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
264251
});
265252
debug!("select: outcome={:?}", outcome);
266253

267-
// these are obligations that were proven to be true.
268-
for pending_obligation in outcome.completed {
269-
let predicate = &pending_obligation.obligation.predicate;
270-
selcx.tcx().fulfilled_predicates.borrow_mut()
271-
.add_if_global(selcx.tcx(), predicate);
272-
}
273-
274254
errors.extend(
275255
outcome.errors.into_iter()
276256
.map(|e| to_fulfillment_error(e)));
@@ -318,7 +298,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
318298
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>)
319299
where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
320300
{
321-
if coinductive_match(self.selcx, cycle.clone()) {
301+
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
322302
debug!("process_child_obligations: coinductive match");
323303
} else {
324304
let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
@@ -375,21 +355,31 @@ fn process_predicate<'a, 'gcx, 'tcx>(
375355

376356
match obligation.predicate {
377357
ty::Predicate::Trait(ref data) => {
378-
let tcx = selcx.tcx();
379-
if tcx.fulfilled_predicates.borrow().check_duplicate_trait(tcx, data) {
380-
return Ok(Some(vec![]));
358+
let trait_obligation = obligation.with(data.clone());
359+
360+
if data.is_global() {
361+
// no type variables present, can use evaluation for better caching.
362+
// FIXME: consider caching errors too.
363+
if
364+
// make defaulted unit go through the slow path for better warnings,
365+
// please remove this when the warnings are removed.
366+
!trait_obligation.predicate.skip_binder().self_ty().is_defaulted_unit() &&
367+
selcx.evaluate_obligation_conservatively(&obligation) {
368+
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
369+
data, obligation.recursion_depth);
370+
return Ok(Some(vec![]))
371+
}
381372
}
382373

383-
let trait_obligation = obligation.with(data.clone());
384374
match selcx.select(&trait_obligation) {
385375
Ok(Some(vtable)) => {
386376
debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
387-
data, obligation.recursion_depth);
377+
data, obligation.recursion_depth);
388378
Ok(Some(vtable.nested_obligations()))
389379
}
390380
Ok(None) => {
391381
debug!("selecting trait `{:?}` at depth {} yielded Ok(None)",
392-
data, obligation.recursion_depth);
382+
data, obligation.recursion_depth);
393383

394384
// This is a bit subtle: for the most part, the
395385
// only reason we can fail to make progress on
@@ -549,40 +539,6 @@ fn process_predicate<'a, 'gcx, 'tcx>(
549539
}
550540
}
551541

552-
/// For defaulted traits, we use a co-inductive strategy to solve, so
553-
/// that recursion is ok. This routine returns true if the top of the
554-
/// stack (`cycle[0]`):
555-
/// - is a defaulted trait, and
556-
/// - it also appears in the backtrace at some position `X`; and,
557-
/// - all the predicates at positions `X..` between `X` an the top are
558-
/// also defaulted traits.
559-
fn coinductive_match<'a,'c,'gcx,'tcx,I>(selcx: &mut SelectionContext<'a,'gcx,'tcx>,
560-
cycle: I) -> bool
561-
where I: Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
562-
'tcx: 'c
563-
{
564-
let mut cycle = cycle;
565-
cycle
566-
.all(|bt_obligation| {
567-
let result = coinductive_obligation(selcx, &bt_obligation.obligation);
568-
debug!("coinductive_match: bt_obligation={:?} coinductive={}",
569-
bt_obligation, result);
570-
result
571-
})
572-
}
573-
574-
fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>,
575-
obligation: &PredicateObligation<'tcx>)
576-
-> bool {
577-
match obligation.predicate {
578-
ty::Predicate::Trait(ref data) => {
579-
selcx.tcx().trait_has_default_impl(data.def_id())
580-
}
581-
_ => {
582-
false
583-
}
584-
}
585-
}
586542

587543
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
588544
r_b: ty::Region<'tcx>,
@@ -602,55 +558,6 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
602558

603559
}
604560

605-
impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
606-
pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'gcx> {
607-
GlobalFulfilledPredicates {
608-
set: FxHashSet(),
609-
dep_graph,
610-
}
611-
}
612-
613-
pub fn check_duplicate(&self, tcx: TyCtxt, key: &ty::Predicate<'tcx>) -> bool {
614-
if let ty::Predicate::Trait(ref data) = *key {
615-
self.check_duplicate_trait(tcx, data)
616-
} else {
617-
false
618-
}
619-
}
620-
621-
pub fn check_duplicate_trait(&self, tcx: TyCtxt, data: &ty::PolyTraitPredicate<'tcx>) -> bool {
622-
// For the global predicate registry, when we find a match, it
623-
// may have been computed by some other task, so we want to
624-
// add a read from the node corresponding to the predicate
625-
// processing to make sure we get the transitive dependencies.
626-
if self.set.contains(data) {
627-
debug_assert!(data.is_global());
628-
self.dep_graph.read(data.dep_node(tcx));
629-
debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data);
630-
631-
true
632-
} else {
633-
false
634-
}
635-
}
636-
637-
fn add_if_global(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, key: &ty::Predicate<'tcx>) {
638-
if let ty::Predicate::Trait(ref data) = *key {
639-
// We only add things to the global predicate registry
640-
// after the current task has proved them, and hence
641-
// already has the required read edges, so we don't need
642-
// to add any more edges here.
643-
if data.is_global() {
644-
if let Some(data) = tcx.lift_to_global(data) {
645-
if self.set.insert(data.clone()) {
646-
debug!("add_if_global: global predicate `{:?}` added", data);
647-
}
648-
}
649-
}
650-
}
651-
}
652-
}
653-
654561
fn to_fulfillment_error<'tcx>(
655562
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>)
656563
-> FulfillmentError<'tcx>

‎src/librustc/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use syntax_pos::{Span, DUMMY_SP};
3131
pub use self::coherence::orphan_check;
3232
pub use self::coherence::overlapping_impls;
3333
pub use self::coherence::OrphanCheckErr;
34-
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
34+
pub use self::fulfill::{FulfillmentContext, RegionObligation};
3535
pub use self::project::MismatchedProjectionTypes;
3636
pub use self::project::{normalize, normalize_projection_type, Normalized};
3737
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};

0 commit comments

Comments
 (0)
Please sign in to comment.