8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use dep_graph:: DepGraph ;
11
12
use middle:: infer:: InferCtxt ;
12
13
use middle:: ty:: { self , Ty , TypeFoldable } ;
13
14
use rustc_data_structures:: obligation_forest:: { Backtrace , ObligationForest , Error } ;
@@ -30,7 +31,12 @@ use super::select::SelectionContext;
30
31
use super :: Unimplemented ;
31
32
use super :: util:: predicate_for_builtin_bound;
32
33
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 > {
34
40
set : FnvHashSet < ty:: Predicate < ' tcx > >
35
41
}
36
42
@@ -56,7 +62,7 @@ pub struct FulfillmentContext<'tcx> {
56
62
// initially-distinct type variables are unified after being
57
63
// inserted. Deduplicating the predicate set on selection had a
58
64
// significant performance cost the last time I checked.
59
- duplicate_set : FulfilledPredicates < ' tcx > ,
65
+ duplicate_set : LocalFulfilledPredicates < ' tcx > ,
60
66
61
67
// A list of all obligations that have been registered with this
62
68
// fulfillment context.
@@ -106,7 +112,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
106
112
/// Creates a new fulfillment context.
107
113
pub fn new ( ) -> FulfillmentContext < ' tcx > {
108
114
FulfillmentContext {
109
- duplicate_set : FulfilledPredicates :: new ( ) ,
115
+ duplicate_set : LocalFulfilledPredicates :: new ( ) ,
110
116
predicates : ObligationForest :: new ( ) ,
111
117
region_obligations : NodeMap ( ) ,
112
118
}
@@ -240,7 +246,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
240
246
// local cache). This is because the tcx cache maintains the
241
247
// invariant that it only contains things that have been
242
248
// 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) {
244
250
return true ;
245
251
}
246
252
@@ -283,10 +289,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
283
289
// these are obligations that were proven to be true.
284
290
for pending_obligation in outcome. completed {
285
291
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) ;
290
293
}
291
294
292
295
errors. extend (
@@ -329,17 +332,16 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
329
332
// However, this is a touch tricky, so I'm doing something
330
333
// a bit hackier for now so that the `huge-struct.rs` passes.
331
334
335
+ let tcx = selcx. tcx ( ) ;
336
+
332
337
let retain_vec: Vec < _ > = {
333
338
let mut dedup = FnvHashSet ( ) ;
334
339
v. iter ( )
335
340
. map ( |o| {
336
341
// Screen out obligations that we know globally
337
342
// are true. This should really be the DAG check
338
343
// 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 ) {
343
345
return false ;
344
346
}
345
347
@@ -611,22 +613,62 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
611
613
612
614
}
613
615
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 {
617
619
set : FnvHashSet ( )
618
620
}
619
621
}
620
622
621
- pub fn is_duplicate ( & self , key : & ty:: Predicate < ' tcx > ) -> bool {
622
- self . set . contains ( key)
623
- }
624
-
625
623
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)
626
631
!self . set . insert ( key. clone ( ) )
627
632
}
628
633
}
629
634
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
+
630
672
fn to_fulfillment_error < ' tcx > (
631
673
error : Error < PendingPredicateObligation < ' tcx > , FulfillmentErrorCode < ' tcx > > )
632
674
-> FulfillmentError < ' tcx >
0 commit comments