In short: This is intended behavior.
The [x, y..z] expression is syntactical sugar for enumFromThenTo x y z with enumFromThenTo :: a -> a -> a -> [a].
For Integers it is implemented like:
instance Enum Integer where
# ...
enumFromThenTo x y lim = enumDeltaToInteger x (y-x) lim
So it will call enumDeltaToInteger 2 0 (-20). The enumDeltaToInteger is implemented with [src]:
enumDeltaToInteger :: Integer -> Integer -> Integer -> [Integer]
enumDeltaToInteger x delta lim
| delta >= 0 = up_list x delta lim
| otherwise = dn_list x delta lim
Soo it is considered to be an up_list, and the up_list will increase until it has reached a value larger than lim:
up_list :: Integer -> Integer -> Integer -> [Integer]
up_list x0 delta lim = go (x0 :: Integer)
where
go x | x > lim = []
| otherwise = x : go (x+delta)
This is how it has been described in the Haskell'10 report on the Enum class:
The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1 + i,e1 + 2i,…e3], where the increment, i, is e2 − e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3.
So the document says that if the "step" is zero or more, and e1 > e3, then the result is the empty list.
It is indeed a "tricky" case however. I personally agree that using a special case for 0 as "step" would make sense (although I'm not per se saying this is more favorable than using the up_list implementation). It is however how things are defined.