summaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2020-07-27 14:50:37 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-07-28 02:02:27 -0400
commit6ee07b494ddd0131d53ea2fd6a4bb29cd05f4dd8 (patch)
treecd98755c2466c9fdb6a736a8442d55fa44ac4bf3 /libraries
parent0bd60059b0edfee9e8f66c6817257bbb946656cd (diff)
downloadhaskell-6ee07b494ddd0131d53ea2fd6a4bb29cd05f4dd8.tar.gz
Bignum: add support for negative shifts (fix #18499)
shiftR/shiftL support negative arguments despite Haskell 2010 report saying otherwise. We explicitly test for negative values which is bad (it gets in the way of constant folding, etc.). Anyway, for consistency we fix Bits instancesof Integer/Natural.
Diffstat (limited to 'libraries')
-rw-r--r--libraries/base/Data/Bits.hs20
1 files changed, 16 insertions, 4 deletions
diff --git a/libraries/base/Data/Bits.hs b/libraries/base/Data/Bits.hs
index 5379eac571..89702105eb 100644
--- a/libraries/base/Data/Bits.hs
+++ b/libraries/base/Data/Bits.hs
@@ -537,8 +537,14 @@ instance Bits Integer where
(.|.) = integerOr
xor = integerXor
complement = integerComplement
- shiftR x i = integerShiftR x (fromIntegral i)
- shiftL x i = integerShiftL x (fromIntegral i)
+ unsafeShiftR x i = integerShiftR x (fromIntegral i)
+ unsafeShiftL x i = integerShiftL x (fromIntegral i)
+ shiftR x i@(I# i#)
+ | isTrue# (i# >=# 0#) = unsafeShiftR x i
+ | otherwise = overflowError
+ shiftL x i@(I# i#)
+ | isTrue# (i# >=# 0#) = unsafeShiftL x i
+ | otherwise = overflowError
shift x i | i >= 0 = integerShiftL x (fromIntegral i)
| otherwise = integerShiftR x (fromIntegral (negate i))
testBit x i = integerTestBit x (fromIntegral i)
@@ -560,8 +566,14 @@ instance Bits Natural where
xor = naturalXor
complement _ = errorWithoutStackTrace
"Bits.complement: Natural complement undefined"
- shiftR x i = naturalShiftR x (fromIntegral i)
- shiftL x i = naturalShiftL x (fromIntegral i)
+ unsafeShiftR x i = naturalShiftR x (fromIntegral i)
+ unsafeShiftL x i = naturalShiftL x (fromIntegral i)
+ shiftR x i@(I# i#)
+ | isTrue# (i# >=# 0#) = unsafeShiftR x i
+ | otherwise = overflowError
+ shiftL x i@(I# i#)
+ | isTrue# (i# >=# 0#) = unsafeShiftL x i
+ | otherwise = overflowError
shift x i
| i >= 0 = naturalShiftL x (fromIntegral i)
| otherwise = naturalShiftR x (fromIntegral (negate i))