88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use dep_graph:: DepGraph ;
1112use middle:: infer:: InferCtxt ;
1213use middle:: ty:: { self , Ty , TypeFoldable } ;
1314use rustc_data_structures:: obligation_forest:: { Backtrace , ObligationForest , Error } ;
@@ -30,7 +31,12 @@ use super::select::SelectionContext;
3031use super :: Unimplemented ;
3132use super :: util:: predicate_for_builtin_bound;
3233
33- pub struct FulfilledPredicates < ' tcx > {
34+ pub struct GlobalFulfilledPredicates < ' tcx > {
35+ set : FnvHashSet < ty:: PolyTraitPredicate < ' tcx > > ,
36+ dep_graph : DepGraph ,
37+ }
38+
39+ pub struct LocalFulfilledPredicates < ' tcx > {
3440 set : FnvHashSet < ty:: Predicate < ' tcx > >
3541}
3642
@@ -56,7 +62,7 @@ pub struct FulfillmentContext<'tcx> {
5662 // initially-distinct type variables are unified after being
5763 // inserted. Deduplicating the predicate set on selection had a
5864 // significant performance cost the last time I checked.
59- duplicate_set : FulfilledPredicates < ' tcx > ,
65+ duplicate_set : LocalFulfilledPredicates < ' tcx > ,
6066
6167 // A list of all obligations that have been registered with this
6268 // fulfillment context.
@@ -106,7 +112,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
106112 /// Creates a new fulfillment context.
107113 pub fn new ( ) -> FulfillmentContext < ' tcx > {
108114 FulfillmentContext {
109- duplicate_set : FulfilledPredicates :: new ( ) ,
115+ duplicate_set : LocalFulfilledPredicates :: new ( ) ,
110116 predicates : ObligationForest :: new ( ) ,
111117 region_obligations : NodeMap ( ) ,
112118 }
@@ -240,7 +246,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
240246 // local cache). This is because the tcx cache maintains the
241247 // invariant that it only contains things that have been
242248 // proven, and we have not yet proven that `predicate` holds.
243- if predicate . is_global ( ) && tcx. fulfilled_predicates . borrow ( ) . is_duplicate ( predicate) {
249+ if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( predicate) {
244250 return true ;
245251 }
246252
@@ -283,10 +289,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
283289 // these are obligations that were proven to be true.
284290 for pending_obligation in outcome. completed {
285291 let predicate = & pending_obligation. obligation . predicate ;
286- if predicate. is_global ( ) {
287- selcx. tcx ( ) . fulfilled_predicates . borrow_mut ( )
288- . is_duplicate_or_add ( predicate) ;
289- }
292+ selcx. tcx ( ) . fulfilled_predicates . borrow_mut ( ) . add_if_global ( predicate) ;
290293 }
291294
292295 errors. extend (
@@ -329,17 +332,16 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
329332 // However, this is a touch tricky, so I'm doing something
330333 // a bit hackier for now so that the `huge-struct.rs` passes.
331334
335+ let tcx = selcx. tcx ( ) ;
336+
332337 let retain_vec: Vec < _ > = {
333338 let mut dedup = FnvHashSet ( ) ;
334339 v. iter ( )
335340 . map ( |o| {
336341 // Screen out obligations that we know globally
337342 // are true. This should really be the DAG check
338343 // mentioned above.
339- if
340- o. predicate . is_global ( ) &&
341- selcx. tcx ( ) . fulfilled_predicates . borrow ( ) . is_duplicate ( & o. predicate )
342- {
344+ if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & o. predicate ) {
343345 return false ;
344346 }
345347
@@ -611,22 +613,62 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
611613
612614}
613615
614- impl < ' tcx > FulfilledPredicates < ' tcx > {
615- pub fn new ( ) -> FulfilledPredicates < ' tcx > {
616- FulfilledPredicates {
616+ impl < ' tcx > LocalFulfilledPredicates < ' tcx > {
617+ pub fn new ( ) -> LocalFulfilledPredicates < ' tcx > {
618+ LocalFulfilledPredicates {
617619 set : FnvHashSet ( )
618620 }
619621 }
620622
621- pub fn is_duplicate ( & self , key : & ty:: Predicate < ' tcx > ) -> bool {
622- self . set . contains ( key)
623- }
624-
625623 fn is_duplicate_or_add ( & mut self , key : & ty:: Predicate < ' tcx > ) -> bool {
624+ // For a `LocalFulfilledPredicates`, if we find a match, we
625+ // don't need to add a read edge to the dep-graph. This is
626+ // because it means that the predicate has already been
627+ // considered by this `FulfillmentContext`, and hence the
628+ // containing task will already have an edge. (Here we are
629+ // assuming each `FulfillmentContext` only gets used from one
630+ // task; but to do otherwise makes no sense)
626631 !self . set . insert ( key. clone ( ) )
627632 }
628633}
629634
635+ impl < ' tcx > GlobalFulfilledPredicates < ' tcx > {
636+ pub fn new ( dep_graph : DepGraph ) -> GlobalFulfilledPredicates < ' tcx > {
637+ GlobalFulfilledPredicates {
638+ set : FnvHashSet ( ) ,
639+ dep_graph : dep_graph,
640+ }
641+ }
642+
643+ pub fn check_duplicate ( & self , key : & ty:: Predicate < ' tcx > ) -> bool {
644+ if let ty:: Predicate :: Trait ( ref data) = * key {
645+ // For the global predicate registry, when we find a match, it
646+ // may have been computed by some other task, so we want to
647+ // add a read from the node corresponding to the predicate
648+ // processing to make sure we get the transitive dependencies.
649+ if self . set . contains ( data) {
650+ debug_assert ! ( data. is_global( ) ) ;
651+ self . dep_graph . read ( data. dep_node ( ) ) ;
652+ return true ;
653+ }
654+ }
655+
656+ return false ;
657+ }
658+
659+ fn add_if_global ( & mut self , key : & ty:: Predicate < ' tcx > ) {
660+ if let ty:: Predicate :: Trait ( ref data) = * key {
661+ // We only add things to the global predicate registry
662+ // after the current task has proved them, and hence
663+ // already has the required read edges, so we don't need
664+ // to add any more edges here.
665+ if data. is_global ( ) {
666+ self . set . insert ( data. clone ( ) ) ;
667+ }
668+ }
669+ }
670+ }
671+
630672fn to_fulfillment_error < ' tcx > (
631673 error : Error < PendingPredicateObligation < ' tcx > , FulfillmentErrorCode < ' tcx > > )
632674 -> FulfillmentError < ' tcx >
0 commit comments