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.