Commit fd5d622a authored by Sebastian Graf's avatar Sebastian Graf Committed by Marge Bot

Hackily decouple the parser from the desugarer

In a hopefully temporary hack, I re-used the idea from !1957 of using a
nullary type family to break the dependency from GHC.Driver.Hooks on the
definition of DsM ("Abstract Data").
This in turn broke the last dependency from the parser to the desugarer.
More details in `Note [The Decoupling Abstract Data Hack]`.

In the future, we hope to undo this hack again in favour of breaking the
dependency from the parser to DynFlags altogether.
parent a77e48d2
Pipeline #24652 failed with stages
in 227 minutes and 12 seconds
......@@ -3,7 +3,7 @@
-- NB: this module is SOURCE-imported by DynFlags, and should primarily
-- refer to *types*, rather than *code*
{-# LANGUAGE CPP, RankNTypes #-}
{-# LANGUAGE CPP, RankNTypes, TypeFamilies #-}
module GHC.Driver.Hooks
( Hooks
......@@ -11,6 +11,7 @@ module GHC.Driver.Hooks
, lookupHook
, getHooked
-- the hooks:
, DsForeignsHook
, dsForeignsHook
, tcForeignImportsHook
, tcForeignExportsHook
......@@ -36,9 +37,7 @@ import GHC.Driver.Types
import GHC.Hs.Decls
import GHC.Hs.Binds
import GHC.Hs.Expr
import GHC.Data.OrdList
import GHC.Tc.Types
import GHC.HsToCore.Types
import GHC.Data.Bag
import GHC.Types.Name.Reader
import GHC.Types.Name
......@@ -59,6 +58,7 @@ import GHC.Hs.Extension
import GHC.StgToCmm.Types (ModuleLFInfos)
import Data.Maybe
import qualified Data.Kind
{-
************************************************************************
......@@ -90,9 +90,32 @@ emptyHooks = Hooks
, cmmToRawCmmHook = Nothing
}
{- Note [The Decoupling Abstract Data Hack]
  • That's a nice trick! Is it a hack or a kind of .hs-boot on steroids? :)

    I think we could use it for other hooks and plugins. E.g.:

    -- in GHC..Driver.Plugins
    type family TcPlugin :: Type
    type family CorePlugin :: Type
    type family HoleFitPlugin :: Type
    ...
    
    data Plugin = Plugin
       { tcPlugin :: [CommandLineOption] -> Maybe TcPlugin
       , corePlugin :: [CommandLineOption] -> Maybe CorePlugin
       , ...
       }
    
    defaultPlugin :: Plugin
    defaultPlugin = Plugin
      { tcPlugin   = const Nothing
      , corePlugin = const Nothing
      ...
      }

    No dependence on the type-checker or Core whatsoever.

  • Yeah, it behaves quite like an .hs-boot file, only that you won't have to include the corresponding .hs file. It's probably more like a Backpack signature, but with instantiation to a structure (or whatever that's called in Backpack lingo) only when type-checking gets stuck otherwise.

    But as Simon also expressed in !1957, he really doesn't like it. At least as far as the situation for parser dependencies is concerned, we'll be better off with making it no longer depend on DynFlags at all.

    I'm not completely sure if applying this hack to type-checker plugins is enough to break all dependency chains in the meantime, because I haven't tried. Feel free to test that! You can tell by a decrease in number of dependencies in the CountParserDeps test case.

  • I can be persuaded!

    But I have separately said how I think DynFlags can better be decoupled from other modules. In other words let's not use a tactical nuclear weapon if a hammer will do.

  • I've experimented with it in !4047

Please register or sign in to reply
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The "Abstract Data" idea is due to Richard Eisenberg in
https://gitlab.haskell.org/ghc/ghc/-/merge_requests/1957, where the pattern is
described in more detail.
Here we use it as a temporary measure to break the dependency from the Parser on
the Desugarer until the parser is free of DynFlags. We introduced a nullary type
family @DsForeignsook@, whose single definition is in GHC.HsToCore.Types, where
we instantiate it to
[LForeignDecl GhcTc] -> DsM (ForeignStubs, OrdList (Id, CoreExpr))
In doing so, the Hooks module (which is an hs-boot dependency of DynFlags) can
be decoupled from its use of the DsM definition in GHC.HsToCore.Types. Since
both DsM and the definition of @ForeignsHook@ live in the same module, there is
virtually no difference for plugin authors that want to write a foreign hook.
-}
-- See Note [The Decoupling Abstract Data Hack]
type family DsForeignsHook :: Data.Kind.Type
data Hooks = Hooks
{ dsForeignsHook :: Maybe ([LForeignDecl GhcTc]
-> DsM (ForeignStubs, OrdList (Id, CoreExpr)))
{ dsForeignsHook :: Maybe DsForeignsHook
-- ^ Actual type:
-- @Maybe ([LForeignDecl GhcTc] -> DsM (ForeignStubs, OrdList (Id, CoreExpr)))@
, tcForeignImportsHook :: Maybe ([LForeignDecl GhcRn]
-> TcM ([Id], [LForeignDecl GhcTc], Bag GlobalRdrElt))
, tcForeignExportsHook :: Maybe ([LForeignDecl GhcRn]
......
{-# LANGUAGE TypeFamilies, UndecidableInstances #-}
-- | Various types used during desugaring.
module GHC.HsToCore.Types (
DsM, DsLclEnv(..), DsGblEnv(..),
......@@ -10,13 +12,17 @@ import GHC.Types.CostCentre.State
import GHC.Types.Name.Env
import GHC.Types.SrcLoc
import GHC.Types.Var
import GHC.Hs (HsExpr, GhcTc)
import GHC.Hs (LForeignDecl, HsExpr, GhcTc)
import GHC.Tc.Types (TcRnIf, IfGblEnv, IfLclEnv, CompleteMatches)
import {-# SOURCE #-} GHC.HsToCore.PmCheck.Types (Nablas)
import GHC.Core (CoreExpr)
import GHC.Core.FamInstEnv
import GHC.Utils.Error
import GHC.Utils.Outputable as Outputable
import GHC.Unit.Module
import GHC.Driver.Hooks (DsForeignsHook)
import GHC.Data.OrdList (OrdList)
import GHC.Driver.Types (ForeignStubs)
{-
************************************************************************
......@@ -75,3 +81,5 @@ data DsMetaVal
-- | Desugaring monad. See also 'TcM'.
type DsM = TcRnIf DsGblEnv DsLclEnv
-- See Note [The Decoupling Abstract Data Hack]
type instance DsForeignsHook = [LForeignDecl GhcTc] -> DsM (ForeignStubs, OrdList (Id, CoreExpr))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment