Skip to content

Commit 14b46ec

Browse files
committed
Auto merge of #13776 - epage:msrv-resolver, r=weihanglo
feat(resolver): Add v3 resolver for MSRV-aware resolving ### What does this PR try to resolve? This is a part of #9930 and is important for changing the default with the new edition. ### How should we test and review this PR? ### Additional information
2 parents 02499ab + d052805 commit 14b46ec

File tree

6 files changed

+160
-4
lines changed

6 files changed

+160
-4
lines changed

src/cargo/core/resolver/features.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ impl FeatureOpts {
196196
}
197197
match ws.resolve_behavior() {
198198
ResolveBehavior::V1 => {}
199-
ResolveBehavior::V2 => {
199+
ResolveBehavior::V2 | ResolveBehavior::V3 => {
200200
enable(&vec!["all".to_string()]).unwrap();
201201
}
202202
}
@@ -214,7 +214,7 @@ impl FeatureOpts {
214214
pub fn new_behavior(behavior: ResolveBehavior, has_dev_units: HasDevUnits) -> FeatureOpts {
215215
match behavior {
216216
ResolveBehavior::V1 => FeatureOpts::default(),
217-
ResolveBehavior::V2 => FeatureOpts {
217+
ResolveBehavior::V2 | ResolveBehavior::V3 => FeatureOpts {
218218
decouple_host_deps: true,
219219
decouple_dev_deps: has_dev_units == HasDevUnits::No,
220220
ignore_inactive_targets: true,

src/cargo/core/resolver/types.rs

+4
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,16 @@ pub enum ResolveBehavior {
111111
V1,
112112
/// V2 adds the new feature resolver.
113113
V2,
114+
/// V3 changes version preferences
115+
V3,
114116
}
115117

116118
impl ResolveBehavior {
117119
pub fn from_manifest(resolver: &str) -> CargoResult<ResolveBehavior> {
118120
match resolver {
119121
"1" => Ok(ResolveBehavior::V1),
120122
"2" => Ok(ResolveBehavior::V2),
123+
"3" => Ok(ResolveBehavior::V3),
121124
s => anyhow::bail!(
122125
"`resolver` setting `{}` is not valid, valid options are \"1\" or \"2\"",
123126
s
@@ -129,6 +132,7 @@ impl ResolveBehavior {
129132
match self {
130133
ResolveBehavior::V1 => "1",
131134
ResolveBehavior::V2 => "2",
135+
ResolveBehavior::V3 => "3",
132136
}
133137
.to_owned()
134138
}

src/cargo/core/workspace.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,17 @@ impl<'gctx> Workspace<'gctx> {
306306
MaybePackage::Virtual(vm) => vm.resolve_behavior().unwrap_or(ResolveBehavior::V1),
307307
};
308308

309+
match self.resolve_behavior() {
310+
ResolveBehavior::V1 | ResolveBehavior::V2 => {}
311+
ResolveBehavior::V3 => {
312+
if self.resolve_behavior == ResolveBehavior::V3 {
313+
if !self.gctx().cli_unstable().msrv_policy {
314+
anyhow::bail!("`resolver=\"3\"` requires `-Zmsrv-policy`");
315+
}
316+
self.resolve_honors_rust_version = true;
317+
}
318+
}
319+
}
309320
match self.gctx().get::<CargoResolverConfig>("resolver") {
310321
Ok(CargoResolverConfig {
311322
something_like_precedence: Some(precedence),
@@ -869,7 +880,7 @@ impl<'gctx> Workspace<'gctx> {
869880
self.is_virtual()
870881
|| match self.resolve_behavior() {
871882
ResolveBehavior::V1 => false,
872-
ResolveBehavior::V2 => true,
883+
ResolveBehavior::V2 | ResolveBehavior::V3 => true,
873884
}
874885
}
875886

src/cargo/util/toml/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,12 @@ fn resolve_toml(
266266
warnings: &mut Vec<String>,
267267
_errors: &mut Vec<String>,
268268
) -> CargoResult<manifest::TomlManifest> {
269+
if let Some(workspace) = &original_toml.workspace {
270+
if workspace.resolver.as_deref() == Some("3") {
271+
features.require(Feature::edition2024())?;
272+
}
273+
}
274+
269275
let mut resolved_toml = manifest::TomlManifest {
270276
cargo_features: original_toml.cargo_features.clone(),
271277
package: None,
@@ -300,7 +306,8 @@ fn resolve_toml(
300306
};
301307

302308
if let Some(original_package) = original_toml.package() {
303-
let resolved_package = resolve_package_toml(original_package, package_root, &inherit)?;
309+
let resolved_package =
310+
resolve_package_toml(original_package, features, package_root, &inherit)?;
304311
let edition = resolved_package
305312
.resolved_edition()
306313
.expect("previously resolved")
@@ -432,6 +439,7 @@ fn resolve_toml(
432439
#[tracing::instrument(skip_all)]
433440
fn resolve_package_toml<'a>(
434441
original_package: &manifest::TomlPackage,
442+
features: &Features,
435443
package_root: &Path,
436444
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
437445
) -> CargoResult<Box<manifest::TomlPackage>> {
@@ -559,6 +567,11 @@ fn resolve_package_toml<'a>(
559567
metadata: original_package.metadata.clone(),
560568
_invalid_cargo_features: Default::default(),
561569
};
570+
571+
if resolved_package.resolver.as_deref() == Some("3") {
572+
features.require(Feature::edition2024())?;
573+
}
574+
562575
Ok(Box::new(resolved_package))
563576
}
564577

src/doc/src/reference/unstable.md

+1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ This was stabilized in 1.79 in [#13608](https://github.com/rust-lang/cargo/pull/
338338

339339
`-Zmsrv-policy` allows access to an MSRV-aware resolver which can be enabled with:
340340
- `resolver.something-like-precedence` config field
341+
- `workspace.resolver = "3"` / `package.resolver = "3"`
341342

342343
The resolver will prefer dependencies with a `package.rust-version` that is the same or older than your project's MSRV.
343344
Your project's MSRV is determined by taking the lowest `package.rust-version` set among your workspace members.

tests/testsuite/rust_version.rs

+127
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,133 @@ foo v0.0.1 ([CWD])
613613
.run();
614614
}
615615

616+
#[cargo_test(nightly, reason = "edition2024 in rustc is unstable")]
617+
fn resolve_v3() {
618+
Package::new("only-newer", "1.6.0")
619+
.rust_version("1.65.0")
620+
.file("src/lib.rs", "fn other_stuff() {}")
621+
.publish();
622+
Package::new("newer-and-older", "1.5.0")
623+
.rust_version("1.55.0")
624+
.file("src/lib.rs", "fn other_stuff() {}")
625+
.publish();
626+
Package::new("newer-and-older", "1.6.0")
627+
.rust_version("1.65.0")
628+
.file("src/lib.rs", "fn other_stuff() {}")
629+
.publish();
630+
631+
let p = project()
632+
.file(
633+
"Cargo.toml",
634+
r#"
635+
cargo-features = ["edition2024"]
636+
637+
[package]
638+
name = "foo"
639+
version = "0.0.1"
640+
edition = "2015"
641+
authors = []
642+
rust-version = "1.60.0"
643+
resolver = "3"
644+
645+
[dependencies]
646+
only-newer = "1.0.0"
647+
newer-and-older = "1.0.0"
648+
"#,
649+
)
650+
.file("src/main.rs", "fn main(){}")
651+
.build();
652+
653+
// v3 should resolve for MSRV
654+
p.cargo("generate-lockfile")
655+
.arg("-Zmsrv-policy")
656+
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
657+
.with_stderr(
658+
"\
659+
[UPDATING] `dummy-registry` index
660+
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
661+
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
662+
",
663+
)
664+
.run();
665+
p.cargo("tree")
666+
.arg("-Zmsrv-policy")
667+
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
668+
.with_stdout(
669+
"\
670+
foo v0.0.1 ([CWD])
671+
├── newer-and-older v1.5.0
672+
└── only-newer v1.6.0
673+
",
674+
)
675+
.run();
676+
677+
// `--ignore-rust-version` has precedence over v3
678+
p.cargo("generate-lockfile --ignore-rust-version")
679+
.with_stderr(
680+
"\
681+
[UPDATING] `dummy-registry` index
682+
[LOCKING] 3 packages to latest compatible versions
683+
",
684+
)
685+
.arg("-Zmsrv-policy")
686+
.masquerade_as_nightly_cargo(&["msrv-policy"])
687+
.run();
688+
p.cargo("tree")
689+
.arg("-Zmsrv-policy")
690+
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
691+
.with_stdout(
692+
"\
693+
foo v0.0.1 ([CWD])
694+
├── newer-and-older v1.6.0
695+
└── only-newer v1.6.0
696+
",
697+
)
698+
.run();
699+
700+
// config has precedence over v3
701+
p.cargo("generate-lockfile")
702+
.env(
703+
"CARGO_RESOLVER_SOMETHING_LIKE_PRECEDENCE",
704+
"something-like-maximum",
705+
)
706+
.with_stderr(
707+
"\
708+
[UPDATING] `dummy-registry` index
709+
[LOCKING] 3 packages to latest compatible versions
710+
",
711+
)
712+
.arg("-Zmsrv-policy")
713+
.masquerade_as_nightly_cargo(&["msrv-policy"])
714+
.run();
715+
p.cargo("tree")
716+
.arg("-Zmsrv-policy")
717+
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
718+
.with_stdout(
719+
"\
720+
foo v0.0.1 ([CWD])
721+
├── newer-and-older v1.6.0
722+
└── only-newer v1.6.0
723+
",
724+
)
725+
.run();
726+
727+
// unstable
728+
p.cargo("generate-lockfile")
729+
.with_status(101)
730+
.with_stderr(
731+
"\
732+
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
733+
734+
Caused by:
735+
the cargo feature `edition2024` requires a nightly version of Cargo, but this is the `stable` channel
736+
See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels.
737+
See https://doc.rust-lang.org/cargo/reference/unstable.html#edition-2024 for more information about using this feature.
738+
",
739+
)
740+
.run();
741+
}
742+
616743
#[cargo_test]
617744
fn generate_lockfile_ignore_rust_version_is_unstable() {
618745
Package::new("bar", "1.5.0")

0 commit comments

Comments
 (0)