Rust doesn't do method overloading. It finds methods by name, and then looks what arguments they are supposed to have. Type inference isn't a full constraint solver.
It's only a problem if both traits are in scope where you're calling the ambiguous name.
Yes, but Baz.foo(1) is doubly ambiguous. Given the way type inference flows in Rust, I think this is fine myself. How common are colliding trait method names where both traits are:
<Baz as Trait1>::foo(&Baz, 1);
<Baz as Trait2>::foo(&Baz, 2);
Admittedly, the syntax is neither pretty nor obvious. However, resolution by argument types would have problems of overloading. e.g. what if the traits are fn foo(&self, bar: impl Into<u8>) and fn foo(&self, bar: impl Into<u16>)? C++ has a whole hierarchy of types and conversions for disambiguating this, and it creates a lot of surprising situations.
This is incorrect, as noted by other posters. What the OP is asking for is closer to argument-dependent lookup, which is stronger than overloading.
A more accurate statement is that Rust's overload (read: trait impl) resolution algorithm does not rank overloads and gives up if the constraint solver does not come up with a unique answer to the query; C++ will try to pick the "most specific" overload.
You can observe function overloading at work by writing x << 1u8 and x << 1u32. These expand to different calls of Shl::shl().
That's not overloading, instead you should think of Shl::shl as being a single generic function
fn shl<A, B>(a: A, b: B) -> A::Output
where
A: Shl<B,
{ … }
Well perhaps it is overloading, depending on what you define as “overloading”, at least traits (i. e. “type classes”) were indeed (IIRC) initially invented in order to “overload” syntax like < or ==.