1
+ {-# LANGUAGE CPP #-}
1
2
{-# LANGUAGE MagicHash #-}
2
3
{-# LANGUAGE ScopedTypeVariables #-}
3
4
{-# LANGUAGE UnboxedTuples #-}
@@ -22,6 +23,13 @@ import Test.Tasty.QuickCheck (testProperty)
22
23
import qualified Data.HashMap.Lazy as HML
23
24
import qualified Data.HashMap.Strict as HMS
24
25
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
+
25
33
issue32 :: Assertion
26
34
issue32 = assert $ isJust $ HMS. lookup 7 m'
27
35
where
@@ -124,6 +132,61 @@ issue254Strict = do
124
132
touch mp
125
133
assert $ isNothing res
126
134
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
+
127
190
------------------------------------------------------------------------
128
191
-- * Test list
129
192
@@ -135,4 +198,12 @@ tests = testGroup "Regression tests"
135
198
, testProperty " issue39b" propEqAfterDelete
136
199
, testCase " issue254 lazy" issue254Lazy
137
200
, 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
+ ]
138
209
]
0 commit comments