Why is `2 + x = 7` valid Haskell?

It is valid because it defines + instead.

main = print (3 + 4)
   where -- silly redefinition of `+` follows
   0 + y = y
   x + y = x * ((x-1) + y)

Above, the Prelude (+) function is shadowed by a local binding. The result will be 24, not 7, consequently.

Turning on warnings should point out the dangerous shadowing.

<interactive>:11:6: warning: [-Wname-shadowing]
    This binding for ‘+’ shadows the existing binding

You're defining a local function called +.

2 + x = 7 is equivalent to (+) 2 x = 7, which is equivalent to

(+) y x | y == 2 = 7

x is an (unused) parameter, and the function is only defined if the first argument is 2. That's not very useful, but it explains why x is not visible outside.