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

Bumping a transitive dependency breaks a build #48406

Closed
mathstuf opened this issue Feb 21, 2018 · 14 comments
Closed

Bumping a transitive dependency breaks a build #48406

mathstuf opened this issue Feb 21, 2018 · 14 comments
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@mathstuf
Copy link
Contributor

I work on the git-checks crate and an update to rayon-core:1.4.0 broke the build somehow with this build error:

error[E0277]: the trait bound `str: std::cmp::PartialOrd<std::string::String>` is not satisfied
  --> src/checks/lfs_pointer.rs:32:27
   |
32 |             } else if key < &old_key {
   |                           ^ can't compare `str` with `std::string::String`
   |
   = help: the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `str`
   = note: required because of the requirements on the impl of `std::cmp::PartialOrd<&std::string::String>` for `&str`

I've set up commits which show the error with just a change in Cargo.lock: working build broken build. Why would updating rayon-core, a dependency only by transitivity, break the build of the git-checks crate?

This happens when using any compiler from 1.17.0 (the minimum Rust version of git-checks) through nightly. I'll try and push back to older Rust versions to see if this worked before.

Originally filed in rayon-rs/rayon#542.

@mathstuf
Copy link
Contributor Author

It happens back to 1.13.0 as well. 1.12.0 fails because of ? usage in arrayvec.

@mathstuf
Copy link
Contributor Author

A simple case of just a library depending on rayon (or rayon-core) doesn't reproduce the problem. I'll try and trim down even more.

@mathstuf
Copy link
Contributor Author

Actually it does as soon as I add the extern crate rayon. Bisecting the dependency tree to find the real culprit.

@mathstuf
Copy link
Contributor Author

OK, this project breaks:

[package]
name = "dep-break"
version = "0.1.0"
authors = ["Ben Boeckel <mathstuf@gmail.com>"]

[dependencies]
arrayvec = "~0.3"
extern crate arrayvec;
pub fn cmp(p: String, n: &str) -> bool {
    n < &p
}

Changing it to arrayvec = "~0.2" works again. Bisecting arrayvec now.

@mathstuf
Copy link
Contributor Author

Cc: @bluss

@mathstuf
Copy link
Contributor Author

Bisected to bluss/arrayvec@0c8f467.

@cuviper cuviper added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. A-coercions Area: implicit and explicit `expr as Type` coercions labels Feb 21, 2018
@cuviper
Copy link
Member

cuviper commented Feb 21, 2018

As I noted on the rayon bug, it does work if you explicitly dereference like n < &*p, so this would seem to be a problem with deref coercion.

I guess the most relevant part of that bisected commit is:

impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str

@mathstuf
Copy link
Contributor Author

Indeed, commenting out that instance also gets a working build.

@cuviper
Copy link
Member

cuviper commented Feb 21, 2018

A self-contained reproducer:
https://play.rust-lang.org/?gist=f56aa402ac77885767d6dc4231d0125d&version=stable

use std::cmp::Ordering;

struct Foo;

impl PartialEq<Foo> for str {
    fn eq(&self, _: &Foo) -> bool {
        true
    }
}

impl PartialOrd<Foo> for str {
    fn partial_cmp(&self, _: &Foo) -> Option<Ordering> {
        Some(Ordering::Equal)
    }
}

pub fn cmp(p: String, n: &str) -> bool {
    n < &p
}

@cuviper
Copy link
Member

cuviper commented Feb 21, 2018

This Foo example fails all the way back to rustc 1.0.0. So maybe this is expected behavior, but it seems really unfortunate that this can't infer that we want PartialOrd<str> for str.
(especially when that's broken from afar, from a new impl in a totally separate crate!)

@mathstuf
Copy link
Contributor Author

It seems like the deref coersion is "pushing" from the potential impls of PartialOrd on the left hand side rather than looking through available Deref implementations of the right hand side (which makes more sense to me, but I don't know the compiler internals) and it fails once a PartialOrd is found without a matching Deref when it should instead continue the search.

@jonas-schievink
Copy link
Contributor

When the compiler only finds a single applicable impl, it eagerly selects it, which drives type inference forward. In this case, that infers the right-hand side to be &str, which will trigger the deref coercion. When there are more impls in scope (and apparently just doing extern crate x; pulls all impls from x into scope), this doesn't happen and the right hand side stays an uninferred type variable that is then unified with the &String on the right-hand side, which then causes the PartialOrd<String> not implemented error.

So I think this is just an unpleasant interaction of the above behaviour and the orphan rules, which allow such an impl to be written in the first place (both PartialOrd and str are from a different crate).

@mathstuf
Copy link
Contributor Author

Hmm, OK. We've fixed it by using .as_str() in our codebase (more explicit than &*). Was hoping it could go back to the old way, but it's not a big deal for our instance.

@jonas-schievink
Copy link
Contributor

Closing as not-a-bug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants