@@ -43,7 +43,6 @@ import GHC.Stack (CallStack, prettyCallStack)
4343
4444#ifdef NO_IGNORE_ASSERTS
4545import Control.Concurrent (yield )
46- import qualified Control.Exception
4746import Data.IORef
4847import GHC.Stack (HasCallStack , callStack )
4948import System.IO.Unsafe (unsafeDupablePerformIO , unsafePerformIO )
@@ -282,7 +281,7 @@ deRef ref@Ref{refobj} =
282281--
283282withRef ::
284283 forall m obj a .
285- PrimMonad m
284+ ( PrimMonad m , MonadThrow m )
286285 => HasCallStackIfDebug
287286 => Ref obj
288287 -> (obj -> m a )
@@ -291,6 +290,10 @@ withRef ref@Ref{refobj} f = do
291290 assertNoUseAfterRelease ref
292291 assertNoForgottenRefs
293292 f refobj
293+ #ifndef NO_IGNORE_ASSERTS
294+ where
295+ _unused = throwIO @ m @ SomeException
296+ #endif
294297
295298{-# SPECIALISE
296299 dupRef ::
@@ -302,7 +305,7 @@ withRef ref@Ref{refobj} f = do
302305-- | Duplicate an existing reference, to produce a new reference.
303306--
304307dupRef ::
305- (RefCounted m obj , PrimMonad m )
308+ forall m obj . (RefCounted m obj , PrimMonad m , MonadThrow m )
306309 => HasCallStackIfDebug
307310 => Ref obj
308311 -> m (Ref obj )
@@ -311,6 +314,10 @@ dupRef ref@Ref{refobj} = do
311314 assertNoForgottenRefs
312315 incrementRefCounter (getRefCounter refobj)
313316 newRefWithTracker refobj
317+ #ifndef NO_IGNORE_ASSERTS
318+ where
319+ _unused = throwIO @ m @ SomeException
320+ #endif
314321
315322-- | A \"weak\" reference to an object: that is, a reference that does not
316323-- guarantee to keep the object alive. If however the object is still alive
@@ -483,42 +490,40 @@ finaliserRefTracker inner refid allocSite = do
483490 Just (refid', _) | refid < refid' -> return ()
484491 _ -> writeIORef globalForgottenRef (Just (refid, allocSite))
485492
486- assertNoForgottenRefs :: PrimMonad m => m ()
487- assertNoForgottenRefs =
488- unsafeIOToPrim $ do
489- mrefs <- readIORef globalForgottenRef
493+ assertNoForgottenRefs :: (PrimMonad m , MonadThrow m ) => m ()
494+ assertNoForgottenRefs = do
495+ mrefs <- unsafeIOToPrim $ readIORef globalForgottenRef
490496 case mrefs of
491497 Nothing -> return ()
492498 Just (refid, allocSite) -> do
493499 -- Clear the var so we don't assert again.
494- writeIORef globalForgottenRef Nothing
500+ unsafeIOToPrim $ writeIORef globalForgottenRef Nothing
495501 throwIO (RefNeverReleased refid allocSite)
496502
497- assertNoUseAfterRelease :: ( PrimMonad m , HasCallStack ) => Ref a -> m ()
498- assertNoUseAfterRelease Ref { reftracker = RefTracker refid _weak outer allocSite } =
499- unsafeIOToPrim $ do
500- released <- readIORef =<< readIORef outer
503+
504+ assertNoUseAfterRelease :: ( PrimMonad m , MonadThrow m , HasCallStack ) => Ref a -> m ()
505+ assertNoUseAfterRelease Ref { reftracker = RefTracker refid _weak outer allocSite } = do
506+ released <- unsafeIOToPrim ( readIORef =<< readIORef outer)
501507 case released of
502508 Nothing -> pure ()
503509 Just releaseSite -> do
504510 -- The site where the reference is used after release
505511 let useSite = callStack
506- Control.Exception. throwIO (RefUseAfterRelease refid allocSite releaseSite useSite)
512+ throwIO (RefUseAfterRelease refid allocSite releaseSite useSite)
507513#if !(MIN_VERSION_base(4,20,0))
508514 where
509515 _unused = callStack
510516#endif
511517
512- assertNoDoubleRelease :: (PrimMonad m , HasCallStack ) => Ref a -> m ()
513- assertNoDoubleRelease Ref { reftracker = RefTracker refid _weak outer allocSite } =
514- unsafeIOToPrim $ do
515- released <- readIORef =<< readIORef outer
518+ assertNoDoubleRelease :: (PrimMonad m , MonadThrow m , HasCallStack ) => Ref a -> m ()
519+ assertNoDoubleRelease Ref { reftracker = RefTracker refid _weak outer allocSite } = do
520+ released <- unsafeIOToPrim (readIORef =<< readIORef outer)
516521 case released of
517522 Nothing -> pure ()
518523 Just releaseSite1 -> do
519524 -- The second release site
520525 let releaseSite2 = callStack
521- Control.Exception. throwIO (RefDoubleRelease refid allocSite releaseSite1 releaseSite2)
526+ throwIO (RefDoubleRelease refid allocSite releaseSite1 releaseSite2)
522527#if !(MIN_VERSION_base(4,20,0))
523528 where
524529 _unused = callStack
@@ -532,7 +537,7 @@ assertNoDoubleRelease Ref { reftracker = RefTracker refid _weak outer allocSite
532537-- Note however that this is not the only place where 'RefNeverReleased'
533538-- exceptions can be thrown. All Ref operations poll for forgotten refs.
534539--
535- checkForgottenRefs :: IO ()
540+ checkForgottenRefs :: forall m . ( PrimMonad m , MonadThrow m ) => m ()
536541checkForgottenRefs = do
537542#ifndef NO_IGNORE_ASSERTS
538543 return ()
@@ -545,20 +550,22 @@ checkForgottenRefs = do
545550 -- Unfortunately, this relies on the implementation of the GHC scheduler,
546551 -- not on any Haskell specification, and is therefore both non-portable and
547552 -- presumably rather brittle. Therefore, for good measure, we do it twice.
548- performMajorGCWithBlockingIfAvailable
549- yield
550- performMajorGCWithBlockingIfAvailable
551- yield
553+ unsafeIOToPrim $ do
554+ performMajorGCWithBlockingIfAvailable
555+ yield
556+ performMajorGCWithBlockingIfAvailable
557+ yield
552558 assertNoForgottenRefs
553- where
554559#endif
560+ where
561+ _unused = throwIO @ m @ SomeException
555562
556563-- | Ignore and reset the state of forgotten reference tracking. This ensures
557564-- that any stale fogotten references are not reported later.
558565--
559566-- This is especillay important in QC tests with shrinking which otherwise
560567-- leads to confusion.
561- ignoreForgottenRefs :: IO ()
568+ ignoreForgottenRefs :: ( PrimMonad m , MonadCatch m ) => m ()
562569ignoreForgottenRefs = void $ try @ _ @ SomeException $ checkForgottenRefs
563570
564571#ifdef NO_IGNORE_ASSERTS
0 commit comments