It should compile perfectly fine, the overflow error occurs at runtime.
But to answer your question, it overflows because @w * @h is still an UInt16 multiplied with an UInt16 and Crystal only casts this value to an UInt32 after the calculation.
You can fix this by casting @w to a UInt32 before multiplying it, like @w.to_u32 * @h.