Description
This code compiles fine:
use core::ops::Mul;
#[derive(Debug)]
struct Foo(i32);
impl Mul<Foo> for i32 {
type Output = Foo;
fn mul(self, other: Foo) -> Self::Output {
Foo(self * other.0)
}
}
fn main() {
let prod1 = 7 * Foo(6);
assert_eq!(prod1.0, 42);
}
Adding an impl Mul<Foo> for i8
(or any other integer type) breaks the type inference happening on the first line of main()
(playground link):
use core::ops::Mul;
#[derive(Debug)]
struct Foo(i32);
impl Mul<Foo> for i32 {
type Output = Foo;
fn mul(self, other: Foo) -> Self::Output {
Foo(self * other.0)
}
}
impl Mul<Foo> for i8 {
type Output = Foo;
fn mul(self, other: Foo) -> Self::Output {
Foo(self as i32 * other.0)
}
}
fn main() {
let prod1 = 7 * Foo(6);
assert_eq!(prod1.0, 42);
}
The stable (1.61.0) compiler gives a better message about what's really happening here as compared to the beta or nightly (1.62.0, 1.63.0) versions. Stable prints this:
error[[E0282]](https://doc.rust-lang.org/stable/error-index.html#E0282): type annotations needed
--> src/main.rs:24:16
|
23 | let prod1 = 7 * Foo(6);
| ----- consider giving `prod1` a type
24 | assert_eq!(prod1.0, 42);
| ^^^^^ cannot infer type
|
= note: type must be known at this point
error[[E0283]](https://doc.rust-lang.org/stable/error-index.html#E0283): type annotations needed
--> src/main.rs:23:19
|
23 | let prod1 = 7 * Foo(6);
| ^ cannot infer type for type `{integer}`
|
note: multiple `impl`s satisfying `{integer}: Mul<Foo>` found
--> src/main.rs:6:1
|
6 | impl Mul<Foo> for i32 {
| ^^^^^^^^^^^^^^^^^^^^^
...
14 | impl Mul<Foo> for i8 {
| ^^^^^^^^^^^^^^^^^^^^
The outputs of all the Mul
impl blocks are non-diverging and produce Foo
for all inputs. Theoretically, specifying let prod1: Foo = ...
instead of let prod1 = ...
would do nothing to ameliorate the situation (since either i8 or i32 impl could satisfy the code as written, even with the additional type constraint). However, simply supplying the prod1: Foo
type specifier fixes the inference and lets rust's default integer preference succeed: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bf76c0fa2edf27dc656a7bc07ecaab12
Note that this doesn't happen for the commutative equivalent (Foo * numeric
rather than numeric * Foo
) with the correct Mul
impls in place.
rust seems to know that the output is Foo
in all cases, because the following emits an error with the correct type:
fn main() {
let mut prod1 = 7 * Foo(6);
prod1 = ();
//assert_eq!(prod1.0, 42);
}
error[[E0271]](https://doc.rust-lang.org/nightly/error-index.html#E0271): type mismatch resolving `<i32 as Mul<Foo>>::Output == ()`
--> src/main.rs:39:23
|
39 | let mut prod1 = 7 * Foo(6);
| ^ type mismatch resolving `<i32 as Mul<Foo>>::Output == ()`
|
note: expected this to be `Foo`
--> src/main.rs:23:19
|
23 | type Output = Foo;
| ^^^
So there's no reason why : Foo
needs to be specified explicitly.
Meta
rustc --version --verbose
:
2022-06-20 5750a6aa2777382bf421