1
1
//! Feature resolver.
2
2
//!
3
3
//! This is a new feature resolver that runs independently of the main
4
- //! dependency resolver. It is enabled when the user specifies `resolver =
5
- //! "2"` in `Cargo.toml` .
4
+ //! dependency resolver. It has several options which can enable new feature
5
+ //! resolution behavior .
6
6
//!
7
7
//! One of its key characteristics is that it can avoid unifying features for
8
8
//! shared dependencies in some situations. See `FeatureOpts` for the
9
9
//! different behaviors that can be enabled. If no extra options are enabled,
10
10
//! then it should behave exactly the same as the dependency resolver's
11
- //! feature resolution. This can be verified by setting the
12
- //! `__CARGO_FORCE_NEW_FEATURES=compare` environment variable and running
13
- //! Cargo's test suite (or building other projects), and checking if it
14
- //! panics. Note: the `features2` tests will fail because they intentionally
15
- //! compare the old vs new behavior, so forcing the old behavior will
16
- //! naturally fail the tests.
11
+ //! feature resolution.
17
12
//!
18
13
//! The preferred way to engage this new resolver is via
19
14
//! `resolve_ws_with_opts`.
@@ -59,22 +54,12 @@ pub struct ResolvedFeatures {
59
54
///
60
55
/// The value is the `name_in_toml` of the dependencies.
61
56
activated_dependencies : ActivateMap ,
62
- /// This is only here for legacy support when the new resolver is not enabled.
63
- ///
64
- /// This is the set of features enabled for each package.
65
- legacy_features : Option < HashMap < PackageId , Vec < InternedString > > > ,
66
- /// This is only here for legacy support when the new resolver is not enabled.
67
- ///
68
- /// This is the set of optional dependencies enabled for each package.
69
- legacy_dependencies : Option < HashMap < PackageId , HashSet < InternedString > > > ,
70
57
opts : FeatureOpts ,
71
58
}
72
59
73
60
/// Options for how the feature resolver works.
74
61
#[ derive( Default ) ]
75
62
pub struct FeatureOpts {
76
- /// Use the new resolver instead of the old one.
77
- new_resolver : bool ,
78
63
/// Build deps and proc-macros will not share share features with other dep kinds.
79
64
decouple_host_deps : bool ,
80
65
/// Dev dep features will not be activated unless needed.
@@ -132,7 +117,6 @@ impl FeatureOpts {
132
117
let mut opts = FeatureOpts :: default ( ) ;
133
118
let unstable_flags = ws. config ( ) . cli_unstable ( ) ;
134
119
let mut enable = |feat_opts : & Vec < String > | {
135
- opts. new_resolver = true ;
136
120
for opt in feat_opts {
137
121
match opt. as_ref ( ) {
138
122
"build_dep" | "host_dep" => opts. decouple_host_deps = true ,
@@ -159,26 +143,13 @@ impl FeatureOpts {
159
143
enable ( & vec ! [ "all" . to_string( ) ] ) . unwrap ( ) ;
160
144
}
161
145
}
162
- // This env var is intended for testing only.
163
- if let Ok ( env_opts) = std:: env:: var ( "__CARGO_FORCE_NEW_FEATURES" ) {
164
- if env_opts == "1" {
165
- opts. new_resolver = true ;
166
- } else {
167
- let env_opts = env_opts. split ( ',' ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
168
- enable ( & env_opts) ?;
169
- }
170
- }
171
146
if let HasDevUnits :: Yes = has_dev_units {
172
147
// Dev deps cannot be decoupled when they are in use.
173
148
opts. decouple_dev_deps = false ;
174
149
}
175
150
if let ForceAllTargets :: Yes = force_all_targets {
176
151
opts. ignore_inactive_targets = false ;
177
152
}
178
- if unstable_flags. weak_dep_features {
179
- // Force this ON because it only works with the new resolver.
180
- opts. new_resolver = true ;
181
- }
182
153
Ok ( opts)
183
154
}
184
155
@@ -187,7 +158,6 @@ impl FeatureOpts {
187
158
match behavior {
188
159
ResolveBehavior :: V1 => FeatureOpts :: default ( ) ,
189
160
ResolveBehavior :: V2 => FeatureOpts {
190
- new_resolver : true ,
191
161
decouple_host_deps : true ,
192
162
decouple_dev_deps : has_dev_units == HasDevUnits :: No ,
193
163
ignore_inactive_targets : true ,
@@ -306,18 +276,11 @@ impl ResolvedFeatures {
306
276
features_for : FeaturesFor ,
307
277
dep_name : InternedString ,
308
278
) -> bool {
309
- if let Some ( legacy) = & self . legacy_dependencies {
310
- legacy
311
- . get ( & pkg_id)
312
- . map ( |deps| deps. contains ( & dep_name) )
313
- . unwrap_or ( false )
314
- } else {
315
- let is_build = self . opts . decouple_host_deps && features_for == FeaturesFor :: HostDep ;
316
- self . activated_dependencies
317
- . get ( & ( pkg_id, is_build) )
318
- . map ( |deps| deps. contains ( & dep_name) )
319
- . unwrap_or ( false )
320
- }
279
+ let is_build = self . opts . decouple_host_deps && features_for == FeaturesFor :: HostDep ;
280
+ self . activated_dependencies
281
+ . get ( & ( pkg_id, is_build) )
282
+ . map ( |deps| deps. contains ( & dep_name) )
283
+ . unwrap_or ( false )
321
284
}
322
285
323
286
/// Variant of `activated_features` that returns `None` if this is
@@ -336,30 +299,28 @@ impl ResolvedFeatures {
336
299
pkg_id : PackageId ,
337
300
features_for : FeaturesFor ,
338
301
) -> CargoResult < Vec < InternedString > > {
339
- if let Some ( legacy) = & self . legacy_features {
340
- Ok ( legacy. get ( & pkg_id) . map_or_else ( Vec :: new, |v| v. clone ( ) ) )
302
+ let is_build = self . opts . decouple_host_deps && features_for == FeaturesFor :: HostDep ;
303
+ if let Some ( fs) = self . activated_features . get ( & ( pkg_id, is_build) ) {
304
+ Ok ( fs. iter ( ) . cloned ( ) . collect ( ) )
341
305
} else {
342
- let is_build = self . opts . decouple_host_deps && features_for == FeaturesFor :: HostDep ;
343
- if let Some ( fs) = self . activated_features . get ( & ( pkg_id, is_build) ) {
344
- Ok ( fs. iter ( ) . cloned ( ) . collect ( ) )
345
- } else {
346
- bail ! ( "features did not find {:?} {:?}" , pkg_id, is_build)
347
- }
306
+ bail ! ( "features did not find {:?} {:?}" , pkg_id, is_build)
348
307
}
349
308
}
350
309
351
310
/// Compares the result against the original resolver behavior.
352
311
///
353
312
/// Used by `cargo fix --edition` to display any differences.
354
313
pub fn compare_legacy ( & self , legacy : & ResolvedFeatures ) -> DiffMap {
355
- let legacy_features = legacy. legacy_features . as_ref ( ) . unwrap ( ) ;
356
314
self . activated_features
357
315
. iter ( )
358
316
. filter_map ( |( ( pkg_id, for_host) , new_features) | {
359
- let old_features = match legacy_features. get ( pkg_id) {
360
- Some ( feats) => feats. iter ( ) . cloned ( ) . collect ( ) ,
361
- None => BTreeSet :: new ( ) ,
362
- } ;
317
+ let old_features = legacy
318
+ . activated_features
319
+ . get ( & ( * pkg_id, * for_host) )
320
+ // The new features may have for_host entries where the old one does not.
321
+ . or_else ( || legacy. activated_features . get ( & ( * pkg_id, false ) ) )
322
+ . map ( |feats| feats. iter ( ) . cloned ( ) . collect ( ) )
323
+ . unwrap_or_else ( || BTreeSet :: new ( ) ) ;
363
324
// The new resolver should never add features.
364
325
assert_eq ! ( new_features. difference( & old_features) . next( ) , None ) ;
365
326
let removed_features: BTreeSet < _ > =
@@ -427,17 +388,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
427
388
) -> CargoResult < ResolvedFeatures > {
428
389
use crate :: util:: profile;
429
390
let _p = profile:: start ( "resolve features" ) ;
430
-
431
- if !opts. new_resolver {
432
- // Legacy mode.
433
- return Ok ( ResolvedFeatures {
434
- activated_features : HashMap :: new ( ) ,
435
- activated_dependencies : HashMap :: new ( ) ,
436
- legacy_features : Some ( resolve. features_clone ( ) ) ,
437
- legacy_dependencies : Some ( compute_legacy_deps ( resolve) ) ,
438
- opts,
439
- } ) ;
440
- }
441
391
let track_for_host = opts. decouple_host_deps || opts. ignore_inactive_targets ;
442
392
let mut r = FeatureResolver {
443
393
ws,
@@ -460,8 +410,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
460
410
Ok ( ResolvedFeatures {
461
411
activated_features : r. activated_features ,
462
412
activated_dependencies : r. activated_dependencies ,
463
- legacy_features : None ,
464
- legacy_dependencies : None ,
465
413
opts : r. opts ,
466
414
} )
467
415
}
@@ -826,19 +774,3 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
826
774
. proc_macro ( )
827
775
}
828
776
}
829
-
830
- /// Computes a map of PackageId to the set of optional dependencies that are
831
- /// enabled for that dep (when the new resolver is not enabled).
832
- fn compute_legacy_deps ( resolve : & Resolve ) -> HashMap < PackageId , HashSet < InternedString > > {
833
- let mut result: HashMap < PackageId , HashSet < InternedString > > = HashMap :: new ( ) ;
834
- for pkg_id in resolve. iter ( ) {
835
- for ( _dep_id, deps) in resolve. deps ( pkg_id) {
836
- for dep in deps {
837
- if dep. is_optional ( ) {
838
- result. entry ( pkg_id) . or_default ( ) . insert ( dep. name_in_toml ( ) ) ;
839
- }
840
- }
841
- }
842
- }
843
- result
844
- }
0 commit comments