@@ -5,6 +5,7 @@ use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
5
5
use std:: collections:: hash_map:: Entry ;
6
6
7
7
use uv_normalize:: { ExtraName , PackageName } ;
8
+ use uv_pypi_types:: Conflicts ;
8
9
9
10
use crate :: resolution:: ResolutionGraphNode ;
10
11
use crate :: universal_marker:: UniversalMarker ;
@@ -88,11 +89,21 @@ pub(crate) fn marker_reachability<T>(
88
89
/// For example, given an edge like `foo[x1] -> bar`, then it is known that
89
90
/// `x1` is activated. This in turn can be used to simplify any downstream
90
91
/// conflict markers with `extra == "x1"` in them.
91
- pub ( crate ) fn simplify_conflict_markers ( graph : & mut Graph < ResolutionGraphNode , UniversalMarker > ) {
92
+ pub ( crate ) fn simplify_conflict_markers (
93
+ conflicts : & Conflicts ,
94
+ graph : & mut Graph < ResolutionGraphNode , UniversalMarker > ,
95
+ ) {
96
+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
97
+ struct Inference {
98
+ package : PackageName ,
99
+ extra : ExtraName ,
100
+ included : bool ,
101
+ }
102
+
92
103
// The set of activated extras (and TODO, in the future, groups)
93
104
// for each node. The ROOT nodes don't have any extras activated.
94
- let mut activated: FxHashMap < NodeIndex , FxHashSet < ( PackageName , ExtraName ) > > =
95
- FxHashMap :: with_capacity_and_hasher ( graph . node_count ( ) , FxBuildHasher ) ;
105
+ let mut activated: FxHashMap < NodeIndex , Vec < FxHashSet < ( PackageName , ExtraName ) > > > =
106
+ FxHashMap :: default ( ) ;
96
107
97
108
// Collect the root nodes.
98
109
//
@@ -108,35 +119,101 @@ pub(crate) fn simplify_conflict_markers(graph: &mut Graph<ResolutionGraphNode, U
108
119
} )
109
120
. collect ( ) ;
110
121
111
- let mut assume_by_edge: FxHashMap < EdgeIndex , FxHashSet < ( PackageName , ExtraName ) > > =
112
- FxHashMap :: default ( ) ;
122
+ // let mut assume_by_edge: FxHashMap<EdgeIndex, FxHashSet<(PackageName, ExtraName)>> =
123
+ // FxHashMap::default();
113
124
let mut seen: FxHashSet < NodeIndex > = FxHashSet :: default ( ) ;
114
125
while let Some ( parent_index) = queue. pop ( ) {
115
- for child_edge in graph. edges_directed ( parent_index, Direction :: Outgoing ) {
116
- // TODO: The below seems excessively clone-y.
117
- // Consider tightening this up a bit.
118
- let target = child_edge. target ( ) ;
119
- let mut extras: FxHashSet < ( PackageName , ExtraName ) > =
120
- activated. get ( & parent_index) . cloned ( ) . unwrap_or_default ( ) ;
121
- if let Some ( ( package, extra) ) = graph[ parent_index] . package_extra_names ( ) {
122
- extras. insert ( ( package. clone ( ) , extra. clone ( ) ) ) ;
126
+ if let Some ( ( package, extra) ) = graph[ parent_index] . package_extra_names ( ) {
127
+ for set in activated
128
+ . entry ( parent_index)
129
+ . or_insert_with ( || vec ! [ FxHashSet :: default ( ) ] )
130
+ {
131
+ set. insert ( ( package. clone ( ) , extra. clone ( ) ) ) ;
123
132
}
124
- if let Some ( ( package, extra) ) = graph[ target] . package_extra_names ( ) {
125
- extras. insert ( ( package. clone ( ) , extra. clone ( ) ) ) ;
133
+ }
134
+ let sets = activated. get ( & parent_index) . cloned ( ) . unwrap_or_default ( ) ;
135
+ for child_edge in graph. edges_directed ( parent_index, Direction :: Outgoing ) {
136
+ for set in sets. clone ( ) {
137
+ activated. entry ( child_edge. target ( ) ) . or_default ( ) . push ( set) ;
126
138
}
127
- activated. entry ( target) . or_default ( ) . extend ( extras. clone ( ) ) ;
128
- assume_by_edge
129
- . entry ( child_edge. id ( ) )
130
- . or_default ( )
131
- . extend ( extras) ;
132
139
if seen. insert ( child_edge. target ( ) ) {
133
140
queue. push ( child_edge. target ( ) ) ;
134
141
}
135
142
}
136
143
}
137
- for ( edge_id, extras) in assume_by_edge {
138
- for & ( ref package, ref extra) in & extras {
139
- graph[ edge_id] . assume_extra ( package, extra) ;
144
+
145
+ let mut inferences: FxHashMap < NodeIndex , Vec < FxHashSet < Inference > > > = FxHashMap :: default ( ) ;
146
+ for ( node_id, sets) in activated {
147
+ let mut new_sets = vec ! [ ] ;
148
+ for set in sets {
149
+ let definitive_conflict = conflicts. iter ( ) . any ( |conflict_set| {
150
+ set. iter ( )
151
+ . filter ( |( package, extra) | conflict_set. contains ( package, extra) )
152
+ . count ( )
153
+ >= 2
154
+ } ) ;
155
+ if definitive_conflict {
156
+ continue ;
157
+ }
158
+
159
+ let mut new_set = FxHashSet :: default ( ) ;
160
+ for ( package, extra) in set {
161
+ for conflict_set in conflicts. iter ( ) {
162
+ if !conflict_set. contains ( & package, & extra) {
163
+ continue ;
164
+ }
165
+ for conflict_item in conflict_set. iter ( ) {
166
+ let Some ( conflict_item_extra) = conflict_item. extra ( ) else {
167
+ continue ;
168
+ } ;
169
+ if conflict_item. package ( ) == & package && conflict_item_extra == & extra {
170
+ continue ;
171
+ }
172
+ new_set. insert ( Inference {
173
+ package : conflict_item. package ( ) . clone ( ) ,
174
+ extra : conflict_item_extra. clone ( ) ,
175
+ included : false ,
176
+ } ) ;
177
+ }
178
+ }
179
+ new_set. insert ( Inference {
180
+ package,
181
+ extra,
182
+ included : true ,
183
+ } ) ;
184
+ }
185
+ new_sets. push ( new_set) ;
186
+ }
187
+ inferences. insert ( node_id, new_sets) ;
188
+ }
189
+
190
+ for edge_index in ( 0 ..graph. edge_count ( ) ) . map ( EdgeIndex :: new) {
191
+ let ( from_index, _) = graph. edge_endpoints ( edge_index) . unwrap ( ) ;
192
+ let Some ( inference) = inferences. get ( & from_index) else {
193
+ continue ;
194
+ } ;
195
+ let all_paths_satisfied = inference. iter ( ) . all ( |set| {
196
+ let extras = set
197
+ . iter ( )
198
+ . filter_map ( |inf| {
199
+ if !inf. included {
200
+ return None ;
201
+ }
202
+ Some ( ( inf. package . clone ( ) , inf. extra . clone ( ) ) )
203
+ } )
204
+ . collect :: < Vec < ( PackageName , ExtraName ) > > ( ) ;
205
+ graph[ edge_index] . conflict ( ) . evaluate ( & extras)
206
+ } ) ;
207
+ if all_paths_satisfied {
208
+ for set in inference {
209
+ for inf in set {
210
+ if inf. included {
211
+ graph[ edge_index] . assume_extra ( & inf. package , & inf. extra ) ;
212
+ } else {
213
+ graph[ edge_index] . assume_not_extra ( & inf. package , & inf. extra ) ;
214
+ }
215
+ }
216
+ }
140
217
}
141
218
}
142
219
}
0 commit comments