Skip to content

Commit 2ca333f

Browse files
committed
Warn on any inconsistency in workspace and package resolver
If the workspace and package specify or default to different resolver versions then this will cause inconsistencies in build behavior between a development build within the workspace and the published package. To avoid this all packages must be configured to the same resolver setting as the workspace, whether implied by the edition or explicitly set.
1 parent 015143c commit 2ca333f

File tree

3 files changed

+104
-22
lines changed

3 files changed

+104
-22
lines changed

src/cargo/core/manifest.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,18 @@ impl Manifest {
511511
self.resolve_behavior
512512
}
513513

514+
/// The style of resolver behavior to use, declared with the `resolver` field or defaulted
515+
/// based on edition.
516+
pub fn defaulted_resolve_behavior(&self) -> ResolveBehavior {
517+
self.resolve_behavior().unwrap_or_else(|| {
518+
if self.edition() >= Edition::Edition2021 {
519+
ResolveBehavior::V2
520+
} else {
521+
ResolveBehavior::V1
522+
}
523+
})
524+
}
525+
514526
pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
515527
Manifest {
516528
summary: self.summary.map_source(to_replace, replace_with),
@@ -632,6 +644,11 @@ impl VirtualManifest {
632644
pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
633645
self.resolve_behavior
634646
}
647+
648+
/// The style of resolver behavior to use, declared with the `resolver` field or defaulted.
649+
pub fn defaulted_resolve_behavior(&self) -> ResolveBehavior {
650+
self.resolve_behavior().unwrap_or(ResolveBehavior::V1)
651+
}
635652
}
636653

637654
impl Target {

src/cargo/core/workspace.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::core::features::Features;
1616
use crate::core::registry::PackageRegistry;
1717
use crate::core::resolver::features::CliFeatures;
1818
use crate::core::resolver::ResolveBehavior;
19-
use crate::core::{Dependency, Edition, FeatureValue, PackageId, PackageIdSpec};
19+
use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec};
2020
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
2121
use crate::ops;
2222
use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
@@ -282,21 +282,10 @@ impl<'cfg> Workspace<'cfg> {
282282
}
283283

284284
fn set_resolve_behavior(&mut self) {
285-
// - If resolver is specified in the workspace definition, use that.
286-
// - If the root package specifies the resolver, use that.
287-
// - If the root package specifies edition 2021, use v2.
288-
// - Otherwise, use the default v1.
289285
self.resolve_behavior = match self.root_maybe() {
290-
MaybePackage::Package(p) => p.manifest().resolve_behavior().or_else(|| {
291-
if p.manifest().edition() >= Edition::Edition2021 {
292-
Some(ResolveBehavior::V2)
293-
} else {
294-
None
295-
}
296-
}),
297-
MaybePackage::Virtual(vm) => vm.resolve_behavior(),
286+
MaybePackage::Package(p) => p.manifest().defaulted_resolve_behavior(),
287+
MaybePackage::Virtual(vm) => vm.defaulted_resolve_behavior(),
298288
}
299-
.unwrap_or(ResolveBehavior::V1);
300289
}
301290

302291
/// Returns the current package of this workspace.
@@ -991,11 +980,38 @@ impl<'cfg> Workspace<'cfg> {
991980
if !manifest.patch().is_empty() {
992981
emit_warning("patch")?;
993982
}
994-
if let Some(behavior) = manifest.resolve_behavior() {
995-
if behavior != self.resolve_behavior {
996-
// Only warn if they don't match.
997-
emit_warning("resolver")?;
983+
if manifest.defaulted_resolve_behavior() != self.resolve_behavior {
984+
let package_reason = manifest
985+
.resolve_behavior()
986+
.is_none()
987+
.then(|| format!(r#" implied by edition = "{}""#, manifest.edition()))
988+
.unwrap_or_default();
989+
let workspace_reason = match self.root_maybe() {
990+
MaybePackage::Package(p) => {
991+
p.manifest().resolve_behavior().is_none().then(|| {
992+
format!(r#" implied by edition = "{}""#, manifest.edition())
993+
})
994+
}
995+
MaybePackage::Virtual(vm) => {
996+
vm.resolve_behavior().is_none().then(|| " (default)".into())
997+
}
998998
}
999+
.unwrap_or_default();
1000+
let msg = format!(
1001+
"expected resolver for package is overridden by the workspace root:\n\
1002+
package: {} expects resolver = \"{}\"{package_reason}\n\
1003+
workspace: {} sets resolver = \"{}\"{workspace_reason}",
1004+
pkg.manifest_path().display(),
1005+
manifest
1006+
.defaulted_resolve_behavior()
1007+
.to_manifest()
1008+
.unwrap_or_else(|| "1".into()),
1009+
root_manifest.display(),
1010+
self.resolve_behavior
1011+
.to_manifest()
1012+
.unwrap_or_else(|| "1".into()),
1013+
);
1014+
self.config.shell().warn(&msg)?;
9991015
}
10001016
}
10011017
}

tests/testsuite/features2.rs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ fn proc_macro_ws() {
10651065
[package]
10661066
name = "foo"
10671067
version = "0.1.0"
1068+
resolver = "2"
10681069
10691070
[features]
10701071
feat1 = []
@@ -1077,6 +1078,7 @@ fn proc_macro_ws() {
10771078
[package]
10781079
name = "pm"
10791080
version = "0.1.0"
1081+
resolver = "2"
10801082
10811083
[lib]
10821084
proc-macro = true
@@ -1364,7 +1366,7 @@ Caused by:
13641366

13651367
#[cargo_test]
13661368
fn resolver_ws_member() {
1367-
// Can't specify `resolver` in a ws member.
1369+
// Can't specify a different `resolver` in a ws member.
13681370
let p = project()
13691371
.file(
13701372
"Cargo.toml",
@@ -1388,9 +1390,9 @@ fn resolver_ws_member() {
13881390
p.cargo("check")
13891391
.with_stderr(
13901392
"\
1391-
warning: resolver for the non root package will be ignored, specify resolver at the workspace root:
1392-
package: [..]/foo/a/Cargo.toml
1393-
workspace: [..]/foo/Cargo.toml
1393+
warning: expected resolver for package is overridden by the workspace root:
1394+
package: [..]/foo/a/Cargo.toml expects resolver = \"2\"
1395+
workspace: [..]/foo/Cargo.toml sets resolver = \"1\" (default)
13941396
[CHECKING] a v0.1.0 [..]
13951397
[FINISHED] [..]
13961398
",
@@ -1433,6 +1435,41 @@ fn resolver_ws_root_and_member() {
14331435
.run();
14341436
}
14351437

1438+
#[cargo_test]
1439+
fn implicit_resolver_ws_member() {
1440+
let p = project()
1441+
.file(
1442+
"Cargo.toml",
1443+
r#"
1444+
[workspace]
1445+
members = ["a"]
1446+
"#,
1447+
)
1448+
.file(
1449+
"a/Cargo.toml",
1450+
r#"
1451+
[package]
1452+
name = "a"
1453+
version = "0.1.0"
1454+
edition = "2021" # implies `resolver = "2"`
1455+
"#,
1456+
)
1457+
.file("a/src/lib.rs", "")
1458+
.build();
1459+
1460+
p.cargo("check")
1461+
.with_stderr(
1462+
"\
1463+
warning: expected resolver for package is overridden by the workspace root:
1464+
package: [..]/foo/a/Cargo.toml expects resolver = \"2\" implied by edition = \"2021\"
1465+
workspace: [..]/foo/Cargo.toml sets resolver = \"1\" (default)
1466+
[CHECKING] a v0.1.0 [..]
1467+
[FINISHED] [..]
1468+
",
1469+
)
1470+
.run();
1471+
}
1472+
14361473
#[cargo_test]
14371474
fn resolver_enables_new_features() {
14381475
// resolver="2" enables all the things.
@@ -1472,6 +1509,7 @@ fn resolver_enables_new_features() {
14721509
name = "a"
14731510
version = "0.1.0"
14741511
edition = "2018"
1512+
resolver = "2"
14751513
14761514
[dependencies]
14771515
common = {version = "1.0", features=["normal"]}
@@ -1510,6 +1548,7 @@ fn resolver_enables_new_features() {
15101548
[package]
15111549
name = "b"
15121550
version = "0.1.0"
1551+
resolver = "2"
15131552
15141553
[features]
15151554
ping = []
@@ -1698,6 +1737,7 @@ fn shared_dep_same_but_dependencies() {
16981737
[package]
16991738
name = "bin1"
17001739
version = "0.1.0"
1740+
resolver = "2"
17011741
17021742
[dependencies]
17031743
dep = { path = "../dep" }
@@ -1710,6 +1750,7 @@ fn shared_dep_same_but_dependencies() {
17101750
[package]
17111751
name = "bin2"
17121752
version = "0.1.0"
1753+
resolver = "2"
17131754
17141755
[build-dependencies]
17151756
dep = { path = "../dep" }
@@ -1724,6 +1765,7 @@ fn shared_dep_same_but_dependencies() {
17241765
[package]
17251766
name = "dep"
17261767
version = "0.1.0"
1768+
resolver = "2"
17271769
17281770
[dependencies]
17291771
subdep = { path = "../subdep" }
@@ -1739,6 +1781,7 @@ fn shared_dep_same_but_dependencies() {
17391781
[package]
17401782
name = "subdep"
17411783
version = "0.1.0"
1784+
resolver = "2"
17421785
17431786
[features]
17441787
feat = []
@@ -1818,6 +1861,7 @@ fn test_proc_macro() {
18181861
[package]
18191862
name = "the-macro"
18201863
version = "0.1.0"
1864+
resolver = "2"
18211865
[lib]
18221866
proc-macro = true
18231867
test = false
@@ -1844,6 +1888,7 @@ fn test_proc_macro() {
18441888
[package]
18451889
name = "the-macro-support"
18461890
version = "0.1.0"
1891+
resolver = "2"
18471892
[dependencies]
18481893
shared = { path = "../shared" }
18491894
"#,
@@ -1860,6 +1905,7 @@ fn test_proc_macro() {
18601905
[package]
18611906
name = "shared"
18621907
version = "0.1.0"
1908+
resolver = "2"
18631909
[features]
18641910
b = []
18651911
"#,
@@ -2177,6 +2223,7 @@ fn pm_with_int_shared() {
21772223
name = "foo"
21782224
version = "0.1.0"
21792225
edition = "2018"
2226+
resolver = "2"
21802227
21812228
[dependencies]
21822229
pm = { path = "../pm" }
@@ -2196,6 +2243,7 @@ fn pm_with_int_shared() {
21962243
[package]
21972244
name = "pm"
21982245
version = "0.1.0"
2246+
resolver = "2"
21992247
22002248
[lib]
22012249
proc-macro = true
@@ -2224,6 +2272,7 @@ fn pm_with_int_shared() {
22242272
[package]
22252273
name = "shared"
22262274
version = "0.1.0"
2275+
resolver = "2"
22272276
22282277
[features]
22292278
norm-feat = []

0 commit comments

Comments
 (0)