3
3
//! An incompatibility is a set of terms for different packages
4
4
//! that should never be satisfied all together.
5
5
6
- use std:: fmt;
6
+ use std:: fmt:: { self , Debug , Display } ;
7
7
use std:: sync:: Arc ;
8
8
9
9
use crate :: internal:: arena:: { Arena , Id } ;
@@ -32,26 +32,44 @@ use crate::version_set::VersionSet;
32
32
/// during conflict resolution. More about all this in
33
33
/// [PubGrub documentation](https://github.com/dart-lang/pub/blob/master/doc/solver.md#incompatibility).
34
34
#[ derive( Debug , Clone ) ]
35
- pub struct Incompatibility < P : Package , VS : VersionSet > {
35
+ pub struct Incompatibility < P : Package , VS : VersionSet , M : Eq + Clone + Debug + Display > {
36
36
package_terms : SmallMap < P , Term < VS > > ,
37
- kind : Kind < P , VS > ,
37
+ kind : Kind < P , VS , M > ,
38
38
}
39
39
40
40
/// Type alias of unique identifiers for incompatibilities.
41
- pub type IncompId < P , VS > = Id < Incompatibility < P , VS > > ;
41
+ pub type IncompId < P , VS , M > = Id < Incompatibility < P , VS , M > > ;
42
42
43
43
#[ derive( Debug , Clone ) ]
44
- enum Kind < P : Package , VS : VersionSet > {
44
+ enum Kind < P : Package , VS : VersionSet , M : Eq + Clone + Debug + Display > {
45
45
/// Initial incompatibility aiming at picking the root package for the first decision.
46
+ ///
47
+ /// This incompatibility drives the resolution, it requires that we pick the (virtual) root
48
+ /// packages.
46
49
NotRoot ( P , VS :: V ) ,
47
50
/// There are no versions in the given range for this package.
51
+ ///
52
+ /// This incompatibility is used when we tried all versions in a range and no version
53
+ /// worked, so we have to backtrack
48
54
NoVersions ( P , VS ) ,
49
- /// Dependencies of the package are unavailable for versions in that range.
50
- UnavailableDependencies ( P , VS ) ,
51
55
/// Incompatibility coming from the dependencies of a given package.
56
+ ///
57
+ /// If a@1 depends on b>=1,<2, we create an incompatibility with terms `{a 1, b <1,>=2}` with
58
+ /// kind `FromDependencyOf(a, 1, b, >=1,<2)`.
59
+ ///
60
+ /// We can merge multiple dependents with the same version. For example, if a@1 depends on b and
61
+ /// a@2 depends on b, we can say instead a@1||2 depends on b.
52
62
FromDependencyOf ( P , VS , P , VS ) ,
53
63
/// Derived from two causes. Stores cause ids.
54
- DerivedFrom ( IncompId < P , VS > , IncompId < P , VS > ) ,
64
+ ///
65
+ /// For example, if a -> b and b -> c, we can derive a -> c.
66
+ DerivedFrom ( IncompId < P , VS , M > , IncompId < P , VS , M > ) ,
67
+ /// The package is unavailable for reasons outside pubgrub.
68
+ ///
69
+ /// Examples:
70
+ /// * The version would require building the package, but builds are disabled.
71
+ /// * The package is not available in the cache, but internet access has been disabled.
72
+ Custom ( P , VS , M ) ,
55
73
}
56
74
57
75
/// A Relation describes how a set of terms can be compared to an incompatibility.
@@ -71,7 +89,7 @@ pub enum Relation<P: Package> {
71
89
Inconclusive ,
72
90
}
73
91
74
- impl < P : Package , VS : VersionSet > Incompatibility < P , VS > {
92
+ impl < P : Package , VS : VersionSet , M : Eq + Clone + Debug + Display > Incompatibility < P , VS , M > {
75
93
/// Create the initial "not Root" incompatibility.
76
94
pub fn not_root ( package : P , version : VS :: V ) -> Self {
77
95
Self {
@@ -83,8 +101,7 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
83
101
}
84
102
}
85
103
86
- /// Create an incompatibility to remember
87
- /// that a given set does not contain any version.
104
+ /// Create an incompatibility to remember that a given set does not contain any version.
88
105
pub fn no_versions ( package : P , term : Term < VS > ) -> Self {
89
106
let set = match & term {
90
107
Term :: Positive ( r) => r. clone ( ) ,
@@ -96,14 +113,26 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
96
113
}
97
114
}
98
115
99
- /// Create an incompatibility to remember
100
- /// that a package version is not selectable
101
- /// because its list of dependencies is unavailable.
102
- pub fn unavailable_dependencies ( package : P , version : VS :: V ) -> Self {
116
+ /// Create an incompatibility for a reason outside pubgrub.
117
+ #[ allow( dead_code) ] // Used by uv
118
+ pub fn custom_term ( package : P , term : Term < VS > , metadata : M ) -> Self {
119
+ let set = match & term {
120
+ Term :: Positive ( r) => r. clone ( ) ,
121
+ Term :: Negative ( _) => panic ! ( "No version should have a positive term" ) ,
122
+ } ;
123
+ Self {
124
+ package_terms : SmallMap :: One ( [ ( package. clone ( ) , term) ] ) ,
125
+ kind : Kind :: Custom ( package, set, metadata) ,
126
+ }
127
+ }
128
+
129
+ /// Create an incompatibility for a reason outside pubgrub.
130
+ pub fn custom_version ( package : P , version : VS :: V , metadata : M ) -> Self {
103
131
let set = VS :: singleton ( version) ;
132
+ let term = Term :: Positive ( set. clone ( ) ) ;
104
133
Self {
105
- package_terms : SmallMap :: One ( [ ( package. clone ( ) , Term :: Positive ( set . clone ( ) ) ) ] ) ,
106
- kind : Kind :: UnavailableDependencies ( package, set) ,
134
+ package_terms : SmallMap :: One ( [ ( package. clone ( ) , term ) ] ) ,
135
+ kind : Kind :: Custom ( package, set, metadata ) ,
107
136
}
108
137
}
109
138
@@ -135,7 +164,7 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
135
164
/// When multiple versions of a package depend on the same range of another package,
136
165
/// we can merge the two into a single incompatibility.
137
166
/// For example, if a@1 depends on b and a@2 depends on b, we can say instead
138
- /// a@1 and a@b depend on b.
167
+ /// a@1||2 depends on b.
139
168
///
140
169
/// It is a special case of prior cause computation where the unified package
141
170
/// is the common dependant in the two incompatibilities expressing dependencies.
@@ -231,8 +260,8 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
231
260
self_id : Id < Self > ,
232
261
shared_ids : & Set < Id < Self > > ,
233
262
store : & Arena < Self > ,
234
- precomputed : & Map < Id < Self > , Arc < DerivationTree < P , VS > > > ,
235
- ) -> DerivationTree < P , VS > {
263
+ precomputed : & Map < Id < Self > , Arc < DerivationTree < P , VS , M > > > ,
264
+ ) -> DerivationTree < P , VS , M > {
236
265
match store[ self_id] . kind . clone ( ) {
237
266
Kind :: DerivedFrom ( id1, id2) => {
238
267
let derived = Derived {
@@ -253,19 +282,28 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
253
282
DerivationTree :: External ( External :: NotRoot ( package, version) )
254
283
}
255
284
Kind :: NoVersions ( package, set) => {
256
- DerivationTree :: External ( External :: NoVersions ( package, set) )
285
+ DerivationTree :: External ( External :: NoVersions ( package. clone ( ) , set. clone ( ) ) )
257
286
}
258
- Kind :: UnavailableDependencies ( package, set) => {
259
- DerivationTree :: External ( External :: UnavailableDependencies ( package, set) )
287
+ Kind :: FromDependencyOf ( package, set, dep_package, dep_set) => {
288
+ DerivationTree :: External ( External :: FromDependencyOf (
289
+ package. clone ( ) ,
290
+ set. clone ( ) ,
291
+ dep_package. clone ( ) ,
292
+ dep_set. clone ( ) ,
293
+ ) )
260
294
}
261
- Kind :: FromDependencyOf ( package, set, dep_package, dep_set) => DerivationTree :: External (
262
- External :: FromDependencyOf ( package, set, dep_package, dep_set) ,
263
- ) ,
295
+ Kind :: Custom ( package, set, metadata) => DerivationTree :: External ( External :: Custom (
296
+ package. clone ( ) ,
297
+ set. clone ( ) ,
298
+ metadata. clone ( ) ,
299
+ ) ) ,
264
300
}
265
301
}
266
302
}
267
303
268
- impl < ' a , P : Package , VS : VersionSet + ' a > Incompatibility < P , VS > {
304
+ impl < ' a , P : Package , VS : VersionSet + ' a , M : Eq + Clone + Debug + Display + ' a >
305
+ Incompatibility < P , VS , M >
306
+ {
269
307
/// CF definition of Relation enum.
270
308
pub fn relation ( & self , terms : impl Fn ( & P ) -> Option < & ' a Term < VS > > ) -> Relation < P > {
271
309
let mut relation = Relation :: Satisfied ;
@@ -293,12 +331,17 @@ impl<'a, P: Package, VS: VersionSet + 'a> Incompatibility<P, VS> {
293
331
}
294
332
}
295
333
296
- impl < P : Package , VS : VersionSet > fmt:: Display for Incompatibility < P , VS > {
334
+ impl < P : Package , VS : VersionSet , M : Eq + Clone + Debug + Display > fmt:: Display
335
+ for Incompatibility < P , VS , M >
336
+ {
297
337
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
298
338
write ! (
299
339
f,
300
340
"{}" ,
301
- DefaultStringReportFormatter . format_terms( & self . package_terms. as_map( ) )
341
+ ReportFormatter :: <P , VS , M >:: format_terms(
342
+ & DefaultStringReportFormatter ,
343
+ & self . package_terms. as_map( )
344
+ )
302
345
)
303
346
}
304
347
}
@@ -326,12 +369,12 @@ pub mod tests {
326
369
let mut store = Arena :: new( ) ;
327
370
let i1 = store. alloc( Incompatibility {
328
371
package_terms: SmallMap :: Two ( [ ( "p1" , t1. clone( ) ) , ( "p2" , t2. negate( ) ) ] ) ,
329
- kind: Kind :: UnavailableDependencies ( "0 ", Range :: full( ) )
372
+ kind: Kind :: <_ , _ , String > :: FromDependencyOf ( "p1" , Range :: full ( ) , "p2 ", Range :: full( ) )
330
373
} ) ;
331
374
332
375
let i2 = store. alloc( Incompatibility {
333
376
package_terms: SmallMap :: Two ( [ ( "p2" , t2) , ( "p3" , t3. clone( ) ) ] ) ,
334
- kind: Kind :: UnavailableDependencies ( "0 ", Range :: full( ) )
377
+ kind: Kind :: <_ , _ , String > :: FromDependencyOf ( "p2" , Range :: full ( ) , "p3 ", Range :: full( ) )
335
378
} ) ;
336
379
337
380
let mut i3 = Map :: default ( ) ;
0 commit comments