ghc-plugs-out 1.0.0.0 → 2.0.0.0
raw patch · 16 files changed
+396/−51 lines, 16 filesdep +ghc-corroboratedep ~base
Dependencies added: ghc-corroborate
Dependency ranges changed: base
Files
- README.rst +10/−4
- changelog.md +7/−3
- ghc-plugs-out.cabal +84/−25
- plugins/call-count/CallCount/Impure/Plugin.hs +3/−1
- plugins/call-count/CallCount/Pure/Plugin.hs +81/−4
- plugins/call-count/CallCount/Pure/Plugin1.hs +60/−0
- plugins/call-count/CallCount/Pure/Plugin2.hs +5/−0
- plugins/call-count/CallCount/TcPlugin.hs +71/−7
- plugins/init/Undefined/Init/Plugin.hs +1/−1
- plugins/noop/NoOp/Plugin.hs +16/−4
- plugins/solve/Undefined/Solve/Plugin.hs +1/−1
- plugins/stop/Undefined/Stop/Plugin.hs +1/−1
- test-suites/counter-in-line-each/Main.hs +13/−0
- test-suites/counter-in-line/Main.hs +13/−0
- test-suites/counter-in-turn-each/Main.hs +15/−0
- test-suites/counter-in-turn/Main.hs +15/−0
README.rst view
@@ -6,14 +6,20 @@ Introduction -------------When getting ready to launch, one of the steps is the plugs-out test. Can the-spacecraft function on its own without power or fuel from all cables and+When getting ready to launch to space, one of the steps is the plugs-out test.+Can the spacecraft function on its own without power or fuel from all cables and umbilicals? When debugging GHC plugins, I've added tracing and changed the wiring. Rather than throw those edits away, I've collected them in `ghc-plugs-out`_, a package-of tests that don't supply any power or fuel for typechecking. It is the first-multiple library package I've put together [#]_.+of tests that don't supply typechecking. It is the first multiple library+package I've put together [#]_. The test suites in this package show how type+checker plugins interact with GHC depending on:++* their purity+* how they're wired up+* what options they see+* whether GHC needs help type checking Wiring Diagram --------------
changelog.md view
@@ -1,5 +1,9 @@ # Versions of ghc-plugs-out -## 1.0.0.0 Initial Release-Add tests that show how typechecker plugins interact with GHC depending on-their purity, how they're wired up and whether GHC needs help typechecking.+## 2.0 Options and Haddocks+* Add tests that show how options interact with type checker plugins.+* Add haddocks.++## 1.0 Initial Release+* Add tests that show how type checker plugins interact with GHC depending on+ their purity, how they're wired up and whether GHC needs help type checking.
ghc-plugs-out.cabal view
@@ -1,19 +1,31 @@ cabal-version: 3.0 name: ghc-plugs-out-version: 1.0.0.0+version: 2.0.0.0 synopsis: Type checker plugins without the type checking. description:- Tests that show how typechecker plugins interact with GHC depending on their- purity, how they're wired up and whether GHC needs help typechecking.+ A __plugs-out__ spacecraft has no cables or umbilicals connected. The plugins+ in this package are __plugs-out__ in the sense that they do no type checking.++ The test suites in this package show how type checker plugins interact with GHC+ depending on:++ * their purity++ * how they're wired up++ * what options they see++ * whether GHC needs help type checking+ category: Compiler Plugin author: Phil de Joux maintainer: phil.dejoux@blockscope.com-copyright: © 2020 Phil de Joux, © 2020 Block Scope Limited+copyright: © 2020-2022 Phil de Joux, © 2020-2022 Block Scope Limited homepage: https://github.com/blockscope/ghc-plugs-out license: MPL-2.0 license-file: LICENSE.md-tested-with: GHC == 8.8.3, GHC == 8.10.1+tested-with: GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.2 build-type: Simple extra-source-files: changelog.md, README.rst@@ -39,8 +51,9 @@ hs-source-dirs: plugins/noop build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , ghc+ , ghc-corroborate library undefined-init-plugin import: opts@@ -49,8 +62,9 @@ hs-source-dirs: plugins/init build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , ghc+ , ghc-corroborate , no-op-plugin library undefined-solve-plugin@@ -60,8 +74,9 @@ hs-source-dirs: plugins/solve build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , ghc+ , ghc-corroborate , no-op-plugin library undefined-stop-plugin@@ -71,8 +86,9 @@ hs-source-dirs: plugins/stop build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , ghc+ , ghc-corroborate , no-op-plugin library call-count-plugin@@ -80,12 +96,15 @@ exposed-modules: CallCount.TcPlugin CallCount.Pure.Plugin+ CallCount.Pure.Plugin1+ CallCount.Pure.Plugin2 CallCount.Impure.Plugin hs-source-dirs: plugins/call-count build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , ghc+ , ghc-corroborate , th-printf , no-op-plugin @@ -96,7 +115,7 @@ hs-source-dirs: test-suites/undef-init build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-init-plugin test-suite test-undefined-init-carefree@@ -106,7 +125,7 @@ hs-source-dirs: test-suites/undef-init-carefree build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-init-plugin test-suite test-undefined-solve@@ -116,7 +135,7 @@ hs-source-dirs: test-suites/undef-solve build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-solve-plugin test-suite test-undefined-solve-carefree@@ -126,7 +145,7 @@ hs-source-dirs: test-suites/undef-solve-carefree build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-solve-plugin test-suite test-undefined-stop@@ -136,7 +155,7 @@ hs-source-dirs: test-suites/undef-stop build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-stop-plugin test-suite test-undefined-stop-carefree@@ -146,7 +165,7 @@ hs-source-dirs: test-suites/undef-stop-carefree build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , undefined-stop-plugin test-suite test-wireup-pure-by-option@@ -157,7 +176,7 @@ test-suites/wireup-pure-by-option ghc-options: -Wall -fplugin CallCount.Pure.Plugin build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-wireup-pure-by-pragma@@ -167,7 +186,7 @@ hs-source-dirs: test-suites/wireup-pure-by-pragma build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-wireup-pure-by-both@@ -178,7 +197,7 @@ test-suites/wireup-pure-by-pragma ghc-options: -Wall -fplugin CallCount.Pure.Plugin build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-wireup-impure-by-option@@ -189,7 +208,7 @@ test-suites/wireup-impure-by-option ghc-options: -Wall -fplugin CallCount.Impure.Plugin build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-wireup-impure-by-pragma@@ -199,7 +218,7 @@ hs-source-dirs: test-suites/wireup-impure-by-pragma build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-wireup-impure-by-both@@ -210,7 +229,7 @@ test-suites/wireup-impure-by-pragma ghc-options: -Wall -fplugin CallCount.Impure.Plugin build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-counter-main@@ -220,9 +239,49 @@ hs-source-dirs: test-suites/counter-main build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin +test-suite test-in-turn+ import: opts+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test-suites/counter-in-turn+ build-depends:+ base >= 4.10 && < 5+ , call-count-plugin++test-suite test-in-line+ import: opts+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test-suites/counter-in-line+ build-depends:+ base >= 4.10 && < 5+ , call-count-plugin++test-suite test-in-turn-each+ import: opts+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test-suites/counter-in-turn-each+ build-depends:+ base >= 4.10 && < 5+ , call-count-plugin++test-suite test-in-line-each+ import: opts+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test-suites/counter-in-line-each+ build-depends:+ base >= 4.10 && < 5+ , call-count-plugin+ test-suite test-counter-foo-bar-main import: opts type: exitcode-stdio-1.0@@ -231,7 +290,7 @@ hs-source-dirs: test-suites/counter-foo-bar-main build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin test-suite test-counter-foobar-main@@ -242,5 +301,5 @@ hs-source-dirs: test-suites/counter-foobar-main build-depends:- base >= 4.13 && < 5+ base >= 4.10 && < 5 , call-count-plugin
plugins/call-count/CallCount/Impure/Plugin.hs view
@@ -1,6 +1,8 @@+-- | This module provides an impure call count plugin that prints a message each+-- time its called. See the pure "CallCount.Pure.Plugin" module for examples. module CallCount.Impure.Plugin (plugin) where -import Plugins (Plugin)+import GHC.Corroborate import NoOp.Plugin (mkImpureTcPlugin) import CallCount.TcPlugin (callCount)
plugins/call-count/CallCount/Pure/Plugin.hs view
@@ -1,8 +1,85 @@+-- | This module provides a pure call count plugin that prints a message each+-- time its called. This can be seen in the output of the script+-- @./build-wiring.sh@ that runs each test suite demonstrating a way to wire up+-- plugins that is not expected to fail. Those test suites with __pure__ in the+-- name use this plugin whereas those with __impure__ in the name use the impure+-- 'CallCount.Impure.Plugin.plugin'.+--+-- @+-- > cat ./build-wiring.sh+-- # The steps in .github/workflows/cabal.yml related to wiring up plugins.+-- # You might like to run cabal update and cabal clean before running this script.+-- cabal build all --disable-tests+-- cabal build test-wireup-pure-by-option+-- cabal build test-wireup-pure-by-pragma+-- cabal build test-wireup-pure-by-both+-- cabal build test-wireup-impure-by-option+-- cabal build test-wireup-impure-by-pragma+-- cabal build test-wireup-impure-by-both+-- cabal build test-counter-main+-- cabal build test-counter-foo-bar-main+-- cabal build test-counter-foobar-main⏎+-- @+--+-- @+-- > ./build-wiring.sh+-- ...+-- Building test suite 'test-wireup-pure-by-option'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-wireup-pure-by-pragma'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-wireup-pure-by-both'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-wireup-impure-by-option'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- [1 of 1] Compiling Main [Impure plugin forced recompilation]+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-wireup-impure-by-pragma'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- [1 of 1] Compiling Main [Impure plugin forced recompilation]+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-wireup-impure-by-both'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #1+-- [1 of 1] Compiling Main [Impure plugin forced recompilation]+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #1+-- ...+-- Building test suite 'test-counter-main'+-- [1 of 1] Compiling Main+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #2+-- ...+-- Building test suite 'test-counter-foo-bar-main'+-- [1 of 3] Compiling Bar+-- >>> GHC-TcPlugin #1+-- [2 of 3] Compiling Foo+-- >>> GHC-TcPlugin #1+-- [3 of 3] Compiling Main+-- ...+-- Building test suite 'test-counter-foobar-main'+-- [1 of 2] Compiling FooBar+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #2+-- [2 of 2] Compiling Main+-- @ module CallCount.Pure.Plugin (plugin) where -import Plugins (Plugin)-import NoOp.Plugin (mkPureTcPlugin)-import CallCount.TcPlugin (callCount)+import GHC.Corroborate+import NoOp.Plugin (mkPureOptTcPlugin)+import CallCount.TcPlugin (optCallCount) plugin :: Plugin-plugin = mkPureTcPlugin callCount+plugin = mkPureOptTcPlugin optCallCount
+ plugins/call-count/CallCount/Pure/Plugin1.hs view
@@ -0,0 +1,60 @@+-- | This module re-exports the call count plugin so that it is available from+-- another module name. This enables setting up tests between plugins and their+-- options when a module pulls in multiple plugins.+--+-- @+-- -- test-suites\/counter-in-line-each\/Main.hs+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin1 -fplugin-opt CallCount.Pure.Plugin1:A #-}+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin2 -fplugin-opt CallCount.Pure.Plugin2:B #-}+-- ...+-- Building test suite 'test-in-line-each'+-- [1 of 1] Compiling Main+-- >>> B #1+-- >>> A #1+-- >>> B #2+-- >>> A #2+-- @+--+-- @+-- -- test-suites\/counter-in-line\/Main.hs+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin -fplugin-opt CallCount.Pure.Plugin:A #-}+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin -fplugin-opt CallCount.Pure.Plugin:B #-}+-- ...+-- Building test suite 'test-in-line'+-- [1 of 1] Compiling Main+-- >>> AB #1+-- >>> AB #1+-- >>> AB #2+-- >>> AB #2+-- @+--+-- @+-- -- test-suites\/counter-in-turn-each\/Main.hs+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin1 #-}+-- {-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin1:A #-}+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin2 #-}+-- {-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin2:B #-}+-- ...+-- Building test suite 'test-in-turn-each'+-- [1 of 1] Compiling Main+-- >>> B #1+-- >>> A #1+-- >>> B #2+-- >>> A #2+-- @+--+-- @+-- -- test-suites\/counter-in-turn\/Main.hs+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin #-}+-- {-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin:A #-}+-- {-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin #-}+-- {-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin:B #-}+-- ...+-- Building test suite 'test-in-turn'+-- [1 of 1] Compiling Main+-- >>> AB #1+-- >>> AB #1+-- >>> AB #2+-- >>> AB #2+-- @+module CallCount.Pure.Plugin1 (plugin) where import CallCount.Pure.Plugin (plugin)
+ plugins/call-count/CallCount/Pure/Plugin2.hs view
@@ -0,0 +1,5 @@+-- | This module re-exports the call count plugin so that it is available from+-- another module name. This enables setting up tests between plugins and their+-- options when a module pulls in multiple plugins. See module+-- "CallCount.Pure.Plugin1" for examples.+module CallCount.Pure.Plugin2 (plugin) where import CallCount.Pure.Plugin (plugin)
plugins/call-count/CallCount/TcPlugin.hs view
@@ -1,23 +1,87 @@ {-# LANGUAGE QuasiQuotes, NamedFieldPuns #-} -module CallCount.TcPlugin (callCount) where+module CallCount.TcPlugin (callCount, optCallCount) where import Language.Haskell.Printf (s)+import Data.Maybe (fromMaybe) import Data.IORef (IORef)-import IOEnv (newMutVar, readMutVar, writeMutVar)-import TcPluginM (tcPluginIO)-import TcRnTypes (TcPluginResult(..), TcPlugin(..), unsafeTcPluginTcM)+import GHC.Corroborate+import NoOp.Plugin newtype State = State{callref :: IORef Int} +-- | A plugin that counts the number of times its 'tcPluginSolve' function is+-- called when GHC is type checking. callCount :: TcPlugin-callCount =+callCount = fromMaybe noOp $ optCallCount []++-- | This plugin does no type checking.+--+-- Any options passed are echoed as a prefix before the call count when+-- 'tcPluginSolve' is called. If no options are passed then __GHC-TcPlugin__ is+-- used instead as the prefix before the count like this test suite shows.+--+-- @+-- Building test suite 'test-counter-foobar-main'+-- [1 of 2] Compiling FooBar+-- >>> GHC-TcPlugin #1+-- >>> GHC-TcPlugin #2+-- [2 of 2] Compiling Main+-- @+--+-- The options passed to 'optCallCount' are echoed as a prefix in the test+-- suites called by @./build-opts.sh@.+--+-- @+-- > cat ./build-opts.sh+-- # The steps in .github\/workflows\/cabal.yml related to passing options to plugins.+-- # You might like to run cabal update and cabal clean before running this script.+-- cabal build test-in-turn+-- cabal build test-in-line+-- cabal build test-in-turn-each+-- cabal build test-in-line-each+-- @+--+-- @+-- > ./build-opts.sh+-- ...+-- Building test suite 'test-in-turn'+-- [1 of 1] Compiling Main+-- >>> AB #1+-- >>> AB #1+-- >>> AB #2+-- >>> AB #2+-- ...+-- Building test suite 'test-in-line'+-- [1 of 1] Compiling Main+-- >>> AB #1+-- >>> AB #1+-- >>> AB #2+-- >>> AB #2+-- ...+-- Building test suite 'test-in-turn-each'+-- [1 of 1] Compiling Main+-- >>> B #1+-- >>> A #1+-- >>> B #2+-- >>> A #2+-- ...+-- Building test suite 'test-in-line-each'+-- [1 of 1] Compiling Main+-- >>> B #1+-- >>> A #1+-- >>> B #2+-- >>> A #2+-- @+optCallCount :: [CommandLineOption] -> Maybe TcPlugin+optCallCount opts = Just $ TcPlugin- { tcPluginInit = return . State =<< (unsafeTcPluginTcM $ newMutVar 1)+ { tcPluginInit = State <$> unsafeTcPluginTcM (newMutVar 1) , tcPluginSolve = \State{callref = c} _ _ _ -> do n <- unsafeTcPluginTcM $ readMutVar c- tcPluginIO . putStrLn $ [s|>>> GHC-TcPlugin #%d|] n+ let msg = if null opts then "GHC-TcPlugin" else mconcat opts+ tcPluginIO . putStrLn $ [s|>>> %s #%d|] msg n unsafeTcPluginTcM $ writeMutVar c (n + 1) return $ TcPluginOk [] []
plugins/init/Undefined/Init/Plugin.hs view
@@ -1,6 +1,6 @@ module Undefined.Init.Plugin (plugin) where -import Plugins (Plugin)+import GHC.Corroborate import NoOp.Plugin (undefInit, mkPureTcPlugin) plugin :: Plugin
plugins/noop/NoOp/Plugin.hs view
@@ -1,13 +1,12 @@-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RankNTypes, CPP #-} module NoOp.Plugin ( plugin , noOp, undefInit, undefSolve, undefStop- , mkPureTcPlugin, mkImpureTcPlugin+ , mkPureTcPlugin, mkPureOptTcPlugin, mkImpureTcPlugin ) where -import Plugins (Plugin(..), tcPlugin, defaultPlugin, purePlugin, impurePlugin)-import TcRnTypes (TcPluginResult(..), TcPlugin(..))+import GHC.Corroborate plugin :: Plugin plugin = mkPureTcPlugin noOp@@ -59,12 +58,25 @@ mkPureTcPlugin p = defaultPlugin { tcPlugin = const $ Just p+#if __GLASGOW_HASKELL__ >= 806 , pluginRecompile = purePlugin+#endif } mkImpureTcPlugin :: TcPlugin -> Plugin mkImpureTcPlugin p = defaultPlugin { tcPlugin = const $ Just p+#if __GLASGOW_HASKELL__ >= 806 , pluginRecompile = impurePlugin+#endif+ }++mkPureOptTcPlugin :: ([CommandLineOption] -> Maybe TcPlugin) -> Plugin+mkPureOptTcPlugin p =+ defaultPlugin+ { tcPlugin = p+#if __GLASGOW_HASKELL__ >= 806+ , pluginRecompile = purePlugin+#endif }
plugins/solve/Undefined/Solve/Plugin.hs view
@@ -1,6 +1,6 @@ module Undefined.Solve.Plugin (plugin) where -import Plugins (Plugin)+import GHC.Corroborate import NoOp.Plugin (undefSolve, mkPureTcPlugin) plugin :: Plugin
plugins/stop/Undefined/Stop/Plugin.hs view
@@ -1,6 +1,6 @@ module Undefined.Stop.Plugin (plugin) where -import Plugins (Plugin)+import GHC.Corroborate import NoOp.Plugin (undefStop, mkPureTcPlugin) plugin :: Plugin
+ test-suites/counter-in-line-each/Main.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin1 -fplugin-opt CallCount.Pure.Plugin1:A #-}+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin2 -fplugin-opt CallCount.Pure.Plugin2:B #-}++module Main where++foo :: IO a+foo = undefined++bar :: IO a+bar = undefined++main :: IO ()+main = return ()
+ test-suites/counter-in-line/Main.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin -fplugin-opt CallCount.Pure.Plugin:A #-}+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin -fplugin-opt CallCount.Pure.Plugin:B #-}++module Main where++foo :: IO a+foo = undefined++bar :: IO a+bar = undefined++main :: IO ()+main = return ()
+ test-suites/counter-in-turn-each/Main.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin1 #-}+{-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin1:A #-}+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin2 #-}+{-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin2:B #-}++module Main where++foo :: IO a+foo = undefined++bar :: IO a+bar = undefined++main :: IO ()+main = return ()
+ test-suites/counter-in-turn/Main.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin #-}+{-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin:A #-}+{-# OPTIONS_GHC -fplugin CallCount.Pure.Plugin #-}+{-# OPTIONS_GHC -fplugin-opt CallCount.Pure.Plugin:B #-}++module Main where++foo :: IO a+foo = undefined++bar :: IO a+bar = undefined++main :: IO ()+main = return ()