nothunks-0.3.1: Examine values for unexpected thunks

Safe Haskell | None
Language | Haskell2010

NoThunks.Class

Contents

- Check a value for unexpected thunks
- Helpers for defining instances
- Deriving-via wrappers
- Generic class

Synopsis

- class NoThunks a where
  - noThunks :: Context -> a -> IO (Maybe ThunkInfo)
  - wNoThunks :: Context -> a -> IO (Maybe ThunkInfo)
  - showTypeOf :: Proxy a -> String
- data ThunkInfo = ThunkInfo {
  - thunkContext :: Context
  - thunkInfo :: Maybe Info
  }
- mkThunkInfo :: Context -> a -> IO ThunkInfo
- type Context = [String]
- type Info = String
- unsafeNoThunks :: NoThunks a => a -> Maybe ThunkInfo
- allNoThunks :: [IO (Maybe ThunkInfo)] -> IO (Maybe ThunkInfo)
- noThunksInValues :: NoThunks a => Context -> [a] -> IO (Maybe ThunkInfo)
- noThunksInKeysAndValues :: (NoThunks k, NoThunks v) => Context -> [(k, v)] -> IO (Maybe ThunkInfo)
- newtype OnlyCheckWhnf a = OnlyCheckWhnf a
- newtype OnlyCheckWhnfNamed (name :: Symbol) a = OnlyCheckWhnfNamed a
- newtype InspectHeap a = InspectHeap a
- newtype InspectHeapNamed (name :: Symbol) a = InspectHeapNamed a
- newtype AllowThunk a = AllowThunk a
- newtype AllowThunksIn (fields :: [Symbol]) a = AllowThunksIn a
- class GWNoThunks (a :: [Symbol]) (f :: Type -> Type) where
  - gwNoThunks :: proxy a -> Context -> f x -> IO (Maybe ThunkInfo)

# Check a value for unexpected thunks

class NoThunks a where Source #

Check a value for unexpected thunks

Minimal complete definition

Nothing

Methods

noThunks :: Context -> a -> IO (Maybe ThunkInfo) Source #

Check if the argument does not contain any unexpected thunks

For most datatypes, we should have that

    noThunks ctxt x == Nothing

if and only if

    checkContainsThunks x

For some datatypes however, some thunks are expected. For example, the internal fingertree `Sequence` might contain thunks (this is important for the asymptotic complexity of this data structure). However, we should still check that the values in the sequence don't contain any unexpected thunks.

This means that we need to traverse the sequence, which might force some of the thunks in the tree. In general, it is acceptable for `noThunks` to force such "expected thunks", as long as it always reports the unexpected thunks.

The default implementation of `noThunks` checks that the argument is in WHNF, and if so, adds the type into the context (using `showTypeOf` or `whereFrom` if available), and calls `wNoThunks`. See `ThunkInfo` for a detailed discussion of the type context.

See also discussion of caveats listed for `checkContainsThunks`.

wNoThunks :: Context -> a -> IO (Maybe ThunkInfo) Source #

Check that the argument is in normal form, assuming it is in WHNF.

The context will already have been extended with the type we're looking at, so all that's left is to look at the thunks inside the type. The default implementation uses GHC Generics to do this.

default wNoThunks :: (Generic a, GWNoThunks ('[] :: [Symbol]) (Rep a)) => Context -> a -> IO (Maybe ThunkInfo) Source #

showTypeOf :: Proxy a -> String Source #

Show type `a` (to add to the context)

We try hard to avoid `Typeable` constraints in this module: there are types with no `Typeable` instance but with a `NoThunks` instance (most important example are types such as `ST s` which rely on parametric polymorphism). By default we should therefore only show the "outer layer"; for example, if we have a type

    Seq (ST s ())

then `showTypeOf` should just give `Seq`, leaving it up to the instance for `ST` to decide how to implement `showTypeOf`; this keeps things compositional. The default implementation does precisely this using the metadata that GHC Generics provides.

For convenience, however, some of the `deriving via` newtype wrappers we provide do depend on `Typeable`; see below.

default showTypeOf :: (Generic a, GShowTypeOf (Rep a)) => Proxy a -> String Source #

#### Instances

Instances details

NoThunks ByteString Source # | Instance for string bytestrings Strict bytestrings shouldn't contain any thunks, but could, due to https://gitlab.haskell.org/ghc/ghc/issues/17290. However, such thunks can't retain any data that they shouldn't, and so it's safe to ignore such thunks.
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> ByteString -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> ByteString -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy ByteString -> String Source #
NoThunks ByteString Source # | Instance for lazy bytestrings Defined manually so that it piggy-backs on the one for strict bytestrings.
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> ByteString -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> ByteString -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy ByteString -> String Source #

NoThunks ShortByteString Source #

Instance for short bytestrings

We have

    data ShortByteString = SBS ByteArray#

Values of this type consist of a tag followed by an _unboxed_ byte array, which can't contain thunks. Therefore we only check WHNF.

Instance details Defined in NoThunks.Class Methods noThunks :: Context -> ShortByteString -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> ShortByteString -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy ShortByteString -> String Source #
NoThunks Void Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Void -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Void -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Void -> String Source #
NoThunks ThreadId Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> ThreadId -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> ThreadId -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy ThreadId -> String Source #
NoThunks All Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> All -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> All -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy All -> String Source #
NoThunks Any Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Any -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Any -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Any -> String Source #
NoThunks Int16 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Int16 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Int16 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Int16 -> String Source #
NoThunks Int32 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Int32 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Int32 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Int32 -> String Source #
NoThunks Int64 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Int64 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Int64 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Int64 -> String Source #
NoThunks Int8 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Int8 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Int8 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Int8 -> String Source #
NoThunks CallStack Source # | Since CallStacks can't retain application data, we don't want to check them for thunks at all
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> CallStack -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> CallStack -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy CallStack -> String Source #
NoThunks Word16 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Word16 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Word16 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Word16 -> String Source #
NoThunks Word32 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Word32 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Word32 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Word32 -> String Source #
NoThunks Word64 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Word64 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Word64 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Word64 -> String Source #
NoThunks Word8 Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Word8 -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Word8 -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Word8 -> String Source #
NoThunks Text Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Text -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Text -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Text -> String Source #
NoThunks Text Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Text -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Text -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Text -> String Source #
NoThunks Day Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Day -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Day -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Day -> String Source #
NoThunks DiffTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> DiffTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> DiffTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy DiffTime -> String Source #
NoThunks NominalDiffTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> NominalDiffTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> NominalDiffTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy NominalDiffTime -> String Source #
NoThunks UTCTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> UTCTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> UTCTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy UTCTime -> String Source #
NoThunks UniversalTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> UniversalTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> UniversalTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy UniversalTime -> String Source #
NoThunks TimeLocale Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> TimeLocale -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> TimeLocale -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy TimeLocale -> String Source #
NoThunks LocalTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> LocalTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> LocalTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy LocalTime -> String Source #
NoThunks TimeOfDay Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> TimeOfDay -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> TimeOfDay -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy TimeOfDay -> String Source #
NoThunks TimeZone Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> TimeZone -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> TimeZone -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy TimeZone -> String Source #
NoThunks ZonedTime Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> ZonedTime -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> ZonedTime -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy ZonedTime -> String Source #
NoThunks Integer Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Integer -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Integer -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Integer -> String Source #
NoThunks Natural Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Natural -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Natural -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Natural -> String Source #
NoThunks () Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> () -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> () -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy () -> String Source #
NoThunks Bool Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Bool -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Bool -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Bool -> String Source #
NoThunks Char Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Char -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Char -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Char -> String Source #
NoThunks Double Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Double -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Double -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Double -> String Source #
NoThunks Float Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Float -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Float -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Float -> String Source #
NoThunks Int Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Int -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Int -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Int -> String Source #
NoThunks Word Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Word -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Word -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy Word -> String Source #
NoThunks a => NoThunks (First a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> First a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> First a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (First a) -> String Source #
NoThunks a => NoThunks (Last a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Last a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Last a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Last a) -> String Source #
NoThunks a => NoThunks (Max a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Max a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Max a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Max a) -> String Source #
NoThunks a => NoThunks (Min a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Min a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Min a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Min a) -> String Source #
NoThunks a => NoThunks (WrappedMonoid a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> WrappedMonoid a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> WrappedMonoid a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (WrappedMonoid a) -> String Source #
NoThunks a => NoThunks (IntMap a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> IntMap a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> IntMap a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (IntMap a) -> String Source #
NoThunks a => NoThunks (Seq a) Source # | Instance for `Seq` checks elements only The internal fingertree in `Seq` might have thunks, which is essential for its asymptotic complexity.
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Seq a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Seq a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Seq a) -> String Source #
NoThunks a => NoThunks (Set a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Set a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Set a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Set a) -> String Source #
NoThunks a => NoThunks (NonEmpty a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> NonEmpty a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> NonEmpty a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (NonEmpty a) -> String Source #
NoThunks a => NoThunks (TVar a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> TVar a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> TVar a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (TVar a) -> String Source #
NoThunks a => NoThunks (Identity a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Identity a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Identity a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Identity a) -> String Source #
NoThunks a => NoThunks (First a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> First a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> First a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (First a) -> String Source #
NoThunks a => NoThunks (Last a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Last a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Last a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Last a) -> String Source #
NoThunks a => NoThunks (Dual a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Dual a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Dual a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Dual a) -> String Source #
NoThunks a => NoThunks (Product a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Product a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Product a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Product a) -> String Source #
NoThunks a => NoThunks (Sum a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Sum a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Sum a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Sum a) -> String Source #
NoThunks a => NoThunks (IORef a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> IORef a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> IORef a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (IORef a) -> String Source #
NoThunks a => NoThunks (MVar a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> MVar a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> MVar a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (MVar a) -> String Source #
NoThunks a => NoThunks (Ratio a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Ratio a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Ratio a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Ratio a) -> String Source #
NoThunks (IO a) Source # | We do not check IO actions for captured thunks by default See instance for `(a -> b)` for detailed discussion.
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> IO a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> IO a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (IO a) -> String Source #
NoThunks (AllowThunk a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> AllowThunk a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> AllowThunk a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (AllowThunk a) -> String Source #
Typeable a => NoThunks (InspectHeap a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> InspectHeap a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> InspectHeap a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (InspectHeap a) -> String Source #
Typeable a => NoThunks (OnlyCheckWhnf a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> OnlyCheckWhnf a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> OnlyCheckWhnf a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (OnlyCheckWhnf a) -> String Source #
NoThunks a => NoThunks (Vector a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Vector a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Vector a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Vector a) -> String Source #
NoThunks (Vector a) Source # | Unboxed vectors can't contain thunks Implementation note: defined manually rather than using `OnlyCheckWhnf` due to ghc limitation in deriving via, making it impossible to use with it with data families.
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Vector a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Vector a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Vector a) -> String Source #
NoThunks a => NoThunks (Maybe a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Maybe a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Maybe a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Maybe a) -> String Source #
NoThunks a => NoThunks (Solo a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Solo a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Solo a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Solo a) -> String Source #
NoThunks a => NoThunks [a] Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> [a] -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> [a] -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy [a] -> String Source #
(NoThunks a, NoThunks b) => NoThunks (Arg a b) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Arg a b -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Arg a b -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Arg a b) -> String Source #
(NoThunks k, NoThunks v) => NoThunks (Map k v) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Map k v -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Map k v -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Map k v) -> String Source #
(NoThunks a, NoThunks b) => NoThunks (Either a b) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Either a b -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Either a b -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Either a b) -> String Source #
(HasFields s a, Generic a, Typeable a, GWNoThunks s (Rep a)) => NoThunks (AllowThunksIn s a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> AllowThunksIn s a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> AllowThunksIn s a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (AllowThunksIn s a) -> String Source #
KnownSymbol name => NoThunks (InspectHeapNamed name a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> InspectHeapNamed name a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> InspectHeapNamed name a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (InspectHeapNamed name a) -> String Source #
KnownSymbol name => NoThunks (OnlyCheckWhnfNamed name a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> OnlyCheckWhnfNamed name a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> OnlyCheckWhnfNamed name a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (OnlyCheckWhnfNamed name a) -> String Source #
(NoThunks a, NoThunks b) => NoThunks (a, b) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b) -> String Source #

NoThunks (a -> b) Source #

We do NOT check function closures for captured thunks by default

Since we have no type information about the values captured in a thunk, the only check we could possibly do is `checkContainsThunks`: we can't recursively call `noThunks` on those captured values, which is problematic if any of those captured values requires a custom instance (for example, data types that depend on laziness, such as `Seq`).

By default we therefore only check if the function is in WHNF, and don't check the captured values at all. If you want a stronger check, you can use ``InspectHeap` (a -> b)` instead.

Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a -> b) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a -> b) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a -> b) -> String Source #
NoThunks (f a) => NoThunks (Ap f a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Ap f a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Ap f a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Ap f a) -> String Source #
NoThunks (f a) => NoThunks (Alt f a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> Alt f a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> Alt f a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (Alt f a) -> String Source #
(NoThunks a, NoThunks b, NoThunks c) => NoThunks (a, b, c) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b, c) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b, c) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b, c) -> String Source #
(NoThunks a, NoThunks b, NoThunks c, NoThunks d) => NoThunks (a, b, c, d) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b, c, d) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b, c, d) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b, c, d) -> String Source #
(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e) => NoThunks (a, b, c, d, e) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b, c, d, e) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b, c, d, e) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b, c, d, e) -> String Source #
(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e, NoThunks f) => NoThunks (a, b, c, d, e, f) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b, c, d, e, f) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b, c, d, e, f) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b, c, d, e, f) -> String Source #
(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e, NoThunks f, NoThunks g) => NoThunks (a, b, c, d, e, f, g) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> (a, b, c, d, e, f, g) -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> (a, b, c, d, e, f, g) -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (a, b, c, d, e, f, g) -> String Source #

data ThunkInfo Source #

Information about unexpected thunks

ThunkInfo contains either precise `Info` about the thunk location or `Context` to make it easier to debug space leaks. `Info` is available if

- `GHC-9.4` or newer is used,
- the code is compiled with `-finfo-table-map` and is improved if `-fdistinct-constructor-tables` is used as well.

The `Context` argument is intended to give a clue to add debugging. For example, suppose we have something of type `(Int, [Int])`. The various contexts we might get are

    Context                  The thunk is..
    ---------------------------------------------------------------------
    ["(,)"]                  the pair itself
    ["Int","(,)"]            the Int in the pair
    ["List","(,)"]           the [Int] in the pair
    ["Int","List","(,)"]     an Int in the [Int] in the pair

Note: prior to `ghc-9.6` a list was indicated by `[]`.

Constructors

ThunkInfo |

Fields

- thunkContext :: Context
- thunkInfo :: Maybe Info

#### Instances

Instances details

Show ThunkInfo Source # |
Instance details Defined in NoThunks.Class Methods showsPrec :: Int -> ThunkInfo -> ShowS Source # show :: ThunkInfo -> String Source # showList :: [ThunkInfo] -> ShowS Source #

mkThunkInfo :: Context -> a -> IO ThunkInfo Source #

Construct `ThunkInfo` either from `Context` or information provided by `GHC` about `a` (see `whereFrom`).

type Context = [String] Source #

Context where a thunk was found

This is intended to give a hint about which thunk was found. For example, a thunk might be reported with context

    ["Int", "(,)", "Map", "AppState"]

telling you that you have an `AppState` containing a `Map` containing a pair, all of which weren't thunks (were in WHNF), but that pair contained an `Int` which was a thunk.

type Info = String Source #

Binding name, type and location information about the thunk, e.g.

    fromModel :: Int @ test/Test/NoThunks/Class.hs:198:53-84

unsafeNoThunks :: NoThunks a => a -> Maybe ThunkInfo Source #

Call `noThunks` in a pure context (relies on `unsafePerformIO`).

# Helpers for defining instances

allNoThunks :: [IO (Maybe ThunkInfo)] -> IO (Maybe ThunkInfo) Source #

Short-circuit a list of checks

noThunksInValues :: NoThunks a => Context -> [a] -> IO (Maybe ThunkInfo) Source #

Check that all elements in the list are thunk-free

Does not check the list itself. Useful for checking the elements of a container.

See also `noThunksInKeysAndValues`

noThunksInKeysAndValues :: (NoThunks k, NoThunks v) => Context -> [(k, v)] -> IO (Maybe ThunkInfo) Source #

Variant on `noThunksInValues` for keyed containers.

Neither the list nor the tuples are checked for thunks.

# Deriving-via wrappers

newtype OnlyCheckWhnf a Source #

Newtype wrapper for use with `deriving via` to check for WHNF only

For some types we don't want to check for nested thunks, and we only want check if the argument is in WHNF, not in NF. A typical example are functions; see the instance of `(a -> b)` for detailed discussion. This should be used sparingly.

Example:

    deriving via OnlyCheckWhnf T instance NoThunks T

Constructors

OnlyCheckWhnf a |

#### Instances

Instances details

Typeable a => NoThunks (OnlyCheckWhnf a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> OnlyCheckWhnf a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> OnlyCheckWhnf a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (OnlyCheckWhnf a) -> String Source #

newtype OnlyCheckWhnfNamed (name :: Symbol) a Source #

Variant on `OnlyCheckWhnf` that does not depend on `Generic`

Example:

    deriving via OnlyCheckWhnfNamed "T" T instance NoThunks T

Constructors

OnlyCheckWhnfNamed a |

#### Instances

Instances details

KnownSymbol name => NoThunks (OnlyCheckWhnfNamed name a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> OnlyCheckWhnfNamed name a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> OnlyCheckWhnfNamed name a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (OnlyCheckWhnfNamed name a) -> String Source #

newtype InspectHeap a Source #

Newtype wrapper for use with `deriving via` to inspect the heap directly

This bypasses the class instances altogether, and inspects the GHC heap directly, checking that the value does not contain any thunks anywhere. Since we can do this without any type classes instances, this is useful for types that contain fields for which `NoThunks` instances are not available.

Since the primary use case for `InspectHeap` then is to give instances for `NoThunks` from third party libraries, we also don't want to rely on a `Generic` instance, which may likewise not be available. Instead, we will rely on `Typeable`, which is available for all types. However, as `showTypeOf` explains, requiring `Typeable` may not always be suitable; if it isn't, `InspectHeapNamed` can be used.

Example:

    deriving via InspectHeap T instance NoThunks T

Constructors

InspectHeap a |

#### Instances

Instances details

Typeable a => NoThunks (InspectHeap a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> InspectHeap a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> InspectHeap a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (InspectHeap a) -> String Source #

newtype InspectHeapNamed (name :: Symbol) a Source #

Variant on `InspectHeap` that does not depend on `Typeable`.

    deriving via InspectHeapNamed "T" T instance NoUnexpecedThunks T

Constructors

InspectHeapNamed a |

#### Instances

Instances details

KnownSymbol name => NoThunks (InspectHeapNamed name a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> InspectHeapNamed name a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> InspectHeapNamed name a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (InspectHeapNamed name a) -> String Source #

newtype AllowThunk a Source #

Newtype wrapper for values that should be allowed to be a thunk

This should be used VERY sparingly, and should ONLY be used on values (or, even rarer, types) which you are SURE cannot retain any data that they shouldn't. Bear in mind allowing a value of type `T` to be a thunk might cause a value of type `S` to be retained if `T` was computed from `S`.

Constructors

AllowThunk a |

#### Instances

Instances details

NoThunks (AllowThunk a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> AllowThunk a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> AllowThunk a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (AllowThunk a) -> String Source #

newtype AllowThunksIn (fields :: [Symbol]) a Source #

Newtype wrapper for records where some of the fields are allowed to be thunks.

Example:

    deriving via AllowThunksIn '["foo","bar"] T instance NoThunks T

This will create an instance that skips the thunk checks for the "foo" and "bar" fields.

Constructors

AllowThunksIn a |

#### Instances

Instances details

(HasFields s a, Generic a, Typeable a, GWNoThunks s (Rep a)) => NoThunks (AllowThunksIn s a) Source # |
Instance details Defined in NoThunks.Class Methods noThunks :: Context -> AllowThunksIn s a -> IO (Maybe ThunkInfo) Source # wNoThunks :: Context -> AllowThunksIn s a -> IO (Maybe ThunkInfo) Source # showTypeOf :: Proxy (AllowThunksIn s a) -> String Source #

# Generic class

class GWNoThunks (a :: [Symbol]) (f :: Type -> Type) where Source #

Generic infrastructure for checking for unexpected thunks

The `a` argument records which record fields are allowed to contain thunks; see `AllowThunksIn` and `GWRecordField`, below.

Methods

gwNoThunks :: proxy a -> Context -> f x -> IO (Maybe ThunkInfo) Source #

Check that the argument does not contain any unexpected thunks

Precondition: the argument is in WHNF.

#### Instances

Instances details

GWNoThunks a (U1 :: Type -> Type) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> U1 x -> IO (Maybe ThunkInfo) Source #
GWNoThunks a (V1 :: Type -> Type) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> V1 x -> IO (Maybe ThunkInfo) Source #
(GWNoThunks a f, GWNoThunks a g) => GWNoThunks a (f :*: g) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> (f :*: g) x -> IO (Maybe ThunkInfo) Source #
(GWNoThunks a f, GWNoThunks a g) => GWNoThunks a (f :+: g) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> (f :+: g) x -> IO (Maybe ThunkInfo) Source #
GWNoThunks a f => GWNoThunks a (C1 c f) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> C1 c f x -> IO (Maybe ThunkInfo) Source #
GWNoThunks a f => GWNoThunks a (D1 c f) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> D1 c f x -> IO (Maybe ThunkInfo) Source #
NoThunks c => GWNoThunks a (K1 i c :: Type -> Type) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> K1 i c x -> IO (Maybe ThunkInfo) Source #
(GWRecordField f (Elem fieldName a), KnownSymbol fieldName) => GWNoThunks a (S1 ('MetaSel ('Just fieldName) su ss ds) f) Source # | If `fieldName` is allowed to contain thunks, skip it.
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> S1 ('MetaSel ('Just fieldName) su ss ds) f x -> IO (Maybe ThunkInfo) Source #
GWNoThunks a f => GWNoThunks a (S1 ('MetaSel ('Nothing :: Maybe Symbol) su ss ds) f) Source # |
Instance details Defined in NoThunks.Class Methods gwNoThunks :: proxy a -> Context -> S1 ('MetaSel ('Nothing :: Maybe Symbol) su ss ds) f x -> IO (Maybe ThunkInfo) Source #