1+ {-# LANGUAGE CPP #-}
12{-# LANGUAGE MagicHash #-}
23{-# LANGUAGE ScopedTypeVariables #-}
34{-# LANGUAGE UnboxedTuples #-}
@@ -22,6 +23,13 @@ import Test.Tasty.QuickCheck (testProperty)
2223import qualified Data.HashMap.Lazy as HML
2324import qualified Data.HashMap.Strict as HMS
2425
26+ #if MIN_VERSION_base(4,12,0)
27+ -- nothunks requires base >= 4.12
28+ #define HAVE_NOTHUNKS
29+ import qualified Data.Foldable as Foldable
30+ import NoThunks.Class (noThunksInValues )
31+ #endif
32+
2533issue32 :: Assertion
2634issue32 = assert $ isJust $ HMS. lookup 7 m'
2735 where
@@ -124,6 +132,61 @@ issue254Strict = do
124132 touch mp
125133 assert $ isNothing res
126134
135+ ------------------------------------------------------------------------
136+ -- Issue #379
137+
138+ #ifdef HAVE_NOTHUNKS
139+
140+ issue379Union :: Assertion
141+ issue379Union = do
142+ let m0 = HMS. fromList [(KC 1 , () ), (KC 2 , () )]
143+ let m1 = HMS. fromList [(KC 2 , () ), (KC 3 , () )]
144+ let u = m0 `HMS.union` m1
145+ mThunkInfo <- noThunksInValues mempty (Foldable. toList u)
146+ assert $ isNothing mThunkInfo
147+
148+ issue379StrictUnionWith :: Assertion
149+ issue379StrictUnionWith = do
150+ let m0 = HMS. fromList [(KC 1 , 10 ), (KC 2 , 20 :: Int )]
151+ let m1 = HMS. fromList [(KC 2 , 20 ), (KC 3 , 30 )]
152+ let u = HMS. unionWith (+) m0 m1
153+ mThunkInfo <- noThunksInValues mempty (Foldable. toList u)
154+ assert $ isNothing mThunkInfo
155+
156+ issue379StrictUnionWithKey :: Assertion
157+ issue379StrictUnionWithKey = do
158+ let m0 = HMS. fromList [(KC 1 , 10 ), (KC 2 , 20 :: Int )]
159+ let m1 = HMS. fromList [(KC 2 , 20 ), (KC 3 , 30 )]
160+ let u = HMS. unionWithKey (\ (KC i) v0 v1 -> i + v0 + v1) m0 m1
161+ mThunkInfo <- noThunksInValues mempty (Foldable. toList u)
162+ assert $ isNothing mThunkInfo
163+
164+ #endif
165+
166+ -- Another key type that always collides.
167+ --
168+ -- Note (sjakobi): The KC newtype of Int somehow can't be used to demonstrate
169+ -- the space leak in issue379LazyUnionWith. This type does the trick.
170+ newtype SC = SC String
171+ deriving (Eq , Ord , Show )
172+ instance Hashable SC where
173+ hashWithSalt salt _ = salt
174+
175+ issue379LazyUnionWith :: Assertion
176+ issue379LazyUnionWith = do
177+ i :: Int <- randomIO
178+ let k = SC (show i)
179+ weakK <- mkWeakPtr k Nothing -- add the ability to test whether k is alive
180+ let f :: Int -> Int
181+ f x = error (" Should not be evaluated " ++ show x)
182+ let m = HML. fromList [(SC " 1" , f 1 ), (SC " 2" , f 2 ), (k, f 3 )]
183+ let u = HML. unionWith (+) m m
184+ Just v <- evaluate $ HML. lookup k u
185+ performGC
186+ res <- deRefWeak weakK -- gives Just if k is still alive
187+ touch v -- makes sure that we didn't GC away the combined value
188+ assert $ isNothing res
189+
127190------------------------------------------------------------------------
128191-- * Test list
129192
@@ -135,4 +198,12 @@ tests = testGroup "Regression tests"
135198 , testProperty " issue39b" propEqAfterDelete
136199 , testCase " issue254 lazy" issue254Lazy
137200 , testCase " issue254 strict" issue254Strict
201+ , testGroup " issue379"
202+ [ testCase " Lazy.unionWith" issue379LazyUnionWith
203+ #ifdef HAVE_NOTHUNKS
204+ , testCase " union" issue379Union
205+ , testCase " Strict.unionWith" issue379StrictUnionWith
206+ , testCase " Strict.unionWithKey" issue379StrictUnionWithKey
207+ #endif
208+ ]
138209 ]
0 commit comments