trait A<X> {}
trait B<X> {}
struct S;
impl<X> A<X> for S {}
impl<X, T: B<X>> A<X> for T {}
And when compiling I get the error: "conflicting implementations of trait A<_> for type S".
Why does the compiler use the impl for T : B when considering S? And why does doing X = i32 (removing X from the list and adding a type X = i32) solve it?
I believe this could strictly be allowed when the struct and both traits are from the same module, this is not an exception that is currently made.
What you are running into is that having both of these implementations added would make it a backwards incompatible change to implement B<X> for S. This could definitely be allowed when S, A, and B are all defined in the same module, but if they were defined in separate modules, it would turn an operation (adding a trait implementation to a struct) that is assumed backwards-compatible into a backwards-incompatible operation.
This could either be addressed with specialization, or with the Rust compiler being fixed/modified to accept this specific case to allow a blanket implementation + one specific implementation where both the blanket trait, the specific trait and the struct are defined in the same module.
The reason is that a different trait would be allowed to write an impl like so:
struct Foo;
impl B<Foo> for S {}
Which would make those two impls overlap. The coherence checker does not take privacy into account when determining this. Setting the default type and removing it from the trait impl is equivalent to saying
impl<T: B<i32>> A<i32> for T {}
which does not overlap, because S does not implement B<i32>, and no other crate could add such an impl.