13
13
/// behavior as long as the resulting behavior is still correct.
14
14
use std:: cmp:: Ordering ;
15
15
use std:: collections:: BTreeMap ;
16
+ use std:: collections:: hash_map:: Entry ;
16
17
use std:: fmt:: Debug ;
17
18
use std:: hash:: Hash ;
18
19
use std:: marker:: PhantomData ;
19
20
20
21
use derive_where:: derive_where;
21
22
use rustc_index:: { Idx , IndexVec } ;
23
+ #[ cfg( feature = "nightly" ) ]
24
+ use rustc_macros:: { HashStable_NoContext , TyDecodable , TyEncodable } ;
22
25
use tracing:: debug;
23
26
24
27
use crate :: data_structures:: HashMap ;
@@ -109,20 +112,29 @@ pub trait Delegate {
109
112
/// In the initial iteration of a cycle, we do not yet have a provisional
110
113
/// result. In the case we return an initial provisional result depending
111
114
/// on the kind of cycle.
112
- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
115
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
116
+ #[ cfg_attr( feature = "nightly" , derive( TyDecodable , TyEncodable , HashStable_NoContext ) ) ]
113
117
pub enum PathKind {
114
- Coinductive ,
118
+ /// A path consisting of only inductive/unproductive steps.
115
119
Inductive ,
120
+ /// A path which is not be coinductive right now but we may want
121
+ /// to change of them to be so in the future. We return an ambiguous
122
+ /// result in this case to prevent people from relying on this.
123
+ Unknown ,
124
+ /// A path with at least one coinductive step. Such cycles hold.
125
+ Coinductive ,
116
126
}
127
+
117
128
impl PathKind {
118
129
/// Returns the path kind when merging `self` with `rest`.
119
130
///
120
131
/// Given an inductive path `self` and a coinductive path `rest`,
121
132
/// the path `self -> rest` would be coinductive.
122
133
fn extend ( self , rest : PathKind ) -> PathKind {
123
- match self {
124
- PathKind :: Coinductive => PathKind :: Coinductive ,
125
- PathKind :: Inductive => rest,
134
+ match ( self , rest) {
135
+ ( PathKind :: Coinductive , _) | ( _, PathKind :: Coinductive ) => PathKind :: Coinductive ,
136
+ ( PathKind :: Unknown , _) | ( _, PathKind :: Unknown ) => PathKind :: Unknown ,
137
+ ( PathKind :: Inductive , PathKind :: Inductive ) => PathKind :: Inductive ,
126
138
}
127
139
}
128
140
}
@@ -156,9 +168,6 @@ impl UsageKind {
156
168
}
157
169
}
158
170
}
159
- fn and_merge ( & mut self , other : impl Into < Self > ) {
160
- * self = self . merge ( other) ;
161
- }
162
171
}
163
172
164
173
/// For each goal we track whether the paths from this goal
@@ -294,14 +303,68 @@ impl CycleHeads {
294
303
295
304
let path_from_entry = match step_kind {
296
305
PathKind :: Coinductive => AllPathsToHeadCoinductive :: Yes ,
297
- PathKind :: Inductive => path_from_entry,
306
+ PathKind :: Unknown | PathKind :: Inductive => path_from_entry,
298
307
} ;
299
308
300
309
self . insert ( head, path_from_entry) ;
301
310
}
302
311
}
303
312
}
304
313
314
+ bitflags:: bitflags! {
315
+ /// Tracks how nested goals have been accessed. This is necessary to disable
316
+ /// global cache entries if computing them would otherwise result in a cycle or
317
+ /// access a provisional cache entry.
318
+ #[ derive( Debug , Clone , Copy ) ]
319
+ pub struct PathsToNested : u8 {
320
+ /// The initial value when adding a goal to its own nested goals.
321
+ const EMPTY = 1 << 0 ;
322
+ const INDUCTIVE = 1 << 1 ;
323
+ const UNKNOWN = 1 << 2 ;
324
+ const COINDUCTIVE = 1 << 3 ;
325
+ }
326
+ }
327
+ impl From < PathKind > for PathsToNested {
328
+ fn from ( path : PathKind ) -> PathsToNested {
329
+ match path {
330
+ PathKind :: Inductive => PathsToNested :: INDUCTIVE ,
331
+ PathKind :: Unknown => PathsToNested :: UNKNOWN ,
332
+ PathKind :: Coinductive => PathsToNested :: COINDUCTIVE ,
333
+ }
334
+ }
335
+ }
336
+ impl PathsToNested {
337
+ #[ must_use]
338
+ fn extend_with ( mut self , path : PathKind ) -> Self {
339
+ match path {
340
+ PathKind :: Inductive => {
341
+ if self . intersects ( PathsToNested :: EMPTY ) {
342
+ self . remove ( PathsToNested :: EMPTY ) ;
343
+ self . insert ( PathsToNested :: INDUCTIVE ) ;
344
+ }
345
+ }
346
+ PathKind :: Unknown => {
347
+ if self . intersects ( PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE ) {
348
+ self . remove ( PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE ) ;
349
+ self . insert ( PathsToNested :: UNKNOWN ) ;
350
+ }
351
+ }
352
+ PathKind :: Coinductive => {
353
+ if self . intersects (
354
+ PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE | PathsToNested :: UNKNOWN ,
355
+ ) {
356
+ self . remove (
357
+ PathsToNested :: EMPTY | PathsToNested :: INDUCTIVE | PathsToNested :: UNKNOWN ,
358
+ ) ;
359
+ self . insert ( PathsToNested :: COINDUCTIVE ) ;
360
+ }
361
+ }
362
+ }
363
+
364
+ self
365
+ }
366
+ }
367
+
305
368
/// The nested goals of each stack entry and the path from the
306
369
/// stack entry to that nested goal.
307
370
///
@@ -319,15 +382,18 @@ impl CycleHeads {
319
382
/// results from a the cycle BAB depending on the cycle root.
320
383
#[ derive_where( Debug , Default , Clone ; X : Cx ) ]
321
384
struct NestedGoals < X : Cx > {
322
- nested_goals : HashMap < X :: Input , UsageKind > ,
385
+ nested_goals : HashMap < X :: Input , PathsToNested > ,
323
386
}
324
387
impl < X : Cx > NestedGoals < X > {
325
388
fn is_empty ( & self ) -> bool {
326
389
self . nested_goals . is_empty ( )
327
390
}
328
391
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) ;
392
+ fn insert ( & mut self , input : X :: Input , paths_to_nested : PathsToNested ) {
393
+ match self . nested_goals . entry ( input) {
394
+ Entry :: Occupied ( mut entry) => * entry. get_mut ( ) |= paths_to_nested,
395
+ Entry :: Vacant ( entry) => drop ( entry. insert ( paths_to_nested) ) ,
396
+ }
331
397
}
332
398
333
399
/// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
@@ -338,18 +404,15 @@ impl<X: Cx> NestedGoals<X> {
338
404
/// the same as for the child.
339
405
fn extend_from_child ( & mut self , step_kind : PathKind , nested_goals : & NestedGoals < X > ) {
340
406
#[ 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) ;
407
+ for ( input, paths_to_nested) in nested_goals. iter ( ) {
408
+ let paths_to_nested = paths_to_nested. extend_with ( step_kind) ;
409
+ self . insert ( input, paths_to_nested) ;
347
410
}
348
411
}
349
412
350
413
#[ cfg_attr( feature = "nightly" , rustc_lint_query_instability) ]
351
414
#[ allow( rustc:: potential_query_instability) ]
352
- fn iter ( & self ) -> impl Iterator < Item = ( X :: Input , UsageKind ) > + ' _ {
415
+ fn iter ( & self ) -> impl Iterator < Item = ( X :: Input , PathsToNested ) > + ' _ {
353
416
self . nested_goals . iter ( ) . map ( |( i, p) | ( * i, * p) )
354
417
}
355
418
@@ -487,7 +550,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
487
550
// goals as this change may cause them to now depend on additional
488
551
// goals, resulting in new cycles. See the dev-guide for examples.
489
552
if parent_depends_on_cycle {
490
- parent. nested_goals . insert ( parent. input , UsageKind :: Single ( PathKind :: Inductive ) )
553
+ parent. nested_goals . insert ( parent. input , PathsToNested :: EMPTY ) ;
491
554
}
492
555
}
493
556
}
@@ -663,7 +726,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
663
726
//
664
727
// We must therefore not use the global cache entry for `B` in that case.
665
728
// See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
666
- last. nested_goals . insert ( last. input , UsageKind :: Single ( PathKind :: Inductive ) ) ;
729
+ last. nested_goals . insert ( last. input , PathsToNested :: EMPTY ) ;
667
730
}
668
731
669
732
debug ! ( "encountered stack overflow" ) ;
@@ -745,16 +808,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
745
808
746
809
// We now care about the path from the next highest cycle head to the
747
810
// 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
- }
811
+ * path_from_head = path_from_head. extend ( Self :: cycle_path_kind (
812
+ & self . stack ,
813
+ stack_entry. step_kind_from_parent ,
814
+ head,
815
+ ) ) ;
758
816
// Mutate the result of the provisional cache entry in case we did
759
817
// not reach a fixpoint.
760
818
* result = mutate_result ( input, * result) ;
@@ -854,7 +912,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
854
912
for & ProvisionalCacheEntry {
855
913
encountered_overflow,
856
914
ref heads,
857
- path_from_head,
915
+ path_from_head : head_to_provisional ,
858
916
result : _,
859
917
} in entries. iter ( )
860
918
{
@@ -866,24 +924,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
866
924
867
925
// A provisional cache entry only applies if the path from its highest head
868
926
// matches the path when encountering the goal.
927
+ //
928
+ // We check if any of the paths taken while computing the global goal
929
+ // would end up with an applicable provisional cache entry.
869
930
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" ) ,
931
+ let head_to_curr = Self :: cycle_path_kind ( stack, step_kind_from_parent, head) ;
932
+ let full_paths = path_from_global_entry. extend_with ( head_to_curr) ;
933
+ if full_paths. contains ( head_to_provisional. into ( ) ) {
934
+ debug ! (
935
+ ?full_paths,
936
+ ?head_to_provisional,
937
+ "cache entry not applicable due to matching paths"
938
+ ) ;
939
+ return false ;
887
940
}
888
941
}
889
942
}
@@ -982,8 +1035,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
982
1035
let last = & mut self . stack [ last_index] ;
983
1036
last. reached_depth = last. reached_depth . max ( next_index) ;
984
1037
985
- last. nested_goals . insert ( input, UsageKind :: Single ( step_kind_from_parent) ) ;
986
- last. nested_goals . insert ( last. input , UsageKind :: Single ( PathKind :: Inductive ) ) ;
1038
+ last. nested_goals . insert ( input, step_kind_from_parent. into ( ) ) ;
1039
+ last. nested_goals . insert ( last. input , PathsToNested :: EMPTY ) ;
987
1040
if last_index != head {
988
1041
last. heads . insert ( head, step_kind_from_parent) ;
989
1042
}
0 commit comments