Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolver fails to update when swapping sources with increased requirements. #9240

Open
ehuss opened this issue Mar 5, 2021 · 1 comment
Open
Labels
A-dependency-resolution Area: dependency resolution and the resolver C-bug Category: bug

Comments

@ehuss
Copy link
Contributor

ehuss commented Mar 5, 2021

Problem
When changing the source of a direct dependency (for example, switching from crates.io to a git dependency), Cargo fails to poison the crates.io source. This results in all crates.io dependencies remaining "locked". If the git dependency introduces any increased requirements, they will fail to resolve because the old version is locked.

Steps
The real-world example is a bit large, but here it is:

  1. git checkout https://github.com/rust-lang/docs.rs.git
  2. cd docs.rs
  3. git checkout da1f36263ff70c02b119a9582c1228b08bd233f2
  4. Edit Cargo.toml, swap rustwide with: rustwide = { git = "https://github.com/jyn514/rustwide", rev = "60de530190b86fd8cc4dda772a96ce0208531d44" }
  5. cargo tree

Fails with the error:

error: failed to select a version for `miow`.
    ... required by package `mio v0.7.6`
    ... which is depended on by `tokio v1.0.1`
    ... which is depended on by `rustwide v0.12.0 (https://github.com/jyn514/rustwide?rev=60de530190b86fd8cc4dda772a96ce0208531d44#60de5301)`
    ... which is depended on by `docs-rs v0.6.0 (/Users/eric/Proj/rust/docs.rs)`
versions that meet the requirements `^0.3.6` are: 0.3.6

all possible versions conflict with previously selected packages.

  previously selected package `miow v0.3.3`
    ... which is depended on by `mio-named-pipes v0.1.6`
    ... which is depended on by `tokio v0.2.22`
    ... which is depended on by `docs-rs v0.6.0 (/Users/eric/Proj/rust/docs.rs)`

failed to select a version for `miow` which could resolve this conflict

A reduced example using Cargo's testsuite is:

use cargo_test_support::git;

#[cargo_test]
fn switches_source_poison() {
    // Issue with changing the source of a direct dependency, which results in
    // an elevated requirement for something locked in Cargo.lock.

    // Needy is here to add a transitive requirement to `conflict.`
    Package::new("needy", "1.0.0")
        .dep("conflict", "1.4")
        .publish();
    // Conflict causes all the trouble.
    Package::new("conflict", "1.4.0").publish();
    // Changeme will be replaced with a git dependency that has elevated requirements.
    Package::new("changeme", "1.0.0")
        .dep("conflict", "1.4")
        .publish();
    let base_manifest = r#"
        [package]
        name = "foo"
        version = "0.1.0"

        [dependencies]
        needy = "1.0"
    "#;
    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
                {}
                changeme = "1.0"
            "#,
                base_manifest
            ),
        )
        .file("src/lib.rs", "")
        .build();

    // Create a valid lock file.
    p.cargo("tree")
        .with_stdout(
            "\
foo v0.1.0 [..]
├── changeme v1.0.0
│   └── conflict v1.4.0
└── needy v1.0.0
    └── conflict v1.4.0
",
        )
        .run();

    // Swap `changeme` with a git dependency that has a newer requirement for `conflict`.
    let changeme_git = git::new("changeme", |project| {
        project
            .file(
                "Cargo.toml",
                r#"
                [package]
                name = "changeme"
                version = "2.0.0"

                [dependencies]
                conflict = "1.5"
            "#,
            )
            .file("src/lib.rs", "")
    });
    Package::new("conflict", "1.5.0").publish();
    p.change_file(
        "Cargo.toml",
        &format!(
            r#"
                {}
                changeme.git = '{}'
            "#,
            base_manifest,
            changeme_git.url()
        ),
    );

    // ****TODO**** This fails, but should succeed.
    // error: failed to select a version for `conflict`.
    //     ... required by package `needy v1.0.0`
    //     ... which is depended on by `foo v0.1.0 (/Users/eric/Proj/rust/cargo/target/cit/t0/foo)`
    // versions that meet the requirements `=1.4.0` are: 1.4.0
    //
    // all possible versions conflict with previously selected packages.
    //
    //   previously selected package `conflict v1.5.0`
    //     ... which is depended on by `changeme v2.0.0 (file:///Users/eric/Proj/rust/cargo/target/cit/t0/changeme#b28dec1c)`
    //     ... which is depended on by `foo v0.1.0 (/Users/eric/Proj/rust/cargo/target/cit/t0/foo)`
    //
    // failed to select a version for `conflict` which could resolve this conflict
    p.cargo("tree")
        .with_stdout(
            "\
foo v0.1.0 [..]
├── changeme v2.0.0 [..]
│   └── conflict v1.5.0
└── needy v1.0.0
    └── conflict v1.5.0
",
        )
        .run();
}

What's surprising to me is that cargo update -p rustwide --aggressive doesn't work, either. I would expect --aggressive to unlock all of those dependencies.

Possible Solution(s)
The issue is these lines of code. When the source changes, Cargo fails to poison crates.io, and thus keeping all dependencies locked. Due to the increased requirements in the git dependency, it can run into conflicts that it can't resolve because the old versions are locked.

I don't off-hand know how to solve this. Those lines are somewhat delicate, but I imagine being a little more aggressive with poisoning is the solution.

Notes

Output of cargo version: cargo 1.52.0-nightly (c68432f1e 2021-03-02)

@ehuss
Copy link
Contributor Author

ehuss commented Oct 22, 2021

See #9699 and #9994 for other examples that should be tested when addressing this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-dependency-resolution Area: dependency resolution and the resolver C-bug Category: bug
Projects
None yet
Development

No branches or pull requests

1 participant