diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2021-07-01 16:55:47 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-07-02 00:27:42 -0400 |
commit | a820f9002d8f75385aaaa141ac3c6f001e8a9874 (patch) | |
tree | 05bd6dd982fd40e0a4cd4db683bebed6567e187d /libraries | |
parent | 6ac9ea86c339489e692730e849a88e86da730837 (diff) | |
download | haskell-a820f9002d8f75385aaaa141ac3c6f001e8a9874.tar.gz |
Detect underflow in fromIntegral/Int->Natural rule
Fix #20066
Diffstat (limited to 'libraries')
-rw-r--r-- | libraries/base/GHC/Real.hs | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/libraries/base/GHC/Real.hs b/libraries/base/GHC/Real.hs index df4143e1ee..6c7ae43e5c 100644 --- a/libraries/base/GHC/Real.hs +++ b/libraries/base/GHC/Real.hs @@ -597,7 +597,7 @@ fromIntegral = fromInteger . toInteger #-} -- Don't forget the type signatures in the following rules! Without a type --- signature we end up with the rule: +-- signature we ended up with the rule: -- -- "fromIntegral/Int->Natural" forall a (d::Integral a). -- fromIntegral @a @Natural = naturalFromWord . fromIntegral @a d @@ -606,12 +606,24 @@ fromIntegral = fromInteger . toInteger -- -- This rule wraps any Integral input into Word's range. As a consequence, -- (2^64 :: Integer) was incorrectly wrapped to (0 :: Natural), see #19345. +-- +-- A follow-up issue with this rule was that no underflow exception was raised +-- for negative Int values (see #20066). We now use a naturalFromInt helper +-- function to restore this behavior. {-# RULES -"fromIntegral/Word->Natural" fromIntegral = naturalFromWord :: Word -> Natural -"fromIntegral/Int->Natural" fromIntegral = naturalFromWord . fromIntegral :: Int -> Natural +"fromIntegral/Word->Natural" fromIntegral = naturalFromWord :: Word -> Natural +"fromIntegral/Int->Natural" fromIntegral = naturalFromInt :: Int -> Natural #-} +-- | Convert an Int into a Natural, throwing an underflow exception for negative +-- values. +naturalFromInt :: Int -> Natural +{-# INLINE naturalFromInt #-} +naturalFromInt x + | x < 0 = underflowError + | otherwise = naturalFromWord (fromIntegral x) + -- | general coercion to fractional types realToFrac :: (Real a, Fractional b) => a -> b {-# NOINLINE [1] realToFrac #-} |