[GHC] #10078: tcPluginStop of a type checker plugin is not called if an error occurs
GHC
ghc-devs at haskell.org
Tue Feb 10 15:06:30 UTC 2015
#10078: tcPluginStop of a type checker plugin is not called if an error occurs
-------------------------------------+-------------------------------------
Reporter: jbracker | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.11
(Type checker) | Operating System: Linux
Keywords: | Type of failure: Incorrect result
Architecture: x86_64 | at runtime
(amd64) | Blocked By:
Test Case: | Related Tickets:
Blocking: |
Differential Revisions: |
-------------------------------------+-------------------------------------
When a module using a type checker plugin produces a compiler error the
clean up function `tcPluginStop` of the plugin is not called.
I am not sure if this is intended, but according to the description of the
wiki page (Plugins/TypeChecker) this should always be called.
=== Test plugin
`MyPlugin.hs`:
{{{#!hs
module MyPlugin
( plugin ) where
import Plugins
import TcRnTypes
import TcPluginM
plugin :: Plugin
plugin = defaultPlugin
{ tcPlugin = \clos -> Just $ TcPlugin
{ tcPluginInit = tcPluginIO $ putStrLn ">>> Plugin Init"
, tcPluginSolve = \_ _ _ _ -> do
tcPluginIO $ putStrLn ">>> Plugin Solve"
return $ TcPluginOk [] []
, tcPluginStop = \_ -> tcPluginIO $ putStrLn ">>> Plugin Stop"
}
}
}}}
=== Minimal example (with type error)
`Main.hs`:
{{{#!hs
{-# OPTIONS_GHC -fplugin MyPlugin #-}
module Main where
main :: (Monad m) => m ()
main = do
return 1
}}}
Compiling this will lead to the following output:
{{{
$ ~/ghc/inplace/bin/ghc-stage2 --make -package ghc-7.11.20150209 -dynamic
Main.hs
[2 of 2] Compiling Main ( Main.hs, Main.o )
>>> Plugin Init
>>> Plugin Solve
>>> Plugin Solve
>>> Plugin Solve
Main.hs:6:10:
Could not deduce (Num ()) arising from the literal ‘1’
from the context: Monad m
bound by the type signature for: main :: Monad m => m ()
at Main.hs:4:9-25
In the first argument of ‘return’, namely ‘1’
In a stmt of a 'do' block: return 1
In the expression: do { return 1 }
}}}
Which means `tcPluginStop` was _not_ called.
=== Minimal example (without type error)
`Main.hs`:
{{{#!hs
{-# OPTIONS_GHC -fplugin MyPlugin #-}
module Main where
main :: (Monad m) => m ()
main = do
return ()
}}}
Compiling this will lead to the following output:
{{{
$ ~/ghc/inplace/bin/ghc-stage2 --make -package ghc-7.11.20150209 -dynamic
Main.hs
[2 of 2] Compiling Main ( Main.hs, Main.o ) [MyPlugin changed]
>>> Plugin Init
>>> Plugin Solve
>>> Plugin Solve
>>> Plugin Stop
Linking Main ...
}}}
Which means `tcPluginStop` _was_ called.
=== Possible solution
As far as I can see, the solution to this should be to change the plugin
code at the bottom of `typechecker/TcRnDriver.hs` from
{{{#!hs
withTcPlugins :: HscEnv -> TcM a -> TcM a
withTcPlugins hsc_env m =
do plugins <- liftIO (loadTcPlugins hsc_env)
case plugins of
[] -> m -- Common fast case
_ -> do (solvers,stops) <- unzip `fmap` mapM startPlugin plugins
res <- updGblEnv (\e -> e { tcg_tc_plugins = solvers }) m
mapM_ runTcPluginM stops
return res
where
startPlugin (TcPlugin start solve stop) =
do s <- runTcPluginM start
return (solve s, stop s)
}}}
to
{{{#!hs
withTcPlugins :: HscEnv -> TcM a -> TcM a
withTcPlugins hsc_env m =
do plugins <- liftIO (loadTcPlugins hsc_env)
case plugins of
[] -> m -- Common fast case
_ -> do (solvers,stops) <- unzip `fmap` mapM startPlugin plugins
eitherRes <- tryM $ do updGblEnv (\e -> e { tcg_tc_plugins
= solvers }) m
mapM_ runTcPluginM stops
case eitherRes of
Left e -> failM
Right res -> return res
where
startPlugin (TcPlugin start solve stop) =
do s <- runTcPluginM start
return (solve s, stop s)
}}}
.
I have tried this. It compiles and my minimal example delivers the correct
result.
Are there any arguments against this change? If not, I would try to commit
a patch for this problem sometime this weekend.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10078>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list