cargo icon indicating copy to clipboard operation
cargo copied to clipboard

Add lint to explicitly set resolver

Open TheButlah opened this issue 2 years ago • 13 comments

Problem

Because the resolver is a global setting in workspaces, and workspaces don't have edition settings, I believe that it is very easy to accidentally use the old resolver in workspaces where you intended on using the new resolver. Because I didn't know about the resolver being global, I just assumed I was using the new one since my crate's edition said "2021" and it caused me to spend the last 4 days trying to fix my builds.

Proposed Solution

I think that having a lint in cargo that says "hey you should explicity set your resolver" would be merited. Because otherwise everyone is going to be using the old resolver all the time, perhaps even without realizing.

Notes

See also https://github.com/rust-lang/rust/issues/90148 and https://github.com/rust-lang/cargo/issues/9996

TheButlah avatar Nov 22 '21 18:11 TheButlah

There is an issue of people who are not using resolver so that their workspace is compatible with older Cargos. This becomes less of an issue overtime, but is still a thing. So maybe we worn on a 2021 crate being built in a workspace that did not set resolver.

Eh2406 avatar Dec 10 '21 21:12 Eh2406

Crates != workspace though, that's why the issue is here to begin with. It's not sufficient to set resolver =2 in the crates cargo.toml, it has to be done in the workspace Cargo.toml

I'm advocating for a lint that suggests explicitly setting the resolver (even if resolver = 1) in the workspace Cargo.toml

TheButlah avatar Dec 10 '21 22:12 TheButlah

As a minimum, I think it would make sense to warn (or generate a error) if a crate explicitly sets resolver = 2, but it uses resolver v1 due a workspace in the root without a resolver set/resolver set to v1.

johnkjellberg avatar Dec 20 '21 14:12 johnkjellberg

Having the default workspace resolver as v1 creates confusion in workspaces with all crates using edition = "2021". Telling the user that the resolver might not match their expectation can save days of troubleshooting weird dependency problems as in my and @TheButlah's cases.

DusterTheFirst avatar Feb 24 '22 11:02 DusterTheFirst

Part of workspace inheritance is the ability for a member to inherit the edition from its workspace. #10587 was opened to discuss if setting the edition in [workspace.package] should imply the resolver version for the workspace if one is not set. This might help mitigate this issue for users of workspace inheritance. If anyone has thoughts on this please add them to the issue.

Muscraft avatar Jul 28 '22 17:07 Muscraft

To extract some discussion from #10910:

The lint I propose is to emit a warning any time one of the members of a workspace has a different resolver to the workspace itself. This is necessary for binaries because developers will expect that when they cargo build locally in their workspace, then cargo publish && cargo install the same feature-resolution algorithm will be used. For libraries it's less important since their resolver is set by the root of whatever build-tree they're in, but there is one important usecase that builds with the library as the root: docs.rs. There were issues building the docs for axum despite them having a local CI test for the docs.

Generally fixing this lint is just adding workspace.resolver = "2" (or workspace.edition = "2021" if #10587 is implemented) and making sure you have updated all your crates to edition 2021. I would be surprised if there are any workspaces that want to have disparate editions longterm, so if there is another version of the resolver implied by a future edition then you would just have to update the resolver version at the same time you update all your editions.

The biggest downside I see is that this will be instantaneously very noisy. I'm certain that 99% of virtual workspaces are currently setup incorrectly since I have never seen workspace.resolver being used.

Nemo157 avatar Jul 28 '22 19:07 Nemo157

This is necessary for binaries because developers will expect that when they cargo build locally in their workspace, then cargo publish && cargo install the same feature-resolution algorithm will be used.

@Nemo157 do you have a reproduction case for this local and published resolution being different?

When we clean up the manifest for publish, we overwrite the package.resolver with workspace.resolver (after all defaulting as been applied), see https://github.com/rust-lang/cargo/blob/master/src/cargo/util/toml/mod.rs#L1345. That should cause the published package's behavior to be the same as local development so long as the package is always within a workspace (e.g. cargo isn't always in a workspace so it can get inconsistent results depending on how you develop on it locally and publish is just consistent with which case cargo was published from)

epage avatar Jul 28 '22 20:07 epage

ResolverBehavior::V1.to_manifest() == None. So this will only upgrade an edition = "2015" crate inside a resolver = "2" workspace to use package.resolver = "2", it will not downgrade a crate to use the old resolver. The linked issue from axum is exactly this case, within their repository they were using resolver = "1" because it was in a virtual workspace and did not override it, they then published a crate using edition = "2021" so it implicitly used resolver = "2".

Nemo157 avatar Jul 28 '22 20:07 Nemo157

@ehuss looks like you added all of this in #8129. Happen to remember if its intentional that TomlManifest::prepare_for_publish will only put the workspace's resolver version into the published manifest if its not v1 and cause an edition="2018" package to build differently locally than with cargo install from the registry?

If its not intentional for local and registry packages to build differently, thoughts on if changing this is breaking or not? To me, it doesn't seem breaking as it only affects newly published packages, it would make newly published packages avoid known failure cases, and I can't imagine anyone is relying on this behavior (consistently installing the same package and would be negatively impacted by the change in dependencies chosen).

epage avatar Jul 28 '22 20:07 epage

No, I don't think that behavior was intentional. I think it would be good to fix it. There is some risk that it might impact someone, but I think the risk is low enough that it shouldn't be too much of an issue.

ehuss avatar Jul 29 '22 00:07 ehuss

I haven't looked too closely, but I think #10910 is perhaps a bit too aggressive.

I might suggest a warning that triggers if: it is a virtual workspace AND it does not specify the resolver AND all members have an edition >= 2021. The solution to remove the warning is to specify workspace.resolver. That seems like the be the scenario that most people are running into, and shouldn't be too noisy for larger workspaces.

It's really unfortunate to force people to put boilerplate in the [workspace] definition, and I suspect the warning will be annoying for some. I can't think of a better way to avoid it.

I would be surprised if there are any workspaces that want to have disparate editions longterm

I do not think that is too unusual.

ehuss avatar Jul 29 '22 01:07 ehuss

I think it would be good to fix it

Great, that should fix all the actual build failures I can see coming from this.

That seems like the be the scenario that most people are running into, and shouldn't be too noisy for larger workspaces.

That's the scenario currently, but if we get a future edition 2030 which implies resolver 3 we'll have the same issue again, people upgrade their crates to edition 2030 and don't realise their workspace is still set to resolver 2. Though that may be mitigated by #10587 if people move to specifying workspace.edition instead of per-crate edition.

Nemo157 avatar Jul 29 '22 09:07 Nemo157

but if we get a future edition 2030 which implies resolver 3

While normally I don't like punting on problems as people are likely to forget about them, in this case I think the landscape could change significantly enough between now and then that a solution that negatively affects the now isn't worth it. For example, we've talked about adding lint control to cargo, giving users control over lints which opens the door to us being noisier in the future.

epage avatar Jul 29 '22 11:07 epage