Skip to content

A variant of `runTcInteractive` that takes a list of orphan modules

Motivation

The concat plugin uses BuildDictionary.hs to find or construct a CoreExpr of the given predicate type. To do so it uses runTcInteractive. The problem is that the way it treats orphan instances is fairly awkward:

-- From BuildDictionary.hs
moduleIsOkay :: HscEnv -> ModuleName -> IO Bool
moduleIsOkay env mname = isFound <$> findExposedPackageModule env mname Nothing

runTcM :: HscEnv -> DynFlags -> ModGuts -> TcM a -> IO a
runTcM env0 dflags guts m = do
    -- Remove hidden modules from dep_orphans
    orphans <- filterM (moduleIsOkay env0) (moduleName <$> dep_orphs (mg_deps guts))
    (msgs, mr) <- runTcInteractive (env orphans) m
    let showMsgs (warns, errs) = showSDoc dflags $ vcat $
              text "Errors:"   : pprErrMsgBagWithLoc errs
           ++ text "Warnings:" : pprErrMsgBagWithLoc warns
    maybe (fail $ showMsgs msgs) return mr
 where
   imports0 = ic_imports (hsc_IC env0)
   env :: [ModuleName] -> HscEnv
   env extraModuleNames =
     env0 { hsc_IC = (hsc_IC env0)
             { ic_imports = map IIModule extraModuleNames ++ imports0
             , ic_rn_gbl_env = mg_rdr_env guts
             , ic_instances = (mg_insts guts, mg_fam_insts guts)
             } }

Given the ModGuts it is dealing with, it extracts the ModuleNames of its dep_orphs, and prepends it to ic_imports, only so that these ModuleNames will be loaded and turned back into Modules in runTcInteractive. This is wasted work.

What's worse, in order to do so it needs to filter out the hidden orphan modules (i.e., the filterM, because loading a hidden module results in an error). This means BuildDictionary cannot find any orphan instances in hidden packages.

Proposal

What would be pretty useful is a variant of runTcInteractive that takes orphan modules as input, and concatenate it with the orphan modules it computes:

runTcInteractive :: HscEnv -> TcRn a -> IO (Messages TcRnMessage, Maybe a)
runTcInteractive = runTcInteractive' []

runTcInteractive' :: [Module] -> HscEnv -> TcRn a -> IO (Messages TcRnMessage, Maybe a)
runTcInteractive' orphs0 hsc_env thing_inside =
    ...
    ; !orphs <- fmap (force . concat . (orphs0 :)) . forM (ic_imports icxt) $ \i ->
    ...

This way BuildDictionary.hs will be both simpler and able to find orphan instances from hidden packages.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information