By default GHC enables the -Woverflowed-literals
warning to emit a message if a literal's precision is too great for its type:
OverflowedLiterals.hs:10:12: warning: [GHC-97441] [-Woverflowed-literals]
Literal 258 is out of the Word8 range 0..255
|
10 | print (258 :: Word8)
| ^^^
OverflowedLiterals.hs:15:12: warning: [GHC-97441] [-Woverflowed-literals]
Literal 9223372036854775817 is out of the Int range -9223372036854775808..9223372036854775807
|
15 | print (9223372036854775817 :: Int)
| ^^^^^^^^^^^^^^^^^^^
Is there a way to enable this warning for a custom numeric type?
For example, I'd want this code
data Word4 = Word4 Bool Bool Bool Bool
instance Num Word4 where
...
main = print (17 :: Word4)
To cause the compiler to complain
StackoverflowExample:LINE:COL: warning: [GHC-97441] [-Woverflowed-literals]
Literal 17 is out of the Word4 range 0..15
No, or at least not with ghc
at the time of writing. The code to check this is located here [GitHub]:
warnAboutOverflowedLiterals dflags lit | wopt Opt_WarnOverflowedLiterals dflags , Just (i, tc) <- lit = if -- These only show up via the 'HsOverLit' route | sameUnique tc intTyConName -> check i tc minInt maxInt | sameUnique tc wordTyConName -> check i tc minWord maxWord | sameUnique tc int8TyConName -> check i tc (min' @Int8) (max' @Int8) | sameUnique tc int16TyConName -> check i tc (min' @Int16) (max' @Int16) | sameUnique tc int32TyConName -> check i tc (min' @Int32) (max' @Int32) | sameUnique tc int64TyConName -> check i tc (min' @Int64) (max' @Int64) | sameUnique tc word8TyConName -> check i tc (min' @Word8) (max' @Word8) | sameUnique tc word16TyConName -> check i tc (min' @Word16) (max' @Word16) | sameUnique tc word32TyConName -> check i tc (min' @Word32) (max' @Word32) | sameUnique tc word64TyConName -> check i tc (min' @Word64) (max' @Word64) | sameUnique tc naturalTyConName -> checkPositive i tc -- These only show up via the 'HsLit' route | sameUnique tc intPrimTyConName -> check i tc minInt maxInt | sameUnique tc wordPrimTyConName -> check i tc minWord maxWord | sameUnique tc int8PrimTyConName -> check i tc (min' @Int8) (max' @Int8) | sameUnique tc int16PrimTyConName -> check i tc (min' @Int16) (max' @Int16) | sameUnique tc int32PrimTyConName -> check i tc (min' @Int32) (max' @Int32) | sameUnique tc int64PrimTyConName -> check i tc (min' @Int64) (max' @Int64) | sameUnique tc word8PrimTyConName -> check i tc (min' @Word8) (max' @Word8) | sameUnique tc word16PrimTyConName -> check i tc (min' @Word16) (max' @Word16) | sameUnique tc word32PrimTyConName -> check i tc (min' @Word32) (max' @Word32) | sameUnique tc word64PrimTyConName -> check i tc (min' @Word64) (max' @Word64)
It thus hardcodes the different (implicit) data constructors to work with Int
, Word
, Int16
, Word32
, etc. and thus checks with the corresponding lower and upperbounds.
Strictly speaking, it might perhaps be possible, but currently not implemented. It will likely be a bit complicated to check if we know that the type to which 17
for example is converted, is of a type that is an instance of Num
and Bounded
, since it just translates 17
to fromInteger 17
.