Trait not implemented... while it is!

In a library, a trait is defined and implemented on ndarray::Array1: rust-sundials/src/vector/mod.rs at master · Chris00/rust-sundials · GitHub

Using the library (with the right feature) used to work but now (latest compiler, edition 2024), I have the error:

the trait `NVectorOps` is not implemented for `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>`

I also tried to implement the trait on the expanded type to no avail. Any help will be appreciated.

Are you sure it's the exact same version of ndarray as before?

1 Like

Aha, spot on — a different version of ndarray was used in each crate! Surprisingly, the compiler did not warn me (in other situations it says “two different versions of crate ndarray are being used; two types coming from two different versions of the same crate are different types even if they look the same”). It would be good is such a warning was also displayed in this case.

Thanks!

Does multiple_crate_versions not work?

Not in this particular case it seems.

Interesting. I wouldn't expect the Clippy lint to fire if a compilation error already occurs, but I don't know why it wouldn't fire when there isn't a compilation error.

When I create the below crate using ndarray 15.6.0:

#[cfg(feature = "nd")]
use ndarray::Array1;
pub trait Bar {}
#[cfg(feature = "nd")]
impl Bar for Array1<f64> {}

and the below crate that uses the above crate with the nd feature and ndarray 16.1.0:

#![deny(clippy::multiple_crate_versions, reason = "bad!")]
fn foo() {}

cargo clippy correctly causes a compilation failure due to multiple crate versions.

Perhaps I misinterpreted your desire. Maybe you want the compilation error to be augmented with the Clippy warning/error this way you know a possible solution (i.e., use a compatible version of the crate).

Don't really have time to experiment much with this but the tricky part is that there is a blanket implementation in the middle: rust-sundials/src/vector/mod.rs at master · Chris00/rust-sundials · GitHub

unsafe impl<T: NVectorOps> Vector for T {

and it is Vector that is used. Could it play a role?

Could you file a ticket against the compiler with a repro (ideally minimized)?

I don't think so, but I'm unsure what exactly you want to happen. Am I correct that what you'd like to happen is for the compiler to warn you about multiple versions of a crate even during a compilation error? cargo clippy seems to work no matter what when multiple_crate_versions is used, but only when compilation would otherwise succeed.

You can submit an improvement request so that the compiler always outputs a warning about multiple crate versions when a compilation error occurs or at least when error code E0277 is the reason for the compilation error.

Do note that we already have a check for multiple crate versions in E0277, but it might not catch OP's case.

Well the OP never stated that there was no hint. @Chris00, can you confirm when you get a compilation failure, there isn't also a hint telling you how to rectify it? For example, my simple example outputs the following:

 --> src/lib.rs:5:9
  |
5 |     foo(x)
  |     --- ^ the trait `Bar` is not implemented for `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `Bar` is implemented for `ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<[usize; 1]>>`

While the help doesn't explicitly state the version of ndarray, it should be enough to signal to you that there is an implementation somewhere which should in turn hopefully be enough for you to figure out that there is a crate version mismatch. Unless @ekuber, you're stating the error should explicitly talk about a crate version mismatch; if so, then my simple example doesn't do that either.

In case you're suggesting it should explicitly mention crate version mismatches, then the below should be pretty close to an MRE:

bar:

[zack@laptop bar]$ cat Cargo.toml
[package]
name = "bar"
version = "0.1.0"
edition = "2024"

[dependencies]
ndarray = { version = "0.15.6", default-features = false }
use ndarray::Array1;
pub trait Bar {}
impl Bar for Array1<f64> {}

foo:

[zack@laptop foo]$ cat Cargo.toml
[package]
name = "foo"
version = "0.1.0"
edition = "2024"

[dependencies]
bar = { version = "0.1.0", path = "../bar", default-features = false }
ndarray = { version = "0.16.1", default-features = false }
use bar::Bar;
use ndarray::Array1;
fn foo<T: Bar>(_x: T) {}
fn bar(x: Array1<f64>) {
    foo(x)
}
[zack@laptop foo]$ cargo build
    Updating crates.io index
     Locking 11 packages to latest Rust 1.87.0 compatible versions
   Compiling autocfg v1.4.0
   Compiling rawpointer v0.2.1
   Compiling num-traits v0.2.19
   Compiling matrixmultiply v0.3.10
   Compiling num-integer v0.1.46
   Compiling num-complex v0.4.6
   Compiling ndarray v0.15.6
   Compiling ndarray v0.16.1
   Compiling bar v0.1.0 (/home/zack/projects/bar)
   Compiling foo v0.1.0 (/home/zack/projects/foo)
error[E0277]: the trait bound `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>: Bar` is not satisfied
 --> src/lib.rs:5:9
  |
5 |     foo(x)
  |     --- ^ the trait `Bar` is not implemented for `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `Bar` is implemented for `ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<[usize; 1]>>`
note: required by a bound in `foo`
 --> src/lib.rs:3:11
  |
3 | fn foo<T: Bar>(_x: T) {}
  |           ^^^ required by this bound in `foo`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `foo` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
1 Like

Here is the error message (paths slightly elided as they contain names):

error[E0277]: the trait bound `ArrayBase<..., ...>: NVectorOps` is not satisfied
   --> src/fem.rs:619:13
    |
619 |             CVode::bdf(μ0, u0, |μ, u, du| {
    |             ^^^^^ unsatisfied trait bound
    |
    = help: the trait `NVectorOps` is not implemented for `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>`
    = help: the following other types implement trait `NVectorOps`:
              (T1, T2)
              (T1, T2, T3)
              (T1, T2, T3, T4)
              (T1, T2, T3, T4, T5)
              (T1, T2, T3, T4, T5, T6)
              (T1, T2, T3, T4, T5, T6, T7)
              (T1, T2, T3, T4, T5, T6, T7, T8)
              (T1, T2, T3, T4, T5, T6, T7, T8, T9)
            and 8 others
    = note: required for `ArrayBase<OwnedRepr<f64>, Dim<[usize; 1]>>` to implement `sundials::vector::Vector`
note: required by a bound in `CVode`
   --> /home/XXX/.cargo/git/checkouts/rust-sundials-159b099bdbe5b731/18c02a8/src/cvode.rs:389:10
    |
388 | pub struct CVode<Ctx, V, CB>
    |            ----- required by a bound in this struct
389 | where V: Vector,
    |          ^^^^^^ required by this bound in `CVode`
    = note: the full name for the type has been written to '/.../superlinear-sign-changing/target/debug/deps/superlinear_sign_changing-1983a759068f60d7.long-type-11300553151382703642.txt'
    = note: consider using `--verbose` to print the full type name to the console