@@ -36,6 +36,7 @@ pub struct GlobalFulfilledPredicates<'tcx> {
3636 dep_graph : DepGraph ,
3737}
3838
39+ #[ derive( Debug ) ]
3940pub struct LocalFulfilledPredicates < ' tcx > {
4041 set : FnvHashSet < ty:: Predicate < ' tcx > >
4142}
@@ -66,7 +67,8 @@ pub struct FulfillmentContext<'tcx> {
6667
6768 // A list of all obligations that have been registered with this
6869 // fulfillment context.
69- predicates : ObligationForest < PendingPredicateObligation < ' tcx > > ,
70+ predicates : ObligationForest < PendingPredicateObligation < ' tcx > ,
71+ LocalFulfilledPredicates < ' tcx > > ,
7072
7173 // A set of constraints that regionck must validate. Each
7274 // constraint has the form `T:'a`, meaning "some type `T` must
@@ -192,7 +194,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
192194 obligation : obligation,
193195 stalled_on : vec ! [ ]
194196 } ;
195- self . predicates . push_root ( obligation) ;
197+ self . predicates . push_tree ( obligation, LocalFulfilledPredicates :: new ( ) ) ;
196198 }
197199
198200 pub fn region_obligations ( & self ,
@@ -278,10 +280,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
278280 let outcome = {
279281 let region_obligations = & mut self . region_obligations ;
280282 self . predicates . process_obligations (
281- |obligation, backtrace| process_predicate ( selcx,
282- obligation,
283- backtrace,
284- region_obligations) )
283+ |obligation, tree, backtrace| process_predicate ( selcx,
284+ tree,
285+ obligation,
286+ backtrace,
287+ region_obligations) )
285288 } ;
286289
287290 debug ! ( "select_where_possible: outcome={:?}" , outcome) ;
@@ -315,61 +318,97 @@ impl<'tcx> FulfillmentContext<'tcx> {
315318
316319/// Like `process_predicate1`, but wrap result into a pending predicate.
317320fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
321+ tree_cache : & mut LocalFulfilledPredicates < ' tcx > ,
318322 pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
319- backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
323+ mut backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
320324 region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
321325 -> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
322326 FulfillmentErrorCode < ' tcx > >
323327{
324- match process_predicate1 ( selcx, pending_obligation, backtrace, region_obligations) {
328+ match process_predicate1 ( selcx, pending_obligation, backtrace. clone ( ) , region_obligations) {
325329 Ok ( Some ( v) ) => {
326- // FIXME(#30977) the right thing to do here, I think, is to permit
327- // DAGs. That is, we should detect whenever this predicate
328- // has appeared somewhere in the current tree./ If it's a
329- // parent, that's a cycle, and we should either error out
330- // or consider it ok. But if it's NOT a parent, we can
331- // ignore it, since it will be proven (or not) separately.
332- // However, this is a touch tricky, so I'm doing something
333- // a bit hackier for now so that the `huge-struct.rs` passes.
330+ // FIXME(#30977) The code below is designed to detect (and
331+ // permit) DAGs, while still ensuring that the reasoning
332+ // is acyclic. However, it does a few things
333+ // suboptimally. For example, it refreshes type variables
334+ // a lot, probably more than needed, but also less than
335+ // you might want.
336+ //
337+ // - more than needed: I want to be very sure we don't
338+ // accidentally treat a cycle as a DAG, so I am
339+ // refreshing type variables as we walk the ancestors;
340+ // but we are going to repeat this a lot, which is
341+ // sort of silly, and it would be nicer to refresh
342+ // them *in place* so that later predicate processing
343+ // can benefit from the same work;
344+ // - less than you might want: we only add items in the cache here,
345+ // but maybe we learn more about type variables and could add them into
346+ // the cache later on.
334347
335348 let tcx = selcx. tcx ( ) ;
336349
337- let retain_vec: Vec < _ > = {
338- let mut dedup = FnvHashSet ( ) ;
339- v. iter ( )
340- . map ( |o| {
350+ // Compute a little FnvHashSet for the ancestors. We only
351+ // do this the first time that we care.
352+ let mut cache = None ;
353+ let mut is_ancestor = |predicate : & ty:: Predicate < ' tcx > | {
354+ if cache. is_none ( ) {
355+ let mut c = FnvHashSet ( ) ;
356+ for ancestor in backtrace. by_ref ( ) {
357+ // Ugh. This just feels ridiculously
358+ // inefficient. But we need to compare
359+ // predicates without being concerned about
360+ // the vagaries of type inference, so for now
361+ // just ensure that they are always
362+ // up-to-date. (I suppose we could just use a
363+ // snapshot and check if they are unifiable?)
364+ let resolved_predicate =
365+ selcx. infcx ( ) . resolve_type_vars_if_possible (
366+ & ancestor. obligation . predicate ) ;
367+ c. insert ( resolved_predicate) ;
368+ }
369+ cache = Some ( c) ;
370+ }
371+
372+ cache. as_ref ( ) . unwrap ( ) . contains ( predicate)
373+ } ;
374+
375+ let pending_predicate_obligations: Vec < _ > =
376+ v. into_iter ( )
377+ . filter_map ( |obligation| {
378+ // Probably silly, but remove any inference
379+ // variables. This is actually crucial to the
380+ // ancestor check below, but it's not clear that
381+ // it makes sense to ALWAYS do it.
382+ let obligation = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation) ;
383+
341384 // Screen out obligations that we know globally
342385 // are true. This should really be the DAG check
343386 // mentioned above.
344- if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & o . predicate ) {
345- return false ;
387+ if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & obligation . predicate ) {
388+ return None ;
346389 }
347390
348- // If we see two siblings that are exactly the
349- // same, no need to add them twice.
350- if !dedup. insert ( & o. predicate ) {
351- return false ;
391+ // Check whether this obligation appears somewhere else in the tree.
392+ if tree_cache. is_duplicate_or_add ( & obligation. predicate ) {
393+ // If the obligation appears as a parent,
394+ // allow it, because that is a cycle.
395+ // Otherwise though we can just ignore
396+ // it. Note that we have to be careful around
397+ // inference variables here -- for the
398+ // purposes of the ancestor check, we retain
399+ // the invariant that all type variables are
400+ // fully refreshed.
401+ if !( & mut is_ancestor) ( & obligation. predicate ) {
402+ return None ;
403+ }
352404 }
353405
354- true
406+ Some ( PendingPredicateObligation {
407+ obligation : obligation,
408+ stalled_on : vec ! [ ]
409+ } )
355410 } )
356- . collect ( )
357- } ;
358-
359- let pending_predicate_obligations =
360- v. into_iter ( )
361- . zip ( retain_vec)
362- . flat_map ( |( o, retain) | {
363- if retain {
364- Some ( PendingPredicateObligation {
365- obligation : o,
366- stalled_on : vec ! [ ]
367- } )
368- } else {
369- None
370- }
371- } )
372- . collect ( ) ;
411+ . collect ( ) ;
373412
374413 Ok ( Some ( pending_predicate_obligations) )
375414 }
@@ -405,7 +444,7 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
405444 pending_obligation. stalled_on = vec ! [ ] ;
406445 }
407446
408- let obligation = & pending_obligation. obligation ;
447+ let obligation = & mut pending_obligation. obligation ;
409448
410449 // If we exceed the recursion limit, take a moment to look for a
411450 // cycle so we can give a better error report from here, where we
@@ -417,18 +456,31 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
417456 }
418457 }
419458
459+ if obligation. predicate . has_infer_types ( ) {
460+ obligation. predicate = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation. predicate ) ;
461+ }
462+
420463 match obligation. predicate {
421464 ty:: Predicate :: Trait ( ref data) => {
465+ if selcx. tcx ( ) . fulfilled_predicates . borrow ( ) . check_duplicate_trait ( data) {
466+ return Ok ( Some ( vec ! [ ] ) ) ;
467+ }
468+
422469 if coinductive_match ( selcx, obligation, data, & backtrace) {
423470 return Ok ( Some ( vec ! [ ] ) ) ;
424471 }
425472
426473 let trait_obligation = obligation. with ( data. clone ( ) ) ;
427474 match selcx. select ( & trait_obligation) {
428475 Ok ( Some ( vtable) ) => {
476+ info ! ( "selecting trait `{:?}` at depth {} yielded Ok(Some)" ,
477+ data, obligation. recursion_depth) ;
429478 Ok ( Some ( vtable. nested_obligations ( ) ) )
430479 }
431480 Ok ( None ) => {
481+ info ! ( "selecting trait `{:?}` at depth {} yielded Ok(None)" ,
482+ data, obligation. recursion_depth) ;
483+
432484 // This is a bit subtle: for the most part, the
433485 // only reason we can fail to make progress on
434486 // trait selection is because we don't have enough
@@ -457,6 +509,8 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
457509 Ok ( None )
458510 }
459511 Err ( selection_err) => {
512+ info ! ( "selecting trait `{:?}` at depth {} yielded Err" ,
513+ data, obligation. recursion_depth) ;
460514 Err ( CodeSelectionError ( selection_err) )
461515 }
462516 }
@@ -642,18 +696,28 @@ impl<'tcx> GlobalFulfilledPredicates<'tcx> {
642696
643697 pub fn check_duplicate ( & self , key : & ty:: Predicate < ' tcx > ) -> bool {
644698 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- }
699+ self . check_duplicate_trait ( data)
700+ } else {
701+ false
654702 }
703+ }
704+
705+ pub fn check_duplicate_trait ( & self , data : & ty:: PolyTraitPredicate < ' tcx > ) -> bool {
706+ // For the global predicate registry, when we find a match, it
707+ // may have been computed by some other task, so we want to
708+ // add a read from the node corresponding to the predicate
709+ // processing to make sure we get the transitive dependencies.
710+ if self . set . contains ( data) {
711+ debug_assert ! ( data. is_global( ) ) ;
712+ self . dep_graph . read ( data. dep_node ( ) ) ;
713+ debug ! ( "check_duplicate: global predicate `{:?}` already proved elsewhere" , data) ;
714+
715+ info ! ( "check_duplicate_trait hit: `{:?}`" , data) ;
655716
656- return false ;
717+ true
718+ } else {
719+ false
720+ }
657721 }
658722
659723 fn add_if_global ( & mut self , key : & ty:: Predicate < ' tcx > ) {
@@ -663,7 +727,10 @@ impl<'tcx> GlobalFulfilledPredicates<'tcx> {
663727 // already has the required read edges, so we don't need
664728 // to add any more edges here.
665729 if data. is_global ( ) {
666- self . set . insert ( data. clone ( ) ) ;
730+ if self . set . insert ( data. clone ( ) ) {
731+ debug ! ( "add_if_global: global predicate `{:?}` added" , data) ;
732+ info ! ( "check_duplicate_trait entry: `{:?}`" , data) ;
733+ }
667734 }
668735 }
669736 }
0 commit comments