Compiler error when implementing traits for more than two tuples

I have a compiler error that I don't understand, so I am hoping that someone can help me here.
The most minimal example I found, where the error still happens looks like this:

#![allow(unused)]

struct Scal;
struct Vec2;
struct Vec3;

trait CanBeMultiplied {}

impl CanBeMultiplied for (Scal, Scal) {}
impl CanBeMultiplied for (Scal, Vec2) {}
impl CanBeMultiplied for (Scal, Vec3) {} // either without this line it compiles

fn op<Rhs>(rhs: Rhs)
where
    (Scal, Rhs): CanBeMultiplied,
{
}

fn problem<Shape>()
where
    (Scal, Shape): CanBeMultiplied, // or without this line it compiles
    (Scal, Scal): CanBeMultiplied,
{
    op(Scal {});
}

fn main() {}

(Rust Playground example)

I expected it to just compile, but the error I get, when not out-commenting one of the two marked lines, looks like this:

error[E0308]: mismatched types
  --> src/main.rs:24:8
   |
19 | fn problem<Shape>()
   |            ----- this type parameter
...
24 |     op(Scal {});
   |     -- ^^^^^^^ expected type parameter `Shape`, found struct `Scal`
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected type parameter `Shape`
                      found struct `Scal`
note: function defined here
  --> src/main.rs:13:4
   |
13 | fn op<Rhs>(rhs: Rhs)
   |    ^^      --------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

I'm not entirely sure what's happening there, I think the slightly weird set of bounds is confusing type inference.

Specifying the type in the function works

op::<Scal>(Scal {});

The problem with being explicit with the type is that the non-minimal example is about implementing the multiplication trait to provide a nice experience for someone using the library. The syntactic sugar of * would be nil if I had to say mul::<Scal> instead (or whatever the exact syntax for that would be).

Issue 20466 or one of the related ones.

1 Like