Skip to content

Commit 4413a0f

Browse files
committed
WIP ghcide: Core.Compile: getDocsBatch batching
1 parent ab8c52b commit 4413a0f

File tree

1 file changed

+74
-19
lines changed

1 file changed

+74
-19
lines changed

ghcide/src/Development/IDE/Core/Compile.hs

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -991,33 +991,88 @@ mkDetailsFromIface session iface linkable = do
991991
initIfaceLoad hsc' (typecheckIface iface)
992992
return (HomeModInfo iface details linkable)
993993

994+
994995
-- | Non-interactive, batch version of 'InteractiveEval.getDocs'.
995996
-- The interactive paths create problems in ghc-lib builds
996997
--- and leads to fun errors like "Cannot continue after interface file error".
997998
getDocsBatch
998999
:: HscEnv
9991000
-> Module -- ^ a moudle where the names are in scope
10001001
-> [Name]
1001-
-> IO [Either String (Maybe HsDocString, Map.Map Int HsDocString)]
1002+
-- 2021-11-19: NOTE: Don't forget these 'Map' currently lazy.
1003+
-- 2021-11-18: NOTE: Map Int would become IntMap if next GHCs.
1004+
-> IO (Either ErrorMessages (Map.Map Name (Either GetDocsFailure (Maybe HsDocString, Maybe (Map.Map Int HsDocString)))))
1005+
-- ^ Return a 'Map' of 'Name's to 'Either' (no docs messages) (general doc body & arg docs)
10021006
getDocsBatch hsc_env _mod _names = do
1003-
((_warns,errs), res) <- initTc hsc_env HsSrcFile False _mod fakeSpan $ forM _names $ \name ->
1004-
case nameModule_maybe name of
1005-
Nothing -> return (Left $ NameHasNoModule name)
1006-
Just mod -> do
1007-
ModIface { mi_doc_hdr = mb_doc_hdr
1008-
, mi_decl_docs = DeclDocMap dmap
1009-
, mi_arg_docs = ArgDocMap amap
1010-
} <- loadModuleInterface "getModuleInterface" mod
1011-
if isNothing mb_doc_hdr && Map.null dmap && Map.null amap
1012-
then pure (Left (NoDocsInIface mod $ compiled name))
1013-
else pure (Right ( Map.lookup name dmap
1014-
, Map.findWithDefault Map.empty name amap))
1015-
case res of
1016-
Just x -> return $ map (first $ T.unpack . showGhc) x
1017-
Nothing -> throwErrors errs
1018-
where
1019-
throwErrors = liftIO . throwIO . mkSrcErr
1020-
compiled n =
1007+
((_warns,errs), res) <- initTc hsc_env HsSrcFile False _mod fakeSpan $ Map.fromList <$> traverse undefined undefined
1008+
pure $ maybeToEither errs res
1009+
where
1010+
mapOfRequestedDocs :: IOEnv (Env TcGblEnv TcLclEnv) (Map Name (Maybe HsDocString, Maybe (Map Int HsDocString)))
1011+
mapOfRequestedDocs = Map.fromList . foldMap getAskedIfaceDocs <$> loadIfaces
1012+
1013+
getAskedIfaceDocs :: ((Map Name HsDocString, Map Name (Map Int HsDocString)), [Name]) -> [(Name, (Maybe HsDocString, Maybe (Map Int HsDocString)))]
1014+
getAskedIfaceDocs a = lookupDocs <$> snd a
1015+
where
1016+
lookupDocs :: Name -> (Name, (Maybe HsDocString, Maybe (Map Int HsDocString)))
1017+
lookupDocs n = (n, bimap (Map.lookup n) (Map.lookup n) $ fst a)
1018+
1019+
loadIfaces :: IOEnv (Env TcGblEnv TcLclEnv) [((Map Name HsDocString, Map Name (Map Int HsDocString)), [Name])]
1020+
loadIfaces = mkOneEnv (fmap (first getIfaceGenNArgDocMaps) loadModules)
1021+
where
1022+
mkOneEnv :: Applicative env => [(env ms, ns)] -> env [(ms, ns)]
1023+
mkOneEnv a = traverse (fmap swap . sequenceA . swap) a
1024+
1025+
getIfaceGenNArgDocMaps :: TcRn ModIface -> IOEnv (Env TcGblEnv TcLclEnv) (Map Name HsDocString, Map Name (Map Int HsDocString))
1026+
getIfaceGenNArgDocMaps mi = do
1027+
ModIface
1028+
{ mi_doc_hdr = mb_doc_hdr
1029+
, mi_decl_docs = DeclDocMap dmap
1030+
, mi_arg_docs = ArgDocMap amap
1031+
}
1032+
<- mi
1033+
pure $
1034+
if isNothing mb_doc_hdr && Map.null dmap && Map.null amap
1035+
then error "Instead of 'error' here handle 'NoDocsInIface mod $ isCompiled name' case"
1036+
else (dmap, amap)
1037+
1038+
loadModules :: [(TcRn ModIface, [Name])]
1039+
loadModules = fmap loadAvailableModules namesGroupedByModule
1040+
where
1041+
loadAvailableModules :: (Module, [Name]) -> (TcRn ModIface, [Name])
1042+
loadAvailableModules = first loadModuleInterfaceOnce
1043+
1044+
1045+
loadModuleInterfaceOnce :: Module -> TcRn ModIface
1046+
loadModuleInterfaceOnce =
1047+
loadModuleInterface "getModuleInterface"
1048+
1049+
namesGroupedByModule :: [(Module, [Name])]
1050+
namesGroupedByModule =
1051+
groupSort $ fmap (first (fromMaybe (error "Instead of 'error' handle here 'NameHasNoModule' case") . nameModule_maybe) . dupe) _names
1052+
1053+
-- modulesPartitionedOnAvalability :: [(Either (Name -> GetDocsFailure) Module, [Name])]
1054+
-- modulesPartitionedOnAvalability = fmap partitionOnModuleAvalibility namesGroupedByModule
1055+
1056+
-- partitionOnModuleAvalibility :: (Maybe Module, [Name]) -> (Either (Name -> GetDocsFailure) Module, [Name])
1057+
-- partitionOnModuleAvalibility =
1058+
-- first (maybeToEither NameHasNoModule)
1059+
1060+
1061+
-- 2021-11-18: NOTE: This code initially was taken from: https://hackage.haskell.org/package/ghc-9.2.1/docs/src/GHC.Runtime.Eval.html#getDocs
1062+
findNameInfo :: Maybe Module -> Name -> IOEnv (Env TcGblEnv TcLclEnv) (Name, Either GetDocsFailure (Maybe HsDocString, Maybe (Map.Map Int HsDocString)))
1063+
findNameInfo Nothing name = return (name, Left $ NameHasNoModule name)
1064+
findNameInfo (Just mod) name = do
1065+
ModIface
1066+
{ mi_doc_hdr = mb_doc_hdr
1067+
, mi_decl_docs = DeclDocMap dmap
1068+
, mi_arg_docs = ArgDocMap amap
1069+
}
1070+
<- loadModuleInterface "getModuleInterface" mod
1071+
pure . (name,) $
1072+
if isNothing mb_doc_hdr && Map.null dmap && Map.null amap
1073+
then Left $ NoDocsInIface mod $ isCompiled name
1074+
else Right (Map.lookup name dmap, Map.lookup name amap)
1075+
isCompiled n =
10211076
-- TODO: Find a more direct indicator.
10221077
case nameSrcLoc n of
10231078
RealSrcLoc {} -> False

0 commit comments

Comments
 (0)