{-# LANGUAGE TemplateHaskell #-} module WorkerWrapper (main) where import Test.Inspection -- In this module, we are interested in checking if the worker-wrapper transformation is firing. -- That transformation is described here: -- https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/compiler/demand#worker-wrapper-split -- In short, we don't want to be passing around the dictionary type below, but rather have GHC -- generate a helper function @$wdictFold :: (m -> m -> m) -> m -> [m] -> m@, as this saves us some -- wrapping and unwrapping work at each iteration. -- -- GHC still generates a wrapper at the @dictFold@ name. That is, a function that still consumes the -- @MonoidDict@ type, but unwraps it just once, before passing it off to @wdictFold@ to handle the -- recuresion. As @dictFold@ refers to this wrapper, we cannot check that the @MonoidDict@ type is -- unused in its definition. -- -- So what are we to do? As the generated wrapper should have an @INLINE@ pragma, once we pass it in -- the @MonoidDict@, we should be safely in worker-land, and not need to reference @MonoidDict@ -- again. Thus, we look at @appliedFold@, and assert that @MonoidDict@ never shows up -- as would be -- expected if worker-wrapper fired as hoped. data MonoidDict a = MonoidDict { dictMappend :: a -> a -> a, dictMempty :: a } dictFold :: MonoidDict m -> [m] -> m dictFold bm xs = case xs of [] -> dictMempty bm x:xs' -> dictMappend bm x $ dictFold bm xs' appliedFold :: [Int] -> Int appliedFold = dictFold $ MonoidDict (+) 0 inspect $ 'appliedFold `doesNotUse` 'MonoidDict main :: IO () main = return ()