Opened 5 weeks ago

Last modified 5 weeks ago

#15745 new feature request

Panicking typechecker plugins

Reported by: philderbeast Owned by:
Priority: normal Milestone:
Component: Compiler (Type checker) Version: 8.2.2
Keywords: TypeCheckerPlugins Cc: adamgundry
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Compile-time crash or panic Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

If I use a typechecker plugin that fails then ghc panics and I'm asked to report a bug with GHC;

ghc: panic! (the 'impossible' happened)
      (GHC version 8.2.2 for x86_64-apple-darwin):
    	Prelude.undefined
    CallStack (from HasCallStack):
      error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
      undefined, called at plugin/Undefined/Solve/Plugin.hs:14:39 in
      undefined-solve-plugin-1.0.0.0-56evBabJYBHHTUlrE3HO5m:Undefined.Solve.Plugin

    Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

Could we please say that it is the typechecker plugin that is panicking and ask for a bug report for the faulty typechecker, giving the issues URL for the plugin if we know it?

The following undefined plugins fail for init, solve and stop functions.

module Undefined.Init.Plugin (plugin) where

import Plugins (Plugin(..), tcPlugin, defaultPlugin)
import TcRnTypes (TcPluginM, TcPluginResult(..), Ct, TcPlugin(..))
import GHC.TcPluginM.Extra (tracePlugin)

plugin :: Plugin
plugin = defaultPlugin { tcPlugin = const $ Just undefinedPlugin }

undefinedPlugin :: TcPlugin
undefinedPlugin = tracePlugin "undefined-init-plugin" $
    TcPlugin
        { tcPluginInit  = undefined
        , tcPluginSolve = \_ _ _ _ -> return $ TcPluginOk [] []
        , tcPluginStop  = const $ return ()
        }
module Undefined.Solve.Plugin (plugin) where

import Plugins (Plugin(..), tcPlugin, defaultPlugin)
import TcRnTypes (TcPluginM, TcPluginResult, Ct, TcPlugin(..))
import GHC.TcPluginM.Extra (tracePlugin)

plugin :: Plugin
plugin = defaultPlugin { tcPlugin = const $ Just undefinedPlugin }

undefinedPlugin :: TcPlugin
undefinedPlugin = tracePlugin "undefined-solve-plugin" $
    TcPlugin
        { tcPluginInit  = return ()
        , tcPluginSolve = \_ _ _ _ -> undefined
        , tcPluginStop  = const $ return ()
        }
module Undefined.Stop.Plugin (plugin) where

import Plugins (Plugin(..), tcPlugin, defaultPlugin)
import TcRnTypes (TcPluginM, TcPluginResult(..), Ct, TcPlugin(..))
import GHC.TcPluginM.Extra (tracePlugin)

plugin :: Plugin
plugin = defaultPlugin { tcPlugin = const $ Just undefinedPlugin }

undefinedPlugin :: TcPlugin
undefinedPlugin = tracePlugin "undefined-stop-plugin" $
    TcPlugin
        { tcPluginInit  = return ()
        , tcPluginSolve = \_ _ _ _ -> return $ TcPluginOk [] []
        , tcPluginStop  = const $ undefined
        }

Change History (2)

comment:1 Changed 5 weeks ago by adamgundry

Cc: adamgundry added
Keywords: TypeCheckerPlugins added

Makes sense. We can't necessarily identify such plugin-caused errors in all cases, but it should at least be possible to catch exceptions thrown in TcPluginM.

comment:2 Changed 5 weeks ago by goldfire

Just to expand on Adam's comment (which I agree with): a plugin passes data back to GHC. If that data contains an undefined, then it will cause a panic, and there's no (reasonably easy) way to properly blame the plugin instead of GHC. I don't see any way to avoid this, unless we deepseq all data that the plugin returns (which isn't, on its surface, a terrible idea).

However, the bald undefineds above should be easy enough to catch.

What might be an unreasonable way to do this? To carefully track plugin-provided information using some sort of tainting process. This is, of course, doable, but of quite small benefit compared to the cost.

Note: See TracTickets for help on using tickets.