1313/// behavior as long as the resulting behavior is still correct.
1414use std:: cmp:: Ordering ;
1515use std:: collections:: BTreeMap ;
16+ use std:: collections:: hash_map:: Entry ;
1617use std:: fmt:: Debug ;
1718use std:: hash:: Hash ;
1819use std:: marker:: PhantomData ;
@@ -111,18 +112,26 @@ pub trait Delegate {
111112/// on the kind of cycle.
112113#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
113114pub enum PathKind {
114- Coinductive ,
115+ /// A path consisting of only inductive/unproductive steps.
115116 Inductive ,
117+ /// A path which is not be coinductive right now but we may want
118+ /// to change of them to be so in the future. We return an ambiguous
119+ /// result in this case to prevent people from relying on this.
120+ Unknown ,
121+ /// A path with at least one coinductive step. Such cycles hold.
122+ Coinductive ,
116123}
124+
117125impl PathKind {
118126 /// Returns the path kind when merging `self` with `rest`.
119127 ///
120128 /// Given an inductive path `self` and a coinductive path `rest`,
121129 /// the path `self -> rest` would be coinductive.
122130 fn extend ( self , rest : PathKind ) -> PathKind {
123- match self {
124- PathKind :: Coinductive => PathKind :: Coinductive ,
125- PathKind :: Inductive => rest,
131+ match ( self , rest) {
132+ ( PathKind :: Coinductive , _) | ( _, PathKind :: Coinductive ) => PathKind :: Coinductive ,
133+ ( PathKind :: Unknown , _) | ( _, PathKind :: Unknown ) => PathKind :: Unknown ,
134+ ( PathKind :: Inductive , PathKind :: Inductive ) => PathKind :: Inductive ,
126135 }
127136 }
128137}
@@ -156,9 +165,6 @@ impl UsageKind {
156165 }
157166 }
158167 }
159- fn and_merge ( & mut self , other : impl Into < Self > ) {
160- * self = self . merge ( other) ;
161- }
162168}
163169
164170/// For each goal we track whether the paths from this goal
@@ -294,14 +300,68 @@ impl CycleHeads {
294300
295301 let path_from_entry = match step_kind {
296302 PathKind :: Coinductive => AllPathsToHeadCoinductive :: Yes ,
297- PathKind :: Inductive => path_from_entry,
303+ PathKind :: Unknown | PathKind :: Inductive => path_from_entry,
298304 } ;
299305
300306 self . insert ( head, path_from_entry) ;
301307 }
302308 }
303309}
304310
311+ bitflags:: bitflags! {
312+ /// Tracks how nested goals have been accessed. This is necessary to disable
313+ /// global cache entries if computing them would otherwise result in a cycle or
314+ /// access a provisional cache entry.
315+ #[ derive( Debug , Clone , Copy ) ]
316+ pub struct PathsToNested : u8 {
317+ /// The initial value when adding a goal to its own nested goals.
318+ const EMPTY = 1 << 0 ;
319+ const INDUCTIVE = 1 << 1 ;
320+ const UNKNOWN = 1 << 2 ;
321+ const COINDUCTIVE = 1 << 3 ;
322+ }
323+ }
324+ impl From < PathKind > for PathsToNested {
325+ fn from ( path : PathKind ) -> PathsToNested {
326+ match path {
327+ PathKind :: Inductive => PathsToNested :: INDUCTIVE ,
328+ PathKind :: Unknown => PathsToNested :: UNKNOWN ,
329+ PathKind :: Coinductive => PathsToNested :: COINDUCTIVE ,
330+ }
331+ }
332+ }
333+ impl PathsToNested {
334+ #[ must_use]
335+ fn extend_with ( mut self , path : PathKind ) -> Self {
336+ match path {
337+ PathKind :: Inductive => {
338+ if self . intersects ( PathsToNested :: EMPTY ) {
339+ self . remove ( PathsToNested :: EMPTY ) ;
340+ self . insert ( PathsToNested :: INDUCTIVE ) ;
341+ }
342+ }
343+ PathKind :: Unknown => {
344+ if self . intersects ( PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE ) {
345+ self . remove ( PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE ) ;
346+ self . insert ( PathsToNested :: UNKNOWN ) ;
347+ }
348+ }
349+ PathKind :: Coinductive => {
350+ if self . intersects (
351+ PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE | PathsToNested :: UNKNOWN ,
352+ ) {
353+ self . remove (
354+ PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE | PathsToNested :: UNKNOWN ,
355+ ) ;
356+ self . insert ( PathsToNested :: COINDUCTIVE ) ;
357+ }
358+ }
359+ }
360+
361+ self
362+ }
363+ }
364+
305365/// The nested goals of each stack entry and the path from the
306366/// stack entry to that nested goal.
307367///
@@ -319,15 +379,18 @@ impl CycleHeads {
319379/// results from a the cycle BAB depending on the cycle root.
320380#[ derive_where( Debug , Default , Clone ; X : Cx ) ]
321381struct NestedGoals < X : Cx > {
322- nested_goals : HashMap < X :: Input , UsageKind > ,
382+ nested_goals : HashMap < X :: Input , PathsToNested > ,
323383}
324384impl < X : Cx > NestedGoals < X > {
325385 fn is_empty ( & self ) -> bool {
326386 self . nested_goals . is_empty ( )
327387 }
328388
329- fn insert ( & mut self , input : X :: Input , path_from_entry : UsageKind ) {
330- self . nested_goals . entry ( input) . or_insert ( path_from_entry) . and_merge ( path_from_entry) ;
389+ fn insert ( & mut self , input : X :: Input , paths_to_nested : PathsToNested ) {
390+ match self . nested_goals . entry ( input) {
391+ Entry :: Occupied ( mut entry) => * entry. get_mut ( ) |= paths_to_nested,
392+ Entry :: Vacant ( entry) => drop ( entry. insert ( paths_to_nested) ) ,
393+ }
331394 }
332395
333396 /// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
@@ -338,18 +401,15 @@ impl<X: Cx> NestedGoals<X> {
338401 /// the same as for the child.
339402 fn extend_from_child ( & mut self , step_kind : PathKind , nested_goals : & NestedGoals < X > ) {
340403 #[ allow( rustc:: potential_query_instability) ]
341- for ( input, path_from_entry) in nested_goals. iter ( ) {
342- let path_from_entry = match step_kind {
343- PathKind :: Coinductive => UsageKind :: Single ( PathKind :: Coinductive ) ,
344- PathKind :: Inductive => path_from_entry,
345- } ;
346- self . insert ( input, path_from_entry) ;
404+ for ( input, paths_to_nested) in nested_goals. iter ( ) {
405+ let paths_to_nested = paths_to_nested. extend_with ( step_kind) ;
406+ self . insert ( input, paths_to_nested) ;
347407 }
348408 }
349409
350410 #[ cfg_attr( feature = "nightly" , rustc_lint_query_instability) ]
351411 #[ allow( rustc:: potential_query_instability) ]
352- fn iter ( & self ) -> impl Iterator < Item = ( X :: Input , UsageKind ) > + ' _ {
412+ fn iter ( & self ) -> impl Iterator < Item = ( X :: Input , PathsToNested ) > + ' _ {
353413 self . nested_goals . iter ( ) . map ( |( i, p) | ( * i, * p) )
354414 }
355415
@@ -487,7 +547,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
487547 // goals as this change may cause them to now depend on additional
488548 // goals, resulting in new cycles. See the dev-guide for examples.
489549 if parent_depends_on_cycle {
490- parent. nested_goals . insert ( parent. input , UsageKind :: Single ( PathKind :: Inductive ) )
550+ parent. nested_goals . insert ( parent. input , PathsToNested :: EMPTY ) ;
491551 }
492552 }
493553 }
@@ -663,7 +723,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
663723 //
664724 // We must therefore not use the global cache entry for `B` in that case.
665725 // See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
666- last. nested_goals . insert ( last. input , UsageKind :: Single ( PathKind :: Inductive ) ) ;
726+ last. nested_goals . insert ( last. input , PathsToNested :: EMPTY ) ;
667727 }
668728
669729 debug ! ( "encountered stack overflow" ) ;
@@ -745,16 +805,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
745805
746806 // We now care about the path from the next highest cycle head to the
747807 // provisional cache entry.
748- match path_from_head {
749- PathKind :: Coinductive => { }
750- PathKind :: Inductive => {
751- * path_from_head = Self :: cycle_path_kind (
752- & self . stack ,
753- stack_entry. step_kind_from_parent ,
754- head,
755- )
756- }
757- }
808+ * path_from_head = path_from_head. extend ( Self :: cycle_path_kind (
809+ & self . stack ,
810+ stack_entry. step_kind_from_parent ,
811+ head,
812+ ) ) ;
758813 // Mutate the result of the provisional cache entry in case we did
759814 // not reach a fixpoint.
760815 * result = mutate_result ( input, * result) ;
@@ -854,7 +909,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
854909 for & ProvisionalCacheEntry {
855910 encountered_overflow,
856911 ref heads,
857- path_from_head,
912+ path_from_head : head_to_provisional ,
858913 result : _,
859914 } in entries. iter ( )
860915 {
@@ -866,24 +921,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
866921
867922 // A provisional cache entry only applies if the path from its highest head
868923 // matches the path when encountering the goal.
924+ //
925+ // We check if any of the paths taken while computing the global goal
926+ // would end up with an applicable provisional cache entry.
869927 let head = heads. highest_cycle_head ( ) ;
870- let full_path = match Self :: cycle_path_kind ( stack, step_kind_from_parent, head) {
871- PathKind :: Coinductive => UsageKind :: Single ( PathKind :: Coinductive ) ,
872- PathKind :: Inductive => path_from_global_entry,
873- } ;
874-
875- match ( full_path, path_from_head) {
876- ( UsageKind :: Mixed , _)
877- | ( UsageKind :: Single ( PathKind :: Coinductive ) , PathKind :: Coinductive )
878- | ( UsageKind :: Single ( PathKind :: Inductive ) , PathKind :: Inductive ) => {
879- debug ! (
880- ?full_path,
881- ?path_from_head,
882- "cache entry not applicable due to matching paths"
883- ) ;
884- return false ;
885- }
886- _ => debug ! ( ?full_path, ?path_from_head, "paths don't match" ) ,
928+ let head_to_curr = Self :: cycle_path_kind ( stack, step_kind_from_parent, head) ;
929+ let full_paths = path_from_global_entry. extend_with ( head_to_curr) ;
930+ if full_paths. contains ( head_to_provisional. into ( ) ) {
931+ debug ! (
932+ ?full_paths,
933+ ?head_to_provisional,
934+ "cache entry not applicable due to matching paths"
935+ ) ;
936+ return false ;
887937 }
888938 }
889939 }
@@ -982,8 +1032,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
9821032 let last = & mut self . stack [ last_index] ;
9831033 last. reached_depth = last. reached_depth . max ( next_index) ;
9841034
985- last. nested_goals . insert ( input, UsageKind :: Single ( step_kind_from_parent) ) ;
986- last. nested_goals . insert ( last. input , UsageKind :: Single ( PathKind :: Inductive ) ) ;
1035+ last. nested_goals . insert ( input, step_kind_from_parent. into ( ) ) ;
1036+ last. nested_goals . insert ( last. input , PathsToNested :: EMPTY ) ;
9871037 if last_index != head {
9881038 last. heads . insert ( head, step_kind_from_parent) ;
9891039 }
0 commit comments