Type inference knows that there is only 1 implementation of ParitalEq for integers, so it uses this to determine your types when you supply one type. But this falls over when you use a custom PartialEq parameterized on multiple integer types. Then Rust then defaults to i32, even if that is not an option.

I see! now your question is more clear. First of all, I love these kind of small little things that will hopefully lead to better understanding of the whole system, so thanks for asking this question

Rust’s type inference is based on Hindley-Milner algorithm, which (based on my understanding) matches the intuition of how inference should be made given usage and type assumptions that already exist (I cannot claim to understanding it deep enough though now).

Here pow has been defined for many integral types i8, i16, i32 etc. and since 3 can belong to more than one of those types (opposite to earlier vec example), then the type inference is confused so the compilation error.

It seems that type inference can take a hint though from assert_eq!(x, 3i32) and exclude other type possibilities. I don’t know at what extent ones can makes these hints. For example, I cannot explicitly exclude other type possibilities using assert_ne!(x, 3i8), assert_ne!(x, 3i16), ... (which kind of makes sense! )

So it seems that x will be of type i32 (in _1 = const 3i32;), because right before the scope ends, the type inference doesn’t have any other options and this is in contrast with having x.pow(3).But this is not a contradiction with saying that the default type of x is i32. It is so if and only if there’s no other possibilities.

I don’t know at what extent ones can makes these hints. For example, I cannot explicitly exclude other type possibilities using assert_ne!(x, 3i8), assert_ne!(x, 3i16), ... (which kind of makes sense! )

I don’t think assert_eq! is acting as a type hint directly, it is doing it through the impl of Eq. Thus assert_ne! would also do the same thing – assert_ne!(x, 3i8) would not tell the compiler that x is not an i8, it would tell the compiler that x is an i8 because that is what would be required to make the != compare work.

Neq wpuld add a new trait for almost no additional value, so that would have been a bad way to design the api. Remember, Eq means the values of the types are equal it says nothing of the types themselves. It just happens to be the case that integers are special cased to allow for better type inference.

That wouldn’t solve the problem either, because a Neq trait would still require the types to be specifically related for the ne operation to be defined. What you’re really thinking of is type inequality, not a trait for value inequality. And to do that, you could use something analogous to a function which requires two of the same type fn test<T>(a: T, b: T), which will produce a compile error if you pass it two unequal types. Rust doesn’t currently have a way to express inequality this way fn uneq<T, U>(a: T, b: U) where T != U. If rust had such a function, you could call it to tell the compiler that a value is not of some type.