rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.83k stars 2.42k forks source link

Source replacements are ignored when producing compilation units #14821

Open P-E-Meunier opened 1 week ago

P-E-Meunier commented 1 week ago

Problem

When replacing sources in .cargo/config.toml so that two different sources point to the same vendored directory, cargo identifies a single package from two different sources as different, giving rise to a confusing error message where a type from a file is claimed to be distinct from itself:

error[E0308]: mismatched types
 --> src/main.rs:2:10
  |
2 |     b::b(c::C {});
  |     ---- ^^^^^^^ expected `c::C`, found `C`
  |     |
  |     arguments to this function are incorrect
  |
  = note: `C` and `c::C` have similar names, but are actually distinct types
note: `C` is defined in crate `c`
 --> /tmp/cargo-vendor-test/a/vendor/c/src/lib.rs:1:1
  |
1 | pub struct C {}
  | ^^^^^^^^^^^^
note: `c::C` is defined in crate `c`
 --> /tmp/cargo-vendor-test/a/vendor/c/src/lib.rs:1:1
  |
1 | pub struct C {}
  | ^^^^^^^^^^^^
  = note: perhaps two different versions of crate `c` are being used?
note: function defined here
 --> /tmp/cargo-vendor-test/a/vendor/b/src/lib.rs:1:8
  |
1 | pub fn b(_c: c::C) {}
  |        ^

Steps

  1. Clone https://github.com/P-E-Meunier/cargo-vendor-test
  2. Run a fake private registry from the root of the repo:
    cd cargo-vendor-test
    python -m http.server 8080 --bind 127.0.0.1 --directory .
  3. Run cargo vendor ../vendor from subdirectory a, which yields a wrong output (as per #14729).
  4. The correct output, to be written to a/.cargo/config.toml, should be:
[source."sparse+http://localhost:8080/registry-y/"]
registry = "sparse+http://localhost:8080/registry-y/"
replace-with = "vendored-sources"

[source."sparse+http://localhost:8080/registry-x/"]
registry = "sparse+http://localhost:8080/registry-x/"
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"
  1. Run cargo build from subdirectory a.
weihanglo commented 1 week ago

Ran cargo vendor didn't give me that output. With which version of Cargo under which directory should I run cargo vendor?

P-E-Meunier commented 1 week ago

So, in my example repo, you need to run those steps from subdirectory a. In #14729, you additionally need to start a fake private registry before, using the following command from the root of the repo:

python -m http.server 8080 --bind 127.0.0.1 --directory .
weihanglo commented 1 week ago

In https://github.com/rust-lang/cargo/issues/14729, you additionally need to start a fake private registry before

You need to start the fake registry in either of those, otherwise Cargo cannot connect to them.

Anyway I can reproduce it now. This reminds me https://github.com/rust-lang/cargo/issues/10310 though they don't seem to be the same, and also one of the two c crate is vendored. The issue is kind of hitting several bad cases of cargo vendor?

P-E-Meunier commented 1 week ago

It is indeed. This isn't an artificial case though, it was triggered by migrating a registry from one domain to another: some versions of some crates are mirrored on both, leading to this situation.

Fortunately, the fix for #14729 doesn't have any unintended effects: the only thing it does is replace more sources in .cargo/config.toml, which can't hurt if these registries aren't used, and fixes the issue when they are.

The fix for this issue is a little different, since it changes the rustc invocations when sources are replaced: