Methods are contravariant in their argument types. Let me take your example and explain:
val b: B = new B
val y: Y = new Y
b.run(y) // everything is ok
val a: A = b // B is A
val x: X = new X {}
a.run(x) // run on A takes an X. x is of type X
// But: B only takes a Y (more specific type) --> Boom
Let me formulate this in words: In order to support the interface defined in A, B needs to be able to work with any X in its run method. So you cannot know for sure the X it is going to get is also a Y.
Note that you are actually allowed to do the opposite:
class B extends A { def run(x: Any) = /* snip */ }
Since B accepts any value in its run method, it also accepts an X, so everything is fine.
It is interesting to see, that return values are the other way around:
trait A {
def foo: X
}
class B extends A {
def foo: Y = /* snip */
}
This is valid, since B just has to return some X. Any Y is also a X, so we are good.
I hope this made it a bit clearer what is going on here and why the compiler forbids you implement your methods that way.