@@ -320,103 +320,172 @@ impl<'tcx> FulfillmentContext<'tcx> {
320320fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
321321 tree_cache : & mut LocalFulfilledPredicates < ' tcx > ,
322322 pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
323- mut backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
323+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
324324 region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
325325 -> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
326326 FulfillmentErrorCode < ' tcx > >
327327{
328- match process_predicate1 ( selcx, pending_obligation, backtrace. clone ( ) , region_obligations) {
329- Ok ( Some ( v) ) => {
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.
347-
348- let tcx = selcx. tcx ( ) ;
349-
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) ;
328+ match process_predicate1 ( selcx, pending_obligation, region_obligations) {
329+ Ok ( Some ( v) ) => process_child_obligations ( selcx,
330+ tree_cache,
331+ & pending_obligation. obligation ,
332+ backtrace,
333+ v) ,
334+ Ok ( None ) => Ok ( None ) ,
335+ Err ( e) => Err ( e)
336+ }
337+ }
338+
339+ fn process_child_obligations < ' a , ' tcx > (
340+ selcx : & mut SelectionContext < ' a , ' tcx > ,
341+ tree_cache : & mut LocalFulfilledPredicates < ' tcx > ,
342+ pending_obligation : & PredicateObligation < ' tcx > ,
343+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
344+ child_obligations : Vec < PredicateObligation < ' tcx > > )
345+ -> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
346+ FulfillmentErrorCode < ' tcx > >
347+ {
348+ // FIXME(#30977) The code below is designed to detect (and
349+ // permit) DAGs, while still ensuring that the reasoning
350+ // is acyclic. However, it does a few things
351+ // suboptimally. For example, it refreshes type variables
352+ // a lot, probably more than needed, but also less than
353+ // you might want.
354+ //
355+ // - more than needed: I want to be very sure we don't
356+ // accidentally treat a cycle as a DAG, so I am
357+ // refreshing type variables as we walk the ancestors;
358+ // but we are going to repeat this a lot, which is
359+ // sort of silly, and it would be nicer to refresh
360+ // them *in place* so that later predicate processing
361+ // can benefit from the same work;
362+ // - less than you might want: we only add items in the cache here,
363+ // but maybe we learn more about type variables and could add them into
364+ // the cache later on.
365+
366+ let tcx = selcx. tcx ( ) ;
367+
368+ let mut ancestor_set = AncestorSet :: new ( & backtrace) ;
369+
370+ let pending_predicate_obligations: Vec < _ > =
371+ child_obligations
372+ . into_iter ( )
373+ . filter_map ( |obligation| {
374+ // Probably silly, but remove any inference
375+ // variables. This is actually crucial to the ancestor
376+ // check marked (*) below, but it's not clear that it
377+ // makes sense to ALWAYS do it.
378+ let obligation = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation) ;
379+
380+ // Screen out obligations that we know globally
381+ // are true.
382+ if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & obligation. predicate ) {
383+ return None ;
384+ }
385+
386+ // Check whether this obligation appears
387+ // somewhere else in the tree. If not, we have to
388+ // process it for sure.
389+ if !tree_cache. is_duplicate_or_add ( & obligation. predicate ) {
390+ return Some ( PendingPredicateObligation {
391+ obligation : obligation,
392+ stalled_on : vec ! [ ]
393+ } ) ;
394+ }
395+
396+ debug ! ( "process_child_obligations: duplicate={:?}" ,
397+ obligation. predicate) ;
398+
399+ // OK, the obligation appears elsewhere in the tree.
400+ // This is either a fatal error or else something we can
401+ // ignore. If the obligation appears in our *ancestors*
402+ // (rather than some more distant relative), that
403+ // indicates a cycle. Cycles are either considered
404+ // resolved (if this is a coinductive case) or a fatal
405+ // error.
406+ if let Some ( index) = ancestor_set. has ( selcx. infcx ( ) , & obligation. predicate ) {
407+ // ~~~ (*) see above
408+ debug ! ( "process_child_obligations: cycle index = {}" , index) ;
409+
410+ let backtrace = backtrace. clone ( ) ;
411+ let cycle: Vec < _ > =
412+ iter:: once ( & obligation)
413+ . chain ( Some ( pending_obligation) )
414+ . chain ( backtrace. take ( index + 1 ) . map ( |p| & p. obligation ) )
415+ . cloned ( )
416+ . collect ( ) ;
417+ if coinductive_match ( selcx, & cycle) {
418+ debug ! ( "process_child_obligations: coinductive match" ) ;
419+ None
420+ } else {
421+ report_overflow_error_cycle ( selcx. infcx ( ) , & cycle) ;
370422 }
423+ } else {
424+ // Not a cycle. Just ignore this obligation then,
425+ // we're already in the process of proving it.
426+ debug ! ( "process_child_obligations: not a cycle" ) ;
427+ None
428+ }
429+ } )
430+ . collect ( ) ;
371431
372- cache. as_ref ( ) . unwrap ( ) . contains ( predicate)
373- } ;
432+ Ok ( Some ( pending_predicate_obligations) )
433+ }
434+
435+ struct AncestorSet < ' b , ' tcx : ' b > {
436+ populated : bool ,
437+ cache : FnvHashMap < ty:: Predicate < ' tcx > , usize > ,
438+ backtrace : Backtrace < ' b , PendingPredicateObligation < ' tcx > > ,
439+ }
374440
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-
384- // Screen out obligations that we know globally
385- // are true. This should really be the DAG check
386- // mentioned above.
387- if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & obligation. predicate ) {
388- return None ;
389- }
390-
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 !is_ancestor ( & obligation. predicate ) {
402- return None ;
403- }
404- }
405-
406- Some ( PendingPredicateObligation {
407- obligation : obligation,
408- stalled_on : vec ! [ ]
409- } )
410- } )
411- . collect ( ) ;
412-
413- Ok ( Some ( pending_predicate_obligations) )
441+ impl < ' b , ' tcx > AncestorSet < ' b , ' tcx > {
442+ fn new ( backtrace : & Backtrace < ' b , PendingPredicateObligation < ' tcx > > ) -> Self {
443+ AncestorSet {
444+ populated : false ,
445+ cache : FnvHashMap ( ) ,
446+ backtrace : backtrace. clone ( ) ,
414447 }
415- Ok ( None ) => Ok ( None ) ,
416- Err ( e) => Err ( e)
417448 }
418- }
419449
450+ /// Checks whether any of the ancestors in the backtrace are equal
451+ /// to `predicate` (`predicate` is assumed to be fully
452+ /// type-resolved). Returns `None` if not; otherwise, returns
453+ /// `Some` with the index within the backtrace.
454+ fn has < ' a > ( & mut self ,
455+ infcx : & InferCtxt < ' a , ' tcx > ,
456+ predicate : & ty:: Predicate < ' tcx > )
457+ -> Option < usize > {
458+ // the first time, we have to populate the cache
459+ if !self . populated {
460+ let backtrace = self . backtrace . clone ( ) ;
461+ for ( index, ancestor) in backtrace. enumerate ( ) {
462+ // Ugh. This just feels ridiculously
463+ // inefficient. But we need to compare
464+ // predicates without being concerned about
465+ // the vagaries of type inference, so for now
466+ // just ensure that they are always
467+ // up-to-date. (I suppose we could just use a
468+ // snapshot and check if they are unifiable?)
469+ let resolved_predicate =
470+ infcx. resolve_type_vars_if_possible (
471+ & ancestor. obligation . predicate ) ;
472+
473+ // Though we try to avoid it, it can happen that a
474+ // cycle already exists in the predecessors. This
475+ // happens if the type variables were not fully known
476+ // at the time that the ancestors were pushed. We'll
477+ // just ignore such cycles for now, on the premise
478+ // that they will repeat themselves and we'll deal
479+ // with them properly then.
480+ self . cache . entry ( resolved_predicate)
481+ . or_insert ( index) ;
482+ }
483+ self . populated = true ;
484+ }
485+
486+ self . cache . get ( predicate) . cloned ( )
487+ }
488+ }
420489
421490/// Return the set of type variables contained in a trait ref
422491fn trait_ref_type_vars < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
@@ -438,7 +507,6 @@ fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>,
438507/// - `Err` if the predicate does not hold
439508fn process_predicate1 < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
440509 pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
441- backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
442510 region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
443511 -> Result < Option < Vec < PredicateObligation < ' tcx > > > ,
444512 FulfillmentErrorCode < ' tcx > >
@@ -461,16 +529,6 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
461529
462530 let obligation = & mut pending_obligation. obligation ;
463531
464- // If we exceed the recursion limit, take a moment to look for a
465- // cycle so we can give a better error report from here, where we
466- // have more context.
467- let recursion_limit = selcx. tcx ( ) . sess . recursion_limit . get ( ) ;
468- if obligation. recursion_depth >= recursion_limit {
469- if let Some ( cycle) = scan_for_cycle ( obligation, & backtrace) {
470- report_overflow_error_cycle ( selcx. infcx ( ) , & cycle) ;
471- }
472- }
473-
474532 if obligation. predicate . has_infer_types ( ) {
475533 obligation. predicate = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation. predicate ) ;
476534 }
@@ -481,10 +539,6 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
481539 return Ok ( Some ( vec ! [ ] ) ) ;
482540 }
483541
484- if coinductive_match ( selcx, obligation, data, & backtrace) {
485- return Ok ( Some ( vec ! [ ] ) ) ;
486- }
487-
488542 let trait_obligation = obligation. with ( data. clone ( ) ) ;
489543 match selcx. select ( & trait_obligation) {
490544 Ok ( Some ( vtable) ) => {
@@ -609,63 +663,40 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
609663
610664/// For defaulted traits, we use a co-inductive strategy to solve, so
611665/// that recursion is ok. This routine returns true if the top of the
612- /// stack (`top_obligation` and `top_data `):
666+ /// stack (`cycle[0] `):
613667/// - is a defaulted trait, and
614668/// - it also appears in the backtrace at some position `X`; and,
615669/// - all the predicates at positions `X..` between `X` an the top are
616670/// also defaulted traits.
617671fn coinductive_match < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
618- top_obligation : & PredicateObligation < ' tcx > ,
619- top_data : & ty:: PolyTraitPredicate < ' tcx > ,
620- backtrace : & Backtrace < PendingPredicateObligation < ' tcx > > )
672+ cycle : & [ PredicateObligation < ' tcx > ] )
621673 -> bool
622674{
623- if selcx. tcx ( ) . trait_has_default_impl ( top_data. def_id ( ) ) {
624- debug ! ( "coinductive_match: top_data={:?}" , top_data) ;
625- for bt_obligation in backtrace. clone ( ) {
626- debug ! ( "coinductive_match: bt_obligation={:?}" , bt_obligation) ;
627-
628- // *Everything* in the backtrace must be a defaulted trait.
629- match bt_obligation. obligation . predicate {
630- ty:: Predicate :: Trait ( ref data) => {
631- if !selcx. tcx ( ) . trait_has_default_impl ( data. def_id ( ) ) {
632- debug ! ( "coinductive_match: trait does not have default impl" ) ;
633- break ;
634- }
635- }
636- _ => { break ; }
637- }
638-
639- // And we must find a recursive match.
640- if bt_obligation. obligation . predicate == top_obligation. predicate {
641- debug ! ( "coinductive_match: found a match in the backtrace" ) ;
642- return true ;
643- }
644- }
645- }
646-
647- false
675+ let len = cycle. len ( ) ;
676+
677+ assert_eq ! ( cycle[ 0 ] . predicate, cycle[ len - 1 ] . predicate) ;
678+
679+ cycle[ 0 ..len-1 ]
680+ . iter ( )
681+ . all ( |bt_obligation| {
682+ let result = coinductive_obligation ( selcx, bt_obligation) ;
683+ debug ! ( "coinductive_match: bt_obligation={:?} coinductive={}" ,
684+ bt_obligation, result) ;
685+ result
686+ } )
648687}
649688
650- fn scan_for_cycle < ' a , ' tcx > ( top_obligation : & PredicateObligation < ' tcx > ,
651- backtrace : & Backtrace < PendingPredicateObligation < ' tcx > > )
652- -> Option < Vec < PredicateObligation < ' tcx > > >
653- {
654- let mut map = FnvHashMap ( ) ;
655- let all_obligations =
656- || iter:: once ( top_obligation)
657- . chain ( backtrace. clone ( )
658- . map ( |p| & p. obligation ) ) ;
659- for ( index, bt_obligation) in all_obligations ( ) . enumerate ( ) {
660- if let Some ( & start) = map. get ( & bt_obligation. predicate ) {
661- // Found a cycle starting at position `start` and running
662- // until the current position (`index`).
663- return Some ( all_obligations ( ) . skip ( start) . take ( index - start + 1 ) . cloned ( ) . collect ( ) ) ;
664- } else {
665- map. insert ( bt_obligation. predicate . clone ( ) , index) ;
689+ fn coinductive_obligation < ' a , ' tcx > ( selcx : & SelectionContext < ' a , ' tcx > ,
690+ obligation : & PredicateObligation < ' tcx > )
691+ -> bool {
692+ match obligation. predicate {
693+ ty:: Predicate :: Trait ( ref data) => {
694+ selcx. tcx ( ) . trait_has_default_impl ( data. def_id ( ) )
695+ }
696+ _ => {
697+ false
666698 }
667699 }
668- None
669700}
670701
671702fn register_region_obligation < ' tcx > ( t_a : Ty < ' tcx > ,
0 commit comments