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
This commit is contained in:
bors 2024-04-20 04:37:21 +00:00
commit 14b46ecc62
6 changed files with 160 additions and 4 deletions

View File

@ -196,7 +196,7 @@ impl FeatureOpts {
}
match ws.resolve_behavior() {
ResolveBehavior::V1 => {}
ResolveBehavior::V2 => {
ResolveBehavior::V2 | ResolveBehavior::V3 => {
enable(&vec!["all".to_string()]).unwrap();
}
}
@ -214,7 +214,7 @@ impl FeatureOpts {
pub fn new_behavior(behavior: ResolveBehavior, has_dev_units: HasDevUnits) -> FeatureOpts {
match behavior {
ResolveBehavior::V1 => FeatureOpts::default(),
ResolveBehavior::V2 => FeatureOpts {
ResolveBehavior::V2 | ResolveBehavior::V3 => FeatureOpts {
decouple_host_deps: true,
decouple_dev_deps: has_dev_units == HasDevUnits::No,
ignore_inactive_targets: true,

View File

@ -111,6 +111,8 @@ pub enum ResolveBehavior {
V1,
/// V2 adds the new feature resolver.
V2,
/// V3 changes version preferences
V3,
}
impl ResolveBehavior {
@ -118,6 +120,7 @@ impl ResolveBehavior {
match resolver {
"1" => Ok(ResolveBehavior::V1),
"2" => Ok(ResolveBehavior::V2),
"3" => Ok(ResolveBehavior::V3),
s => anyhow::bail!(
"`resolver` setting `{}` is not valid, valid options are \"1\" or \"2\"",
s
@ -129,6 +132,7 @@ impl ResolveBehavior {
match self {
ResolveBehavior::V1 => "1",
ResolveBehavior::V2 => "2",
ResolveBehavior::V3 => "3",
}
.to_owned()
}

View File

@ -306,6 +306,17 @@ impl<'gctx> Workspace<'gctx> {
MaybePackage::Virtual(vm) => vm.resolve_behavior().unwrap_or(ResolveBehavior::V1),
};
match self.resolve_behavior() {
ResolveBehavior::V1 | ResolveBehavior::V2 => {}
ResolveBehavior::V3 => {
if self.resolve_behavior == ResolveBehavior::V3 {
if !self.gctx().cli_unstable().msrv_policy {
anyhow::bail!("`resolver=\"3\"` requires `-Zmsrv-policy`");
}
self.resolve_honors_rust_version = true;
}
}
}
match self.gctx().get::<CargoResolverConfig>("resolver") {
Ok(CargoResolverConfig {
something_like_precedence: Some(precedence),
@ -869,7 +880,7 @@ impl<'gctx> Workspace<'gctx> {
self.is_virtual()
|| match self.resolve_behavior() {
ResolveBehavior::V1 => false,
ResolveBehavior::V2 => true,
ResolveBehavior::V2 | ResolveBehavior::V3 => true,
}
}

View File

@ -266,6 +266,12 @@ fn resolve_toml(
warnings: &mut Vec<String>,
_errors: &mut Vec<String>,
) -> CargoResult<manifest::TomlManifest> {
if let Some(workspace) = &original_toml.workspace {
if workspace.resolver.as_deref() == Some("3") {
features.require(Feature::edition2024())?;
}
}
let mut resolved_toml = manifest::TomlManifest {
cargo_features: original_toml.cargo_features.clone(),
package: None,
@ -300,7 +306,8 @@ fn resolve_toml(
};
if let Some(original_package) = original_toml.package() {
let resolved_package = resolve_package_toml(original_package, package_root, &inherit)?;
let resolved_package =
resolve_package_toml(original_package, features, package_root, &inherit)?;
let edition = resolved_package
.resolved_edition()
.expect("previously resolved")
@ -432,6 +439,7 @@ fn resolve_toml(
#[tracing::instrument(skip_all)]
fn resolve_package_toml<'a>(
original_package: &manifest::TomlPackage,
features: &Features,
package_root: &Path,
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
) -> CargoResult<Box<manifest::TomlPackage>> {
@ -559,6 +567,11 @@ fn resolve_package_toml<'a>(
metadata: original_package.metadata.clone(),
_invalid_cargo_features: Default::default(),
};
if resolved_package.resolver.as_deref() == Some("3") {
features.require(Feature::edition2024())?;
}
Ok(Box::new(resolved_package))
}

View File

@ -338,6 +338,7 @@ This was stabilized in 1.79 in [#13608](https://github.com/rust-lang/cargo/pull/
`-Zmsrv-policy` allows access to an MSRV-aware resolver which can be enabled with:
- `resolver.something-like-precedence` config field
- `workspace.resolver = "3"` / `package.resolver = "3"`
The resolver will prefer dependencies with a `package.rust-version` that is the same or older than your project's MSRV.
Your project's MSRV is determined by taking the lowest `package.rust-version` set among your workspace members.

View File

@ -613,6 +613,133 @@ foo v0.0.1 ([CWD])
.run();
}
#[cargo_test(nightly, reason = "edition2024 in rustc is unstable")]
fn resolve_v3() {
Package::new("only-newer", "1.6.0")
.rust_version("1.65.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
Package::new("newer-and-older", "1.5.0")
.rust_version("1.55.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
Package::new("newer-and-older", "1.6.0")
.rust_version("1.65.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
rust-version = "1.60.0"
resolver = "3"
[dependencies]
only-newer = "1.0.0"
newer-and-older = "1.0.0"
"#,
)
.file("src/main.rs", "fn main(){}")
.build();
// v3 should resolve for MSRV
p.cargo("generate-lockfile")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
",
)
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.5.0
only-newer v1.6.0
",
)
.run();
// `--ignore-rust-version` has precedence over v3
p.cargo("generate-lockfile --ignore-rust-version")
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest compatible versions
",
)
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["msrv-policy"])
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.6.0
only-newer v1.6.0
",
)
.run();
// config has precedence over v3
p.cargo("generate-lockfile")
.env(
"CARGO_RESOLVER_SOMETHING_LIKE_PRECEDENCE",
"something-like-maximum",
)
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest compatible versions
",
)
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["msrv-policy"])
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.6.0
only-newer v1.6.0
",
)
.run();
// unstable
p.cargo("generate-lockfile")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
the cargo feature `edition2024` requires a nightly version of Cargo, but this is the `stable` channel
See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels.
See https://doc.rust-lang.org/cargo/reference/unstable.html#edition-2024 for more information about using this feature.
",
)
.run();
}
#[cargo_test]
fn generate_lockfile_ignore_rust_version_is_unstable() {
Package::new("bar", "1.5.0")