88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use dep_graph:: DepGraph ;
1112use infer:: { InferCtxt , InferOk } ;
12- use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , ToPredicate } ;
13+ use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , TyCtxt , ToPredicate } ;
1314use ty:: error:: ExpectedFound ;
1415use rustc_data_structures:: obligation_forest:: { ObligationForest , Error } ;
1516use rustc_data_structures:: obligation_forest:: { ForestObligation , ObligationProcessor } ;
1617use std:: marker:: PhantomData ;
1718use syntax:: ast;
18- use util:: nodemap:: NodeMap ;
19+ use util:: nodemap:: { FxHashSet , NodeMap } ;
1920use hir:: def_id:: DefId ;
2021
2122use 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
544588fn 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+
562655fn to_fulfillment_error < ' tcx > (
563656 error : Error < PendingPredicateObligation < ' tcx > , FulfillmentErrorCode < ' tcx > > )
564657 -> FulfillmentError < ' tcx >
0 commit comments