Skip to content

Commit 97e9c7e

Browse files
committed
Revert "Auto merge of #42840 - arielb1:poison-smoke-and-mirrors, r=nikomatsakis"
This reverts commit 9b85e1c, reversing changes made to 13157c4.
1 parent 80a0504 commit 97e9c7e

File tree

6 files changed

+169
-239
lines changed

6 files changed

+169
-239
lines changed

src/librustc/traits/fulfill.rs

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

11+
use dep_graph::DepGraph;
1112
use infer::{InferCtxt, InferOk};
12-
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
13+
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
1314
use ty::error::ExpectedFound;
1415
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
1516
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
1617
use std::marker::PhantomData;
1718
use syntax::ast;
18-
use util::nodemap::NodeMap;
19+
use util::nodemap::{FxHashSet, NodeMap};
1920
use hir::def_id::DefId;
2021

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

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

178184
assert!(!infcx.is_in_snapshot());
179185

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+
180193
self.predicates.register_obligation(PendingPredicateObligation {
181194
obligation,
182195
stalled_on: vec![]
@@ -251,6 +264,13 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
251264
});
252265
debug!("select: outcome={:?}", outcome);
253266

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+
254274
errors.extend(
255275
outcome.errors.into_iter()
256276
.map(|e| to_fulfillment_error(e)));
@@ -298,7 +318,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
298318
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>)
299319
where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
300320
{
301-
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
321+
if coinductive_match(self.selcx, cycle.clone()) {
302322
debug!("process_child_obligations: coinductive match");
303323
} else {
304324
let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
@@ -355,31 +375,21 @@ fn process_predicate<'a, 'gcx, 'tcx>(
355375

356376
match obligation.predicate {
357377
ty::Predicate::Trait(ref data) => {
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-
}
378+
let tcx = selcx.tcx();
379+
if tcx.fulfilled_predicates.borrow().check_duplicate_trait(tcx, data) {
380+
return Ok(Some(vec![]));
372381
}
373382

383+
let trait_obligation = obligation.with(data.clone());
374384
match selcx.select(&trait_obligation) {
375385
Ok(Some(vtable)) => {
376386
debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
377-
data, obligation.recursion_depth);
387+
data, obligation.recursion_depth);
378388
Ok(Some(vtable.nested_obligations()))
379389
}
380390
Ok(None) => {
381391
debug!("selecting trait `{:?}` at depth {} yielded Ok(None)",
382-
data, obligation.recursion_depth);
392+
data, obligation.recursion_depth);
383393

384394
// This is a bit subtle: for the most part, the
385395
// only reason we can fail to make progress on
@@ -540,6 +550,40 @@ fn process_predicate<'a, 'gcx, 'tcx>(
540550
}
541551
}
542552

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

544588
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
545589
r_b: ty::Region<'tcx>,
@@ -559,6 +603,55 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
559603

560604
}
561605

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