1
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
1
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap , FxIndexSet } ;
2
2
use rustc_index:: { Idx , IndexVec } ;
3
3
use std:: cell:: RefCell ;
4
4
use std:: collections:: { BTreeMap , BTreeSet } ;
@@ -23,10 +23,9 @@ pub struct DedupSolver {
23
23
/// The cliques that constraints are partitioned into. Constraints can only be merged if they belong to the same clique,
24
24
/// and it's impossible for a constraint to be in more than one clique
25
25
constraint_cliques : IndexVec < CliqueIndex , Vec < ConstraintIndex > > ,
26
- /// A set of variables we cannot remove, i.e. they belong to a universe that the caller can name. We keep track of these
27
- /// to determine if there's a variable that we **can** remove that behaves like one of these, where in that case we just
28
- /// remove the unremovable var and keep the removable ones
29
- unremovable_vars : FxIndexSet < VarIndex > ,
26
+ /// The universes each var resides in. This is used because deduping prioritizes the removal of constraints
27
+ /// that involve the highest universe indices
28
+ var_universes : FxHashMap < VarIndex , usize > ,
30
29
31
30
/// The below are internal variables used in the solving process:
32
31
@@ -58,23 +57,17 @@ struct MappingInfo {
58
57
/// a preexisting constraint. Therefore, the two constraints depend on each other
59
58
dependencies : FxIndexMap < ConstraintIndex , BTreeSet < MappingIndex > > ,
60
59
}
61
- #[ derive( Debug , PartialEq , Eq ) ]
62
- enum MapEval {
63
- Ok ( MappingInfo ) ,
64
- Conflicts ,
65
- Unremovable ,
66
- }
67
60
68
61
impl DedupSolver {
69
62
pub fn dedup (
70
63
constraint_vars : IndexVec < ConstraintIndex , Vec < VarIndex > > ,
71
64
constraint_cliques : IndexVec < CliqueIndex , Vec < ConstraintIndex > > ,
72
- unremovable_vars : FxIndexSet < VarIndex > ,
65
+ var_universes : FxHashMap < VarIndex , usize > ,
73
66
) -> DedupResult {
74
67
let mut deduper = Self {
75
68
constraint_vars,
76
69
constraint_cliques,
77
- unremovable_vars ,
70
+ var_universes ,
78
71
79
72
mappings : FxIndexMap :: default ( ) ,
80
73
removed_constraints : RefCell :: new ( FxIndexSet :: default ( ) ) ,
@@ -122,18 +115,20 @@ impl DedupSolver {
122
115
// map the constraint [1] into [11], which is a constraint that doesn't exist
123
116
let ( eval_forward, eval_reverse) =
124
117
( self . eval_mapping ( & forward) , self . eval_mapping ( & reverse) ) ;
125
- if eval_forward == MapEval :: Conflicts || eval_reverse == MapEval :: Conflicts {
118
+ let ( Ok ( eval_forward) , Ok ( eval_reverse ) ) = ( eval_forward , eval_reverse) else {
126
119
continue ;
127
- }
128
- if let MapEval :: Ok ( eval_forward) = eval_forward {
129
- if self . try_apply_mapping ( & forward, & eval_forward, false ) == Err ( true ) {
130
- self . mappings . insert ( forward, eval_forward) ;
131
- }
132
- }
133
- if let MapEval :: Ok ( eval_reverse) = eval_reverse {
134
- if self . try_apply_mapping ( & reverse, & eval_reverse, false ) == Err ( true ) {
135
- self . mappings . insert ( reverse, eval_reverse) ;
136
- }
120
+ } ;
121
+
122
+ let max_forward_universe = forward. max_removed_universe ( & self . var_universes ) ;
123
+ let max_reverse_universe = reverse. max_removed_universe ( & self . var_universes ) ;
124
+ let ( chosen_mapping, chosen_eval) =
125
+ if max_forward_universe >= max_reverse_universe {
126
+ ( forward, eval_forward)
127
+ } else {
128
+ ( reverse, eval_reverse)
129
+ } ;
130
+ if self . try_apply_mapping ( & chosen_mapping, & chosen_eval, false ) == Err ( true ) {
131
+ self . mappings . insert ( chosen_mapping, chosen_eval) ;
137
132
}
138
133
}
139
134
}
@@ -146,10 +141,7 @@ impl DedupSolver {
146
141
/// MappingInfo can contain dependencies - these occur if a mapping *partially* maps
147
142
/// a constraint onto another, so the mapping isn't immediately invalid, but we do need
148
143
/// another mapping to complete that partial map for it to actually be valid
149
- fn eval_mapping ( & self , mapping : & Mapping ) -> MapEval {
150
- let maps_unremovable_var =
151
- mapping. 0 . iter ( ) . any ( |( from, to) | self . unremovable_vars . contains ( from) && from != to) ;
152
-
144
+ fn eval_mapping ( & self , mapping : & Mapping ) -> Result < MappingInfo , ( ) > {
153
145
let mut info = MappingInfo :: new ( ) ;
154
146
for clique in self . constraint_cliques . iter ( ) {
155
147
for constraint_1 in clique {
@@ -179,14 +171,11 @@ impl DedupSolver {
179
171
}
180
172
}
181
173
if !found_non_conflicting {
182
- return MapEval :: Conflicts ;
174
+ return Err ( ( ) ) ;
183
175
}
184
176
}
185
177
}
186
- if maps_unremovable_var {
187
- return MapEval :: Unremovable ;
188
- }
189
- MapEval :: Ok ( info)
178
+ Ok ( info)
190
179
}
191
180
/// Currently, dependencies are in the form FxIndexMap<ConstraintIndex, Empty FxIndexSet>,
192
181
/// where ConstraintIndex is the constraint we must *also* map in order to apply this mapping.
@@ -294,9 +283,6 @@ impl DedupSolver {
294
283
// If we already applied a mapping, we now remove it from `from`, as its dependencies have
295
284
// been resolved and therefore we don't need to worry about it
296
285
from. retain ( |x| !used_mappings. contains ( x) ) ;
297
- if from. is_empty ( ) {
298
- return Some ( used_mappings) ;
299
- }
300
286
used_mappings. extend ( from. iter ( ) ) ;
301
287
302
288
// For each unresolved dependency, we have a list of Mappings that can resolve it
@@ -314,6 +300,9 @@ impl DedupSolver {
314
300
} ) ;
315
301
unresolved_dependencies. extend ( resolve_options) ;
316
302
}
303
+ if unresolved_dependencies. is_empty ( ) {
304
+ return Some ( used_mappings) ;
305
+ }
317
306
if unresolved_dependencies. iter ( ) . any ( |x| x. is_empty ( ) ) {
318
307
return None ;
319
308
}
@@ -430,6 +419,9 @@ impl Mapping {
430
419
}
431
420
false
432
421
}
422
+ fn max_removed_universe ( & self , var_universes : & FxHashMap < VarIndex , usize > ) -> usize {
423
+ self . 0 . keys ( ) . map ( |x| * var_universes. get ( x) . unwrap ( ) ) . max ( ) . unwrap_or ( 0 )
424
+ }
433
425
}
434
426
impl MappingInfo {
435
427
fn new ( ) -> Self {
0 commit comments