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 infer:: { InferCtxt , InferOk } ;
12
- use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , ToPredicate } ;
13
+ use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , TyCtxt , ToPredicate } ;
13
14
use ty:: error:: ExpectedFound ;
14
15
use rustc_data_structures:: obligation_forest:: { ObligationForest , Error } ;
15
16
use rustc_data_structures:: obligation_forest:: { ForestObligation , ObligationProcessor } ;
16
17
use std:: marker:: PhantomData ;
17
18
use syntax:: ast;
18
- use util:: nodemap:: NodeMap ;
19
+ use util:: nodemap:: { FxHashSet , NodeMap } ;
19
20
use hir:: def_id:: DefId ;
20
21
21
22
use super :: CodeAmbiguity ;
@@ -33,6 +34,11 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
33
34
fn as_predicate ( & self ) -> & Self :: Predicate { & self . obligation . predicate }
34
35
}
35
36
37
+ pub struct GlobalFulfilledPredicates < ' tcx > {
38
+ set : FxHashSet < ty:: PolyTraitPredicate < ' tcx > > ,
39
+ dep_graph : DepGraph ,
40
+ }
41
+
36
42
/// The fulfillment context is used to drive trait resolution. It
37
43
/// consists of a list of obligations that must be (eventually)
38
44
/// satisfied. The job is to track which are satisfied, which yielded
@@ -177,6 +183,13 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
177
183
178
184
assert ! ( !infcx. is_in_snapshot( ) ) ;
179
185
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
+
180
193
self . predicates . register_obligation ( PendingPredicateObligation {
181
194
obligation,
182
195
stalled_on : vec ! [ ]
@@ -251,6 +264,13 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
251
264
} ) ;
252
265
debug ! ( "select: outcome={:?}" , outcome) ;
253
266
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
+
254
274
errors. extend (
255
275
outcome. errors . into_iter ( )
256
276
. map ( |e| to_fulfillment_error ( e) ) ) ;
@@ -298,7 +318,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
298
318
_marker : PhantomData < & ' c PendingPredicateObligation < ' tcx > > )
299
319
where I : Clone + Iterator < Item =& ' c PendingPredicateObligation < ' tcx > > ,
300
320
{
301
- if self . selcx . coinductive_match ( cycle. clone ( ) . map ( |s| s . obligation . predicate ) ) {
321
+ if coinductive_match ( self . selcx , cycle. clone ( ) ) {
302
322
debug ! ( "process_child_obligations: coinductive match" ) ;
303
323
} else {
304
324
let cycle : Vec < _ > = cycle. map ( |c| c. obligation . clone ( ) ) . collect ( ) ;
@@ -355,31 +375,21 @@ fn process_predicate<'a, 'gcx, 'tcx>(
355
375
356
376
match obligation. predicate {
357
377
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 ! [ ] ) ) ;
372
381
}
373
382
383
+ let trait_obligation = obligation. with ( data. clone ( ) ) ;
374
384
match selcx. select ( & trait_obligation) {
375
385
Ok ( Some ( vtable) ) => {
376
386
debug ! ( "selecting trait `{:?}` at depth {} yielded Ok(Some)" ,
377
- data, obligation. recursion_depth) ;
387
+ data, obligation. recursion_depth) ;
378
388
Ok ( Some ( vtable. nested_obligations ( ) ) )
379
389
}
380
390
Ok ( None ) => {
381
391
debug ! ( "selecting trait `{:?}` at depth {} yielded Ok(None)" ,
382
- data, obligation. recursion_depth) ;
392
+ data, obligation. recursion_depth) ;
383
393
384
394
// This is a bit subtle: for the most part, the
385
395
// only reason we can fail to make progress on
@@ -540,6 +550,40 @@ fn process_predicate<'a, 'gcx, 'tcx>(
540
550
}
541
551
}
542
552
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
+ }
543
587
544
588
fn register_region_obligation < ' tcx > ( t_a : Ty < ' tcx > ,
545
589
r_b : ty:: Region < ' tcx > ,
@@ -559,6 +603,55 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
559
603
560
604
}
561
605
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
+
562
655
fn to_fulfillment_error < ' tcx > (
563
656
error : Error < PendingPredicateObligation < ' tcx > , FulfillmentErrorCode < ' tcx > > )
564
657
-> FulfillmentError < ' tcx >
0 commit comments