cargo icon indicating copy to clipboard operation
cargo copied to clipboard

MSRV-dependent dependency version resolution

Open newpavlov opened this issue 4 years ago • 64 comments

Based on RFC 2495 Rust now supports the rust-version field, which currently works as:

If the currently selected version of the Rust compiler is older than the stated version, cargo will exit with an error, telling the user what version is require

This behavior is not ideal. If a project depends on crate foo v0.1.0 with MSRV 1.56, then releasing crate foo v0.1.1 with MSRV 1.60 will break build of the project on older toolchains after simple cargo update. Ideally Cargo would select foo v0.1.0 on older tolchains, thus preventing the breakage.

RFC 2495 has described MSRV-dependent version resolution as a potential future extension. This issue is intended for design discussions and tracking implementation progress of this feature.

Third-party support

  • dependabot/dependabot-core#5423
  • renovatebot/renovate#26060

This has been approved as RFC #3537.

Implementation by stabilization milestone

  • [x] Improve the cargo install error (#12798)
  • [x] Improve documentation around rust-version (#13056)
  • [x] cargo-add (#13608)
    • [x] cargo add support (#10653)
    • [x] Infer users rust-version from rustc -V (#13516)
  • [x] Attempt to report the MSRV error top-down, rather than bottom up (#13514)
  • [x] cargo update keeps user informed when using old versions (#13372)
  • [x] #13539
  • [ ] Resolver (#14639)
    • [x] Prototype (#12560)
    • [x] Switch resolver to "prefer" rather than "enforce" (#12950)
    • [x] De-prioritize dep versions without rust-version (#13066)
    • [x] Infer users rust-version from rustc -V (#13743)
    • [x] Existing --ignore-rust-version support (#13738)
    • [x] --ignore-rust-version support for cargo update / cargo-generate-lockfile (#13742)
    • [x] #13540
    • [x] Add resolver v3 (#13776)
    • [x] Verify resolver 3 doesn't change cargo-install (#13769, #13790)
    • [x] Verify cargo update --precise can select incompatible versions (#13769)
    • [x] Enable resolver v3 with Edition 2024 (#13785)
    • [x] #14569
  • [x] Have lockfile format version respect --ignore-rust-version (see #12861)
  • [ ] --update-rust-version support
    • cargo add
    • cargo update
    • cargo generate-lockfile
  • [ ] Turn MSRV error into a lint (blocked on #12235)
  • [ ] "auto": Add field with cargo-publish behavior (see also #11451)
  • [ ] Update cargo new template

Changes from RFC

Unresolved questions

  • cargo add and the resolver have different behavior for unset rust-version, see #13791

Deferred

  • Determination for what cargo install should do, see also #10903

newpavlov avatar Sep 21 '21 04:09 newpavlov

I think this probably makes more sense in the Cargo repository, since version resolution happens in Cargo -- might even make sense to do an RFC for it. @ehuss @Eh2406 what do you think?

I can see the attraction of this feature, but I'm also worried about it -- if this behavior doesn't come with a warning, it's trivially possible that downstream crates no longer get updated to upstream dependencies that fixed security vulnerabilities, for example. While I usually deploy cargo-deny in CI to make sure I'm aware of this, as long as something similar is not integrated in Cargo it would be a little scary that semver-compatible updates no longer flow as freely as they used to.

djc avatar Sep 21 '21 08:09 djc

Yes, having a Cargo warning for cases when there are dependency updates with incompatible MSRV would be a good feature.

As for security vulnerabilities, I think it should be solved by advisories like RustSec and by yanking affected versions. Also note that today crates can have minor (for pre-1.0, major otherwise) version updates with security fixes which do not get ported to older releases. So I don't think that the proposed MSRV-dependent version resolution is fundamentally different from the existing status quo in this regard.

newpavlov avatar Sep 21 '21 11:09 newpavlov

Transferred to Cargo.

IMO one of the big problems blocking this is the error messages. The current Resolver has pretty bad messages, it just reports on the last thing that did not work. So In effect the Resolver will just ignore all versions with a different MSRV leaving no record of why newer versions were not considered. This may be on the list of things to consider when/if we use PubGrub. But that is just my opinion.

Eh2406 avatar Sep 21 '21 15:09 Eh2406

Is this actually a good idea? I feel like rust-version should solely be a safeguard, and not actually affect behavior. IMO pinning a Rust version without pinning dependencies is user error, and it's better for this to be a hard error instead of doing what might be the wrong thing.

leo60228 avatar Sep 21 '21 15:09 leo60228

broken code doesn't help anyone. If cargo update / upgrade gives warnings that your rust version is too old to bring in all the latest updates then people will be more likely to run cargo upgrade as they are more likely to get a result that works. Pragmatically some stuff upgraded is better than nothing upgraded.

gilescope avatar Oct 15 '21 20:10 gilescope

@leo60228

Is this actually a good idea?

It was my main motivation for writing the MSRV RFC. Without it I (and many others) consider bumping MSRV a breaking change, since otherwise we risk breaking people's builds on older toolchains (e.g. think of Rust packaged with Debian). Printing an error is just slightly improves ergonomics, no solves the problem at the root.

newpavlov avatar Oct 21 '21 18:10 newpavlov

I think most maintainers have stepped away from the idea of MSRV bumps requiring a semver bump. Even fundamental things like serde have done it. Instead, just keep a conservative enough MSRV for your crate's audience.

djc avatar Oct 21 '21 18:10 djc

I think most maintainers have stepped away from the idea of MSRV bumps requiring a semver bump. Even fundamental things like serde have done it. Instead, just keep a conservative enough MSRV for your crate's audience.

But keeping "a conservative enough MSRV for your crate's audience" is not_possible if your upstream dependencies don't do the same. If upstream crates raise their MSRV without a major version bump, then you have little choice but to follow suit. As @leo60228 suggested you could pin those crates versions to before their MSRV bump, but that causes a different problem: Cargo refuses to build two semver-compatible versions of a single crate in a single build. That can result in downstream users' builds breaking, even if they don't care about MSRV. So Rust really does need an MSRV-sensitive resolver.

asomers avatar Oct 23 '21 13:10 asomers

pinning a Rust version without pinning dependencies is user error, and it's better for this to be a hard error instead of doing what might be the wrong thing.

One way to resolve this concern is to make the behavior opt-in. By default, behavior is at is today (modulo a better error message), but you can pass --rust-version flag to commands like update or generate-lockfile to request resolution at a specific version.

matklad avatar Oct 25 '21 14:10 matklad

But keeping "a conservative enough MSRV for your crate's audience" is not_possible if your upstream dependencies don't do the same. If upstream crates raise their MSRV without a major version bump, then you have little choice but to follow suit.

In theory, this is true. In practice, I've found that upstream maintainers have usually been happy to accomodate my requests for changes to allow a more conservative MSRV -- just a matter of (a) being aware when changes happen and (b) engaging with upstream to voice your concerns/discuss trade-offs.

djc avatar Oct 26 '21 08:10 djc

How should this interact with rust-toolchain.toml? At the moment it is only selecting a toolchain from rustup. Should it become the default version for update and generate-lockfile as well?

197g avatar Oct 26 '21 15:10 197g

@Eh2406

IMO one of the big problems blocking this is the error messages.

Wouldn't it be viable to implement an MVP with bad error messages first and work on improving them later?

So In effect the Resolver will just ignore all versions with a different MSRV leaving no record of why newer versions were not considered.

I think it should be fine to start with a simple warning if at least one dependency version was ignored due to the MSRV filtration.

newpavlov avatar Dec 14 '21 15:12 newpavlov

I came across a related problem, where a CI/CD pipeline failed due to a updated dependency which demanded a higher MSRV than specified for the downstream project.

While I am not sure, that doing a automated MSRV-dependent dependency version resolution is a good idea in general, I would like a feature which notifies you if dependencies can't be build with the specified MSRV. As far as I can tell, it should be no big deal to implement a warning which, when building, notifies you about this. This may not prevent the problem that a upstream crate may change the MSRV in a semver compatible release in the future, but ensures that there isn't already a unwanted mismatch at development time.

Furthermore I am not completely sure how its meant to be specified: Should the developer ensure, that the MSRV of his Crate is at least as high as all upstream dependencies?

RFC 2495 mentions this, but there seems to be no check implemented right now.

rust field value will be checked as well. During crate build cargo will check if all upstream dependencies can be built with the specified MSRV. (i.e. it will check if there is exists solution for given crates and Rust versions constraints) Yanked crates will be ignored in this process.

embediver avatar May 30 '22 12:05 embediver

While I am not sure, that doing a automated MSRV-dependent dependency version resolution is a good idea in general, I would like a feature which notifies you if dependencies can't be build with the specified MSRV. As far as I can tell, it should be no big deal to implement a warning which, when building, notifies you about this.

Cargo from Rust 1.56 and newer should yield an MSRV-specific error when trying to build a dependency that has its rust-version set to something lower than the currently executing version of the compiler.

Furthermore I am not completely sure how its meant to be specified: Should the developer ensure, that the MSRV of his Crate is at least as high as all upstream dependencies?

Yes, there is currently no way that the tooling can ensure this.

djc avatar May 30 '22 12:05 djc

Cargo from Rust 1.56 and newer should yield an MSRV-specific error when trying to build a dependency that has its rust-version set to something lower than the currently executing version of the compiler.

Just tried to provoke this behaviour with two freshly created crates, and can't really confirm this. As long as the edition and rust-version key match, there seems to be no warning or error at all. Or did I get something wrong here.

When building crate A which depends on crate B, I can set rust-version and edition to whatever I like for both crates and won't get a error (e.g. rust-version 1.42 for crate A and 1.61 for crate B). cargo --version gives me cargo 1.61.0 (a028ae4 2022-04-29).

embediver avatar May 30 '22 13:05 embediver

I didn't say you would get an error in that situation. You're building with Cargo 1.61 and both of the crates have 1.61 or older, so there is no error. We currently don't check that depending crates have a newer or equal MSRV compared to the crate they're depending on.

You can refer to the documentation here: https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field.

As far as I can tell, all of this discussion is off-topic for this issue, which is about influencing the Cargo resolver such that it would select the lower version of a dependency if that is a better match for the current Cargo version.

djc avatar May 30 '22 13:05 djc

Ok, thanks for the clarification. And yes its somewhat off-topic, my apologies.

Initially I was just confused that the RFC excerpt I cited isn't implemented in some tooling right now and came up to this Issue.

To contribute at least a bit here: If the Cargo resolver will make some decisions based on the MSRV, the tooling which hints the developer of incompatible MSRVs, is basically included in that. IMO that would be good to have.

embediver avatar May 30 '22 14:05 embediver

Perhaps there could be an unstable option similar to cargo update -Z minimal-versions to perform a resolution that considers MSRV?

tarcieri avatar May 30 '22 14:05 tarcieri

Highlights of discussion so far:

Need for notifying users

if this behavior doesn't come with a warning, it's trivially possible that downstream crates no longer get updated to upstream dependencies that fixed security vulnerabilities, for example. While I usually deploy cargo-deny in CI to make sure I'm aware of this, as long as something similar is not integrated in Cargo it would be a little scary that semver-compatible updates no longer flow as freely as they used to.

Yes, having a Cargo warning for cases when there are dependency updates with incompatible MSRV would be a good feature.

As for security vulnerabilities, I think it should be solved by advisories like RustSec and by yanking affected versions. Also note that today crates can have minor (for pre-1.0, major otherwise) version updates with security fixes which do not get ported to older releases. So I don't think that the proposed MSRV-dependent version resolution is fundamentally different from the existing status quo in this regard.


Error messages

IMO one of the big problems blocking this is the error messages. The current Resolver has pretty bad messages, it just reports on the last thing that did not work. So In effect the Resolver will just ignore all versions with a different MSRV leaving no record of why newer versions were not considered. This may be on the list of things to consider when/if we use PubGrub. But that is just my opinion.

Wouldn't it be viable to implement an MVP with bad error messages first and work on improving them later?


rust-version as advisory only

Is this actually a good idea? I feel like rust-version should solely be a safeguard, and not actually affect behavior. IMO pinning a Rust version without pinning dependencies is user error, and it's better for this to be a hard error instead of doing what might be the wrong thing.

broken code doesn't help anyone. If cargo update / upgrade gives warnings that your rust version is too old to bring in all the latest updates then people will be more likely to run cargo upgrade as they are more likely to get a result that works. Pragmatically some stuff upgraded is better than nothing upgraded.

But keeping "a conservative enough MSRV for your crate's audience" is not_possible if your upstream dependencies don't do the same. If upstream crates raise their MSRV without a major version bump, then you have little choice but to follow suit. As @leo60228 suggested you could pin those crates versions to before their MSRV bump, but that causes a different problem: Cargo refuses to build two semver-compatible versions of a single crate in a single build. That can result in downstream users' builds breaking, even if they don't care about MSRV. So Rust really does need an MSRV-sensitive resolver.

In theory, this is true. In practice, I've found that upstream maintainers have usually been happy to accomodate my requests for changes to allow a more conservative MSRV -- just a matter of (a) being aware when changes happen and (b) engaging with upstream to voice your concerns/discuss trade-offs.

One way to resolve this concern is to make the behavior opt-in. By default, behavior is at is today (modulo a better error message), but you can pass --rust-version flag to commands like update or generate-lockfile to request resolution at a specific version.

Perhaps there could be an unstable option similar to cargo update -Z minimal-versions to perform a resolution that considers MSRV?


rustup interaction

How should this interact with rust-toolchain.toml? At the moment it is only selecting a toolchain from rustup. Should it become the default version for update and generate-lockfile as well?


Other relevant discussions

  • https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/rust-version.20and.20the.20Index
  • https://github.com/rust-lang/libs-team/issues/72
  • https://github.com/time-rs/time/discussions/535

epage avatar Mar 29 '23 18:03 epage

Blockers for MSRV in the resolver

Exceptions are bolded

The rust-version field existing in the Index so the resolver can reference it

  • The more packages that get rust-version populated (which will happen over time as new crates are published), the more useful any features using it will be

Problem

As an end-user, I might have rust installed but haven't been keeping up with the latest and just want to cargo install without extra steps or might not be familiar with how to upgrade. Even worse if I was using a distribution version, like from Debian.

As a maintainer, it is cumbersome to have an MSRV and for it to be something besides the latest. When upgrading or pulling in a new dependency, a maintainer has to choose

  • To forget it and update MSRV
  • Try to get the depedency to hold back their MSRV which just shifts this burden to someone else
  • Hand pick MSRV compatible versions, iterating with cargo update --precise until you are done
    • This also means depenents need to do the same
  • Misuse version requirements without full understanding of the impact, e.g.
    • https://github.com/rust-lang/cargo/issues/6584#issuecomment-1308032517
    • https://www.reddit.com/r/rust/comments/p8clcx/how_to_fix_cargo_dependency_issue/

Similarly, as a corporate user, I might be aligned to specific rust versions that have been integrated into our build process or certified for our use.

As a maintainer, I frequently have to support my users through picking the right version of my dependencies

  • Examples:
    • https://github.com/clap-rs/clap/issues/4811
    • https://github.com/clap-rs/clap/issues/3727
    • https://github.com/clap-rs/clap/issues/2735 https://github.com/clap-rs/clap/issues/2734 https://github.com/clap-rs/clap/issues/2691

As a maintainer, it can be tiring to deal with people making special requests for MSRV and I want things to "just work" so there is less reason for these requests to be made

  • Sometimes these requests don't come with any requirement more than "someone else asked me"
  • The conversations in libc and time MSRV policy discussion don't feel all that unique

Proposed behavior

By default, we resolve with MSRV

Implementation: the resolver would treat rust as just another dependency, one that exists in a different namespace as packages.

For local development tasks

  • We effectively treat it as all rust versions exist.
  • workspace members with a package.rust-version effectively have rustc.version = "<=package.rust-version"
  • non-workspace members with a package.rust-version effectively have rustc.version = "^package.rust-version"

For cargo install <foo> (no version specified) (#10903)

  • For unconstrained versions, select a version of the package compatible with rustc -V
  • If --locked or --ignore-rust-version are not set:
    • Either
      • We only act as if rustc -V exists
      • The current toolchain is another node in the dependency graph with the dependency rustc.version = "=package.rust-version"
    • all packages with a package.rust-version effectively have rustc.version = "^package.rust-version"

For cargo add <foo> (no version specified), versions newer than the selected package's package.rust-version will be ignored (#10653)

--ignore-rust-version would be updated to opt-out of the MSRV resolver

Corner cases

  • cargo add, cargo install, and cargo update --precise will need to have a good error message if the selected version is semver incompatible

Challenges with doing MSRV-aware resolver with possible solutions

Error reporting

  • The proposed implementation should have errors that are no worse than existing resolver errors
  • Heuristics could possibly be added that don't say what caused the failure but provide context for the user to decide what caused the failure (e.g. reporting versions of a dependency that are yanked or have too high of an MSRV)
    • This is likely over simplifying and making it sound easier than it is

Users running stale, possibly insecure versions

  • Note: this is already a problem with semver incompatible versions and renames
  • cargo audit, cargo deny exist but require users to opt-in
  • Github will notify of vulnerabilities through Dependabot, even using the push-message to tell users on the command-line but this is limited to Github
  • cargo update report upgrades/downgrades in a table with old, new, latest compatible, latest incompatible versions
    • Make --verbose report the status for all crates not on latest version
    • A --dry-run flag is already available to see the status without upgrading
    • No blockers
  • cargo add and cargo install could warn when not selecting the latest version of the specified package, informing the user what the latest compatible and/or incompatible version is
    • This does leave off any notifying the user for any indirect dependencies
    • No blockers for semver-incompatible versions
  • Longer term, we can explore integrating cargo audit into cargo (e.g. #10016) which will help with both MSRV incompatible and semver incompatible versions

Upgrading to a new rust version causes my lockfile to change

  • This is particularly bad for CI jobs that ensure the Cargo.lock is aligned with Cargo.toml
  • This is only a problem if...
    • You specify rust-version
    • The version of a dependency already has a rust-version entry in the index
    • The dependency's rust-version is newer than your rust-version
    • You do not have a CI job to verify rust-version to catch this
  • A user can resolve this on one-off basis by updating the lockfile
  • So far, this does not seem like a big enough concern. If people find a reason to raise the priority, we could make this opt-in until the next edition after which it would be opt-out

Maintainers who want to different rust versions between MSRV verification and regular development

  • Use case: As a binary author, I want my pre-built binaries to have all the latest features/fixes but I want an older MSRV for compatibility with Debian users
  • Maintainers can use the --ignore-rust-version flag to opt-out of the MSRV-aware resolver and maintain multiple lockfiles
    • We might need to add `--ignore-rust-version to more commands
    • While this is more of a burden, I suspect this is narrow enough of a use case to be acceptable
    • To make this more ergonomic, we could add a rust-version config field that overrides the effective MSRV with either a "..or "package" (take from Cargo.toml) orcurrent (rustc -V) so users can set an env variable or drop a .cargo/config.toml` file

Alternatives

Make MSRV-aware resolver opt-in

  • MSRV jobs could use the "--resolve-with-msrv" flag
  • MSRV build errors could suggest passing the "--resolve-with-msrv" flag
  • 🔴 This steers the community away from having a cohesive, dependable MSRV experience like we do for semver.
    • I attribute the dependability of semver within the rust ecosystem to (1) it was there from the beginning, (2) its encoded as the default in our tools with version constraints, and (3) the lack of Cargo.lock for libs has us self-policing each other for semver violations
    • By not making MSRV the default resolver policy, its putting in extra roadhumps to maintainers doing the right thing, making it less likely the ecosystem will have a good MSRV story (package.rust-version actually set and is accurate)
  • 🔴 For new or irregular users, this creates hurdles when starting a task (e.g. cargo install). If enough of these hurdles are present, it could sour the person on their experience with Rust.

Open Questions

  • Once rust-version is in the index, do we backfill it for already published crates?
    • Do we continue backfilling? For how long?
  • Is there any way to help ensure rust-version is specified in more packages?
    • Have cargo publish implicitly set it to rustc -V since we know the current version works
    • Have cargo new set the rust-version to rustc -V (related: #11451)

epage avatar Mar 29 '23 20:03 epage

I'd like to propose that cargo update should also always warn if an update is withheld due to MSRV. I think there's a decent argument that it should even hard-error unless a flag is passed, but that may be overkill.

jonhoo avatar Apr 01 '23 16:04 jonhoo

I'd like to propose that cargo update should also always warn if an update is withheld due to MSRV

What if the table mentioned this? While I didn't specify it, that was one of my expectations with the table to report why a newer version may not be available

I think there's a decent argument that it should even hard-error unless a flag is passed, but that may be overkill.

If the flag always has to be passed in, it loses its meaning and instead only serves as a barrier which just instills a feeling of frustation. For any project lagging behind its dependencies, this will always be needed.

epage avatar Apr 02 '23 01:04 epage

I'd like to propose that cargo update should also always warn if an update is withheld due to MSRV

What if the table mentioned this? While I didn't specify it, that was one of my expectations with the table to report why a newer version may not be available

Maybe this is a "me" thing, but I generally do not want verbose output from commands. A table would be far too noisy for me, and I would only want one if I explicitly passed in --verbose. Ideally, in my mind, cargo update would print nothing, with an option to print a list, and another option to print a full table. But this warning should be surfaced no matter which output mode is used.

I think there's a decent argument that it should even hard-error unless a flag is passed, but that may be overkill.

If the flag always has to be passed in, it loses its meaning and instead only serves as a barrier which just instills a feeling of frustation. For any project lagging behind its dependencies, this will always be needed.

I think my proposal here stems from the fact that I worry a lot about folks using old versions of their dependencies, and ending up with insecure, buggy, or under-performing software as a result. To the point that I think having MSRV-aware resolving by default for cargo update is a mistake. I fully acknowledge there's a trade-off here, but I think valuing "Cargo.lock represents rust-version" higher than "you're using the latest possible version of your dependencies" is going to come back to bite us over and over again. If we go that path though, I think at the very least the decision to willingly take older versions should be made very explicit.

jonhoo avatar Apr 08 '23 17:04 jonhoo

I think my proposal here stems from the fact that I worry a lot about folks using old versions of their dependencies, and ending up with insecure, buggy, or under-performing software as a result.

Following this logic Cargo should not use Cargo.lock at all and instead always fetch dependency updates on each build job. It's obviously not how we work with dependencies, because updating them has its own set of risks.

newpavlov avatar Apr 08 '23 18:04 newpavlov

The difference is that you can currently expect to get the latest versions compatible with what you wrote in Cargo.toml when running cargo update. With MSRV-dependent resolution, you might start silently getting older versions based solely on the libraries' Cargo.tomls and your current version of Rust.

And "your current version of Rust" is not always a real constraint- sometimes you just haven't run rustup update yet, and would be perfectly willing to do so if you knew it would help.

rpjohnst avatar Apr 08 '23 18:04 rpjohnst

I think my proposal here stems from the fact that I worry a lot about folks using old versions of their dependencies, and ending up with insecure, buggy, or under-performing software as a result.

Following this logic Cargo should not use Cargo.lock at all and instead always fetch dependency updates on each build job. It's obviously not how we work with dependencies, because updating them has its own set of risks.

I don't think that follows. cargo update is an explicit operation I run to update. Cargo does not run it on my behalf.

That said, this is related to one of the concerns I know have been raised in response to the suggestion that folks should start checking in Cargo.lock for libraries — that doing so would mean less automatic testing of new versions of dependencies, and that such an outcome would be detrimental to the health of the ecosystem.

jonhoo avatar Apr 08 '23 19:04 jonhoo

@rpjohnst

With MSRV-dependent resolution, you might start silently getting older versions based solely on the libraries' Cargo.tomls and your current version of Rust.

Not silently. With an appropriate warning message on cargo update or on first generation of Cargo.lock.

@jonhoo

I don't think that follows. cargo update is an explicit operation I run to update. Cargo does not run it on my behalf.

By having Cargo.lock in your workspace (regardless whether it's committed to VCS or not) you are likely using "old versions of dependencies", unless you explicitly run cargo update. If we consider it's fine, then what exactly MSRV-dependent resolution changes? If anything, from your point of view, the current status quo should be even worse than the proposed warning system. Today you do not get any built-in warnings if there are outdated dependencies in your tree, you have to use separate tools like cargo outdated.

newpavlov avatar Apr 08 '23 19:04 newpavlov

Per the summary above it seems like there's fairly widespread agreement that using an older version to be MSRV compatible should print a warning

tarcieri avatar Apr 08 '23 19:04 tarcieri

I think my proposal here stems from the fact that I worry a lot about folks using old versions of their dependencies, and ending up with insecure, buggy, or under-performing software as a result.

In general I agree with this.

To the point that I think having MSRV-aware resolving by default for cargo update is a mistake. I fully acknowledge there's a trade-off here, but I think valuing "Cargo.lock represents rust-version" higher than "you're using the latest possible version of your dependencies" is going to come back to bite us over and over again.

It feels like there's a missing piece here around intent.

If we consider a "how-much-I-care-about-msrv" equivalent to Cargo.toml's existing "maintenance" field, I can imagine the following values:

  • I really strongly care about MSRV
  • My real aim is to target e.g. current minus 6 months, so I'd be happy to bump to whatever that is
  • I would be happy to bump this if there's any good reason to
  • I don't actually care about this at all, but cargo started setting a default value for me so here it is

And if we consider the operations a maintainer may be doing on a crate, I can imagine being in any of the following modes:

  • I'm just trying to work keeping to my original MSRV
  • I'm trying to work, and am happy to explore changing my MSRV if it's convenient
  • I'm explicitly looking to bump my MSRV

When performing operations, particularly cargo update, these two factors combine to give reasonable behaviours.

If you really strongly care about MSRV, you probably want an explicit flag to ever violate MSRV. If you actually have a more flexible policy, maybe a different default makes sense. But it feels like being able to express the intent of why this is your MSRV may affect how cargo should act.

you might start silently getting older versions based solely on the libraries' Cargo.tomls

It feels like transitive dependencies' MSRVs should be capped by the actual package being operated on from the command line is.

If I have a package foo which specifies MSRV 1.56, and I have a dependency which specifies MSRV 1.54, any new package I consider bringing in should be capped by 1.56 not 1.54. I think in the latest proposal, this is actually slightly ambiguous as to which crates in the dep graph factor into MSRV calculation.

illicitonion avatar Apr 08 '23 20:04 illicitonion

By having Cargo.lock in your workspace (regardless whether it's committed to VCS or not) you are likely using "old versions of dependencies", unless you explicitly run cargo update. If we consider it's fine, then what exactly MSRV-dependent resolution changes? If anything, from your point of view, the current status quo should be even worse than the proposed warning system. Today you do not get any built-in warnings if there are outdated dependencies in your tree, you have to use separate tools like cargo outdated.

The big difference is that running cargo update is an indication of intent. When I run that command I'm saying "I want to update now", and it's unfortunate that after running that command I'm not actually up to date.

jonhoo avatar Apr 08 '23 21:04 jonhoo