diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2021-02-11 14:11:29 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-02-13 21:33:56 -0500 |
commit | 5e71dd3379ec4738c3f88271803d0de9b77e004f (patch) | |
tree | af9264330075bf1bc139b3d23153dcd822b0673d | |
parent | 3331b3ad0db55193832617f3af3b18182dc1d4af (diff) | |
download | haskell-5e71dd3379ec4738c3f88271803d0de9b77e004f.tar.gz |
Bignum: fix bogus rewrite rule (#19345)
Fix the following rule:
"fromIntegral/Int->Natural" fromIntegral = naturalFromWord . fromIntegral
Its type wasn't constrained to Int hence #19345.
-rw-r--r-- | libraries/base/GHC/Real.hs | 21 | ||||
-rw-r--r-- | testsuite/tests/lib/integer/T19345.hs | 12 | ||||
-rw-r--r-- | testsuite/tests/lib/integer/T19345.stdout | 1 | ||||
-rw-r--r-- | testsuite/tests/lib/integer/all.T | 2 |
4 files changed, 31 insertions, 5 deletions
diff --git a/libraries/base/GHC/Real.hs b/libraries/base/GHC/Real.hs index ee61e34e70..4329bb7355 100644 --- a/libraries/base/GHC/Real.hs +++ b/libraries/base/GHC/Real.hs @@ -580,14 +580,25 @@ fromIntegral = fromInteger . toInteger #-} {-# RULES -"fromIntegral/Natural->Natural" fromIntegral = id :: Natural -> Natural -"fromIntegral/Natural->Integer" fromIntegral = toInteger :: Natural->Integer -"fromIntegral/Natural->Word" fromIntegral = naturalToWord +"fromIntegral/Natural->Natural" fromIntegral = id :: Natural -> Natural +"fromIntegral/Natural->Integer" fromIntegral = toInteger :: Natural -> Integer +"fromIntegral/Natural->Word" fromIntegral = naturalToWord :: Natural -> Word #-} +-- Don't forget the type signatures in the following rules! Without a type +-- signature we end up with the rule: +-- +-- "fromIntegral/Int->Natural" forall a (d::Integral a). +-- fromIntegral @a @Natural = naturalFromWord . fromIntegral @a d +-- +-- but this rule is certainly not valid for every Integral type a! +-- +-- This rule wraps any Integral input into Word's range. As a consequence, +-- (2^64 :: Integer) was incorrectly wrapped to (0 :: Natural), see #19345. + {-# RULES -"fromIntegral/Word->Natural" fromIntegral = naturalFromWord -"fromIntegral/Int->Natural" fromIntegral = naturalFromWord . fromIntegral +"fromIntegral/Word->Natural" fromIntegral = naturalFromWord :: Word -> Natural +"fromIntegral/Int->Natural" fromIntegral = naturalFromWord . fromIntegral :: Int -> Natural #-} -- | general coercion to fractional types diff --git a/testsuite/tests/lib/integer/T19345.hs b/testsuite/tests/lib/integer/T19345.hs new file mode 100644 index 0000000000..41313a44e5 --- /dev/null +++ b/testsuite/tests/lib/integer/T19345.hs @@ -0,0 +1,12 @@ +{-# OPTIONS_GHC -O #-} +module Main where + +import Numeric.Natural + ( Natural ) + +a, q :: Natural +a = fromIntegral ( 18446744073709551616 :: Integer ) +q = 18446744073709551616 + +main :: IO () +main = print ( fromIntegral ( a `div` q ) :: Word ) diff --git a/testsuite/tests/lib/integer/T19345.stdout b/testsuite/tests/lib/integer/T19345.stdout new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/testsuite/tests/lib/integer/T19345.stdout @@ -0,0 +1 @@ +1 diff --git a/testsuite/tests/lib/integer/all.T b/testsuite/tests/lib/integer/all.T index 740fa0e606..7c9720ed1f 100644 --- a/testsuite/tests/lib/integer/all.T +++ b/testsuite/tests/lib/integer/all.T @@ -23,3 +23,5 @@ test('integerImportExport', [omit_ways(['ghci'])], compile_and_run, ['']) # Disable GMP only tests #test('integerGmpInternals', [], compile_and_run, ['']) + +test('T19345', [], compile_and_run, ['']) |