From 41c2b7734f60b5e69168b83379e0e6259df077ca Mon Sep 17 00:00:00 2001 From: Jakob Bruenker Date: Sun, 30 Oct 2022 21:09:55 +0100 Subject: [PATCH 1/8] Restore ability to run source plugins Since ghc 9.0, plugins are stored in the HscEnv, not in the DynFlags. This caused HLS not to run source plugins anymore. This commit fixes that. Fixes #3299. --- ghcide/src/Development/IDE/Core/Compile.hs | 15 +++----- .../src/Development/IDE/Core/Preprocessor.hs | 38 +++++++++---------- ghcide/src/Development/IDE/Core/Rules.hs | 5 ++- .../src/Development/IDE/GHC/Compat/Plugins.hs | 7 ++++ 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/ghcide/src/Development/IDE/Core/Compile.hs b/ghcide/src/Development/IDE/Core/Compile.hs index 978e0ceccb..419d5b95e5 100644 --- a/ghcide/src/Development/IDE/Core/Compile.hs +++ b/ghcide/src/Development/IDE/Core/Compile.hs @@ -172,11 +172,11 @@ typecheckModule :: IdeDefer typecheckModule (IdeDefer defer) hsc tc_helpers pm = do let modSummary = pm_mod_summary pm dflags = ms_hspp_opts modSummary - mmodSummary' <- catchSrcErrors (hsc_dflags hsc) "typecheck (initialize plugins)" + initialized <- catchSrcErrors (hsc_dflags hsc) "typecheck (initialize plugins)" (initPlugins hsc modSummary) - case mmodSummary' of + case initialized of Left errs -> return (errs, Nothing) - Right modSummary' -> do + Right (modSummary', hsc) -> do (warnings, etcm) <- withWarnings "typecheck" $ \tweak -> let session = tweak (hscSetFlags dflags hsc) @@ -569,11 +569,6 @@ mkHiFileResultCompile se session' tcm simplified_guts = catchErrs $ do . (("Error during " ++ T.unpack source) ++) . show @SomeException ] -initPlugins :: HscEnv -> ModSummary -> IO ModSummary -initPlugins session modSummary = do - session1 <- liftIO $ initializePlugins (hscSetFlags (ms_hspp_opts modSummary) session) - return modSummary{ms_hspp_opts = hsc_dflags session1} - -- | Whether we should run the -O0 simplifier when generating core. -- -- This is required for template Haskell to work but we disable this in DAML. @@ -1101,7 +1096,9 @@ getModSummaryFromImports -> Maybe Util.StringBuffer -> ExceptT [FileDiagnostic] IO ModSummaryResult getModSummaryFromImports env fp modTime contents = do - (contents, opts, dflags) <- preprocessor env fp contents + (contents, opts, env) <- preprocessor env fp contents + + let dflags = hsc_dflags env -- The warns will hopefully be reported when we actually parse the module (_warns, L main_loc hsmod) <- parseHeader dflags fp contents diff --git a/ghcide/src/Development/IDE/Core/Preprocessor.hs b/ghcide/src/Development/IDE/Core/Preprocessor.hs index d41a7f9795..ef08264d7a 100644 --- a/ghcide/src/Development/IDE/Core/Preprocessor.hs +++ b/ghcide/src/Development/IDE/Core/Preprocessor.hs @@ -36,12 +36,12 @@ import GHC.Utils.Outputable (renderWithContext) -- | Given a file and some contents, apply any necessary preprocessors, -- e.g. unlit/cpp. Return the resulting buffer and the DynFlags it implies. -preprocessor :: HscEnv -> FilePath -> Maybe Util.StringBuffer -> ExceptT [FileDiagnostic] IO (Util.StringBuffer, [String], DynFlags) -preprocessor env0 filename mbContents = do +preprocessor :: HscEnv -> FilePath -> Maybe Util.StringBuffer -> ExceptT [FileDiagnostic] IO (Util.StringBuffer, [String], HscEnv) +preprocessor env filename mbContents = do -- Perform unlit (isOnDisk, contents) <- if isLiterate filename then do - newcontent <- liftIO $ runLhs env0 filename mbContents + newcontent <- liftIO $ runLhs env filename mbContents return (False, newcontent) else do contents <- liftIO $ maybe (Util.hGetStringBuffer filename) return mbContents @@ -49,17 +49,17 @@ preprocessor env0 filename mbContents = do return (isOnDisk, contents) -- Perform cpp - (opts, dflags) <- ExceptT $ parsePragmasIntoDynFlags env0 filename contents - let env1 = hscSetFlags dflags env0 - let logger = hsc_logger env1 - (isOnDisk, contents, opts, dflags) <- + (opts, env) <- ExceptT $ parsePragmasIntoHscEnv env filename contents + let dflags = hsc_dflags env + let logger = hsc_logger env + (isOnDisk, contents, opts, env) <- if not $ xopt LangExt.Cpp dflags then - return (isOnDisk, contents, opts, dflags) + return (isOnDisk, contents, opts, env) else do cppLogs <- liftIO $ newIORef [] let newLogger = pushLogHook (const (logActionCompat $ logAction cppLogs)) logger contents <- ExceptT - $ (Right <$> (runCpp (putLogHook newLogger env1) filename + $ (Right <$> (runCpp (putLogHook newLogger env) filename $ if isOnDisk then Nothing else Just contents)) `catch` ( \(e :: Util.GhcException) -> do @@ -68,16 +68,16 @@ preprocessor env0 filename mbContents = do [] -> throw e diags -> return $ Left diags ) - (opts, dflags) <- ExceptT $ parsePragmasIntoDynFlags env1 filename contents - return (False, contents, opts, dflags) + (opts, env) <- ExceptT $ parsePragmasIntoHscEnv env filename contents + return (False, contents, opts, env) -- Perform preprocessor if not $ gopt Opt_Pp dflags then - return (contents, opts, dflags) + return (contents, opts, env) else do - contents <- liftIO $ runPreprocessor env1 filename $ if isOnDisk then Nothing else Just contents - (opts, dflags) <- ExceptT $ parsePragmasIntoDynFlags env1 filename contents - return (contents, opts, dflags) + contents <- liftIO $ runPreprocessor env filename $ if isOnDisk then Nothing else Just contents + (opts, env) <- ExceptT $ parsePragmasIntoHscEnv env filename contents + return (contents, opts, env) where logAction :: IORef [CPPLog] -> LogActionCompat logAction cppLogs dflags _reason severity srcSpan _style msg = do @@ -137,12 +137,12 @@ isLiterate x = takeExtension x `elem` [".lhs",".lhs-boot"] -- | This reads the pragma information directly from the provided buffer. -parsePragmasIntoDynFlags +parsePragmasIntoHscEnv :: HscEnv -> FilePath -> Util.StringBuffer - -> IO (Either [FileDiagnostic] ([String], DynFlags)) -parsePragmasIntoDynFlags env fp contents = catchSrcErrors dflags0 "pragmas" $ do + -> IO (Either [FileDiagnostic] ([String], HscEnv)) +parsePragmasIntoHscEnv env fp contents = catchSrcErrors dflags0 "pragmas" $ do #if MIN_VERSION_ghc(9,3,0) let (_warns,opts) = getOptions (initParserOpts dflags0) contents fp #else @@ -154,7 +154,7 @@ parsePragmasIntoDynFlags env fp contents = catchSrcErrors dflags0 "pragmas" $ do (dflags, _, _) <- parseDynamicFilePragma dflags0 opts hsc_env' <- initializePlugins (hscSetFlags dflags env) - return (map unLoc opts, disableWarningsAsErrors (hsc_dflags hsc_env')) + return (map unLoc opts, hscSetFlags (disableWarningsAsErrors $ hsc_dflags hsc_env') hsc_env') where dflags0 = hsc_dflags env -- | Run (unlit) literate haskell preprocessor on a file, or buffer if set diff --git a/ghcide/src/Development/IDE/Core/Rules.hs b/ghcide/src/Development/IDE/Core/Rules.hs index 83a8e9bad8..87831f8723 100644 --- a/ghcide/src/Development/IDE/Core/Rules.hs +++ b/ghcide/src/Development/IDE/Core/Rules.hs @@ -255,7 +255,7 @@ getParsedModuleRule recorder = define (cmapWithPrio LogShake recorder) $ \GetParsedModule file -> do ModSummaryResult{msrModSummary = ms'} <- use_ GetModSummary file sess <- use_ GhcSession file - let hsc = hscEnv sess + (ms', hsc) <- liftIO $ initPlugins (hscEnv sess) ms' opt <- getIdeOptions modify_dflags <- getModifyDynFlags dynFlagsModifyParser let ms = ms' { ms_hspp_opts = modify_dflags $ ms_hspp_opts ms' } @@ -329,6 +329,7 @@ getParsedModuleWithCommentsRule recorder = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetParsedModuleWithComments file -> do ModSummaryResult{msrModSummary = ms} <- use_ GetModSummary file sess <- use_ GhcSession file + (ms, hsc) <- liftIO $ initPlugins (hscEnv sess) ms opt <- getIdeOptions let ms' = withoutOption Opt_Haddock $ withOption Opt_KeepRawTokenStream ms @@ -336,7 +337,7 @@ getParsedModuleWithCommentsRule recorder = let ms = ms' { ms_hspp_opts = modify_dflags $ ms_hspp_opts ms' } reset_ms pm = pm { pm_mod_summary = ms' } - liftIO $ fmap (fmap reset_ms) $ snd <$> getParsedModuleDefinition (hscEnv sess) opt file ms + liftIO $ fmap (fmap reset_ms) $ snd <$> getParsedModuleDefinition hsc opt file ms getModifyDynFlags :: (DynFlagsModifications -> a) -> Action a getModifyDynFlags f = do diff --git a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs index 9af3d38162..dc91f63cb1 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs @@ -7,6 +7,7 @@ module Development.IDE.GHC.Compat.Plugins ( PluginWithArgs(..), applyPluginsParsedResultAction, initializePlugins, + initPlugins, -- * Static plugins StaticPlugin(..), @@ -67,6 +68,12 @@ initializePlugins env = do pure $ hscSetFlags newDf env #endif +-- Plugins aren't stored in ModSummary anymore since GHC 9.0, but this +-- function still returns it for compatibility with 8.10 +initPlugins :: HscEnv -> ModSummary -> IO (ModSummary, HscEnv) +initPlugins session modSummary = do + session1 <- initializePlugins (hscSetFlags (ms_hspp_opts modSummary) session) + return (modSummary{ms_hspp_opts = hsc_dflags session1}, session1) hsc_static_plugins :: HscEnv -> [StaticPlugin] #if MIN_VERSION_ghc(9,3,0) From 0e35e5297277ad9ec3bff63ad8d7f0076e57d916 Mon Sep 17 00:00:00 2001 From: Jakob Bruenker Date: Wed, 2 Nov 2022 08:25:22 +0100 Subject: [PATCH 2/8] Allow source plugins to change parser errors In 9.4, the ability for parser source plugins to access and manipulate non-fatal parse errors was added: https://gitlab.haskell.org/ghc/ghc/-/wikis/migration/9.4#parser-plugins-have-a-different-type HLS always threw an error in this situation without running the plugins though. This commit fixes that. --- ghcide/src/Development/IDE/Core/Compile.hs | 24 +++++++++++-------- ghcide/src/Development/IDE/GHC/Compat.hs | 19 +++++++++++++-- .../src/Development/IDE/GHC/Compat/Plugins.hs | 13 ++++++---- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/ghcide/src/Development/IDE/Core/Compile.hs b/ghcide/src/Development/IDE/Core/Compile.hs index 419d5b95e5..f1b0ca3d1c 100644 --- a/ghcide/src/Development/IDE/Core/Compile.hs +++ b/ghcide/src/Development/IDE/Core/Compile.hs @@ -132,6 +132,9 @@ import qualified GHC as G import GHC.Hs (LEpaComment) import qualified GHC.Types.Error as Error #endif +#if MIN_VERSION_ghc(9,3,0) +import GHC.Driver.Plugins (PsMessages (..)) +#endif -- | Given a string buffer, return the string (after preprocessing) and the 'ParsedModule'. parseModule @@ -1225,7 +1228,7 @@ parseHeader dflags filename contents = do PFailedWithErrorMessages msgs -> throwE $ diagFromErrMsgs "parser" dflags $ msgs dflags POk pst rdr_module -> do - let (warns, errs) = getMessages' pst dflags + let (warns, errs) = renderMessages $ getMessages' pst dflags -- Just because we got a `POk`, it doesn't mean there -- weren't errors! To clarify, the GHC parser @@ -1260,9 +1263,18 @@ parseFileContents env customPreprocessor filename ms = do POk pst rdr_module -> let hpm_annotations = mkApiAnns pst - (warns, errs) = getMessages' pst dflags + psMessages = getMessages' pst dflags in do + let IdePreprocessedSource preproc_warns errs parsed = customPreprocessor rdr_module + + unless (null errs) $ + throwE $ diagFromStrings "parser" DsError errs + + let preproc_warnings = diagFromStrings "parser" DsWarning preproc_warns + (parsed', msgs) <- liftIO $ applyPluginsParsedResultAction env dflags ms hpm_annotations parsed psMessages + let (warns, errs) = renderMessages msgs + -- Just because we got a `POk`, it doesn't mean there -- weren't errors! To clarify, the GHC parser -- distinguishes between fatal and non-fatal @@ -1275,14 +1287,6 @@ parseFileContents env customPreprocessor filename ms = do unless (null errs) $ throwE $ diagFromErrMsgs "parser" dflags errs - -- Ok, we got here. It's safe to continue. - let IdePreprocessedSource preproc_warns errs parsed = customPreprocessor rdr_module - - unless (null errs) $ - throwE $ diagFromStrings "parser" DsError errs - - let preproc_warnings = diagFromStrings "parser" DsWarning preproc_warns - parsed' <- liftIO $ applyPluginsParsedResultAction env dflags ms hpm_annotations parsed -- To get the list of extra source files, we take the list -- that the parser gave us, diff --git a/ghcide/src/Development/IDE/GHC/Compat.hs b/ghcide/src/Development/IDE/GHC/Compat.hs index 216039cd1c..1ccd8ad58e 100644 --- a/ghcide/src/Development/IDE/GHC/Compat.hs +++ b/ghcide/src/Development/IDE/GHC/Compat.hs @@ -26,6 +26,7 @@ module Development.IDE.GHC.Compat( reLoc, reLocA, getMessages', + renderMessages, pattern PFailedWithErrorMessages, isObjectLinkable, @@ -261,6 +262,7 @@ import GHC.Types.IPE #if MIN_VERSION_ghc(9,3,0) import GHC.Types.Error import GHC.Driver.Config.Stg.Pipeline +import GHC.Driver.Plugins (PsMessages (..)) #endif type ModIfaceAnnotation = Annotation @@ -378,10 +380,14 @@ type ErrMsg = MsgEnvelope DecoratedSDoc type WarnMsg = MsgEnvelope DecoratedSDoc #endif -getMessages' :: PState -> DynFlags -> (Bag WarnMsg, Bag ErrMsg) +#if !MIN_VERSION_ghc(9,3,0) +type PsMessages = (Bag WarnMsg, Bag ErrMsg) +#endif + +getMessages' :: PState -> DynFlags -> PsMessages getMessages' pst dflags = #if MIN_VERSION_ghc(9,3,0) - bimap (fmap (fmap renderDiagnosticMessageWithHints) . getMessages) (fmap (fmap renderDiagnosticMessageWithHints) . getMessages) $ getPsMessages pst + uncurry PsMessages $ getPsMessages pst #else #if MIN_VERSION_ghc(9,2,0) bimap (fmap pprWarning) (fmap pprError) $ @@ -392,6 +398,15 @@ getMessages' pst dflags = #endif #endif +renderMessages :: PsMessages -> (Bag WarnMsg, Bag ErrMsg) +renderMessages msgs = +#if MIN_VERSION_ghc(9,3,0) + let renderMsgs extractor = (fmap . fmap) renderDiagnosticMessageWithHints . getMessages $ extractor msgs + in (renderMsgs psWarnings, renderMsgs psErrors) +#else + msgs +#endif + #if MIN_VERSION_ghc(9,2,0) pattern PFailedWithErrorMessages :: forall a b. (b -> Bag (MsgEnvelope DecoratedSDoc)) -> ParseResult a pattern PFailedWithErrorMessages msgs diff --git a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs index dc91f63cb1..7bc8d3e237 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs @@ -35,15 +35,18 @@ import Plugins import Development.IDE.GHC.Compat.Core import Development.IDE.GHC.Compat.Env (hscSetFlags, hsc_dflags) import Development.IDE.GHC.Compat.Parser as Parser +import Debug.Trace +import GHC.Driver.Env (hsc_plugins) +import GHC.Driver.Plugins -applyPluginsParsedResultAction :: HscEnv -> DynFlags -> ModSummary -> Parser.ApiAnns -> ParsedSource -> IO ParsedSource -applyPluginsParsedResultAction env dflags ms hpm_annotations parsed = do +applyPluginsParsedResultAction :: HscEnv -> DynFlags -> ModSummary -> Parser.ApiAnns -> ParsedSource -> PsMessages -> IO (ParsedSource, PsMessages) +applyPluginsParsedResultAction env dflags ms hpm_annotations parsed msgs = do -- Apply parsedResultAction of plugins let applyPluginAction p opts = parsedResultAction p opts ms #if MIN_VERSION_ghc(9,3,0) - fmap (hpm_module . parsedResultModule) $ runHsc env $ withPlugins + fmap (\result -> (hpm_module (parsedResultModule result), (parsedResultMessages result))) $ runHsc env $ withPlugins #else - fmap hpm_module $ runHsc env $ withPlugins + fmap ((, msgs), hpm_module) $ runHsc env $ withPlugins #endif #if MIN_VERSION_ghc(9,3,0) (Env.hsc_plugins env) @@ -54,7 +57,7 @@ applyPluginsParsedResultAction env dflags ms hpm_annotations parsed = do #endif applyPluginAction #if MIN_VERSION_ghc(9,3,0) - (ParsedResult (HsParsedModule parsed [] hpm_annotations) (PsMessages mempty mempty)) + (ParsedResult (HsParsedModule parsed [] hpm_annotations) msgs) #else (HsParsedModule parsed [] hpm_annotations) #endif From bf6d1882b9029756c3b37546d99c5c9e5ba1f226 Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 12:51:21 +0100 Subject: [PATCH 3/8] Move backwards compatibility code --- ghcide/src/Development/IDE/Core/Compile.hs | 9 +-- ghcide/src/Development/IDE/GHC/Compat.hs | 27 +-------- ghcide/src/Development/IDE/GHC/Compat/Core.hs | 2 +- .../Development/IDE/GHC/Compat/Outputable.hs | 9 +++ .../src/Development/IDE/GHC/Compat/Plugins.hs | 59 ++++++++++++++----- 5 files changed, 57 insertions(+), 49 deletions(-) diff --git a/ghcide/src/Development/IDE/Core/Compile.hs b/ghcide/src/Development/IDE/Core/Compile.hs index 4a5b7c41bb..2f784b360c 100644 --- a/ghcide/src/Development/IDE/Core/Compile.hs +++ b/ghcide/src/Development/IDE/Core/Compile.hs @@ -132,9 +132,6 @@ import qualified GHC as G import GHC.Hs (LEpaComment) import qualified GHC.Types.Error as Error #endif -#if MIN_VERSION_ghc(9,3,0) -import GHC.Driver.Plugins (PsMessages (..)) -#endif -- | Given a string buffer, return the string (after preprocessing) and the 'ParsedModule'. parseModule @@ -475,7 +472,7 @@ mkHiFileResultCompile se session' tcm simplified_guts = catchErrs $ do Nothing #endif -#else +#else let !partial_iface = force (mkPartialIface session details simplified_guts) final_iface <- mkFullIface session partial_iface #endif @@ -1222,7 +1219,7 @@ parseHeader dflags filename contents = do PFailedWithErrorMessages msgs -> throwE $ diagFromErrMsgs "parser" dflags $ msgs dflags POk pst rdr_module -> do - let (warns, errs) = renderMessages $ getMessages' pst dflags + let (warns, errs) = renderMessages $ getPsMessages pst dflags -- Just because we got a `POk`, it doesn't mean there -- weren't errors! To clarify, the GHC parser @@ -1257,7 +1254,7 @@ parseFileContents env customPreprocessor filename ms = do POk pst rdr_module -> let hpm_annotations = mkApiAnns pst - psMessages = getMessages' pst dflags + psMessages = getPsMessages pst dflags in do let IdePreprocessedSource preproc_warns errs parsed = customPreprocessor rdr_module diff --git a/ghcide/src/Development/IDE/GHC/Compat.hs b/ghcide/src/Development/IDE/GHC/Compat.hs index 1ccd8ad58e..d99a8c6566 100644 --- a/ghcide/src/Development/IDE/GHC/Compat.hs +++ b/ghcide/src/Development/IDE/GHC/Compat.hs @@ -25,7 +25,7 @@ module Development.IDE.GHC.Compat( disableWarningsAsErrors, reLoc, reLocA, - getMessages', + getPsMessages, renderMessages, pattern PFailedWithErrorMessages, isObjectLinkable, @@ -373,31 +373,6 @@ corePrepExpr _ = GHC.corePrepExpr simplifyExpr df _ = GHC.simplifyExpr df #endif -#if MIN_VERSION_ghc(9,2,0) -type ErrMsg = MsgEnvelope DecoratedSDoc -#endif -#if MIN_VERSION_ghc(9,3,0) -type WarnMsg = MsgEnvelope DecoratedSDoc -#endif - -#if !MIN_VERSION_ghc(9,3,0) -type PsMessages = (Bag WarnMsg, Bag ErrMsg) -#endif - -getMessages' :: PState -> DynFlags -> PsMessages -getMessages' pst dflags = -#if MIN_VERSION_ghc(9,3,0) - uncurry PsMessages $ getPsMessages pst -#else -#if MIN_VERSION_ghc(9,2,0) - bimap (fmap pprWarning) (fmap pprError) $ -#endif - getMessages pst -#if !MIN_VERSION_ghc(9,2,0) - dflags -#endif -#endif - renderMessages :: PsMessages -> (Bag WarnMsg, Bag ErrMsg) renderMessages msgs = #if MIN_VERSION_ghc(9,3,0) diff --git a/ghcide/src/Development/IDE/GHC/Compat/Core.hs b/ghcide/src/Development/IDE/GHC/Compat/Core.hs index 56579f6130..b89d7a1c35 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Core.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Core.hs @@ -579,7 +579,7 @@ import GHC.Parser.Header hiding (getImports) #if MIN_VERSION_ghc(9,2,0) import qualified GHC.Linker.Loader as Linker import GHC.Linker.Types -import GHC.Parser.Lexer hiding (initParserState) +import GHC.Parser.Lexer hiding (initParserState, getPsMessages) import GHC.Parser.Annotation (EpAnn (..)) import GHC.Platform.Ways import GHC.Runtime.Context (InteractiveImport (..)) diff --git a/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs b/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs index 0dd10fc9a3..f34f03658f 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs @@ -27,6 +27,8 @@ module Development.IDE.GHC.Compat.Outputable ( -- * Error infrastructure DecoratedSDoc, MsgEnvelope, + ErrMsg, + WarnMsg, errMsgSpan, errMsgSeverity, formatErrorWithQual, @@ -192,6 +194,13 @@ type PsWarning = ErrMsg type PsError = ErrMsg #endif +#if MIN_VERSION_ghc(9,2,0) +type ErrMsg = MsgEnvelope DecoratedSDoc +#endif +#if MIN_VERSION_ghc(9,3,0) +type WarnMsg = MsgEnvelope DecoratedSDoc +#endif + mkPrintUnqualifiedDefault :: HscEnv -> GlobalRdrEnv -> PrintUnqualified mkPrintUnqualifiedDefault env = #if MIN_VERSION_ghc(9,2,0) diff --git a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs index 7bc8d3e237..990ad2d0dc 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs @@ -2,6 +2,7 @@ -- | Plugin Compat utils. module Development.IDE.GHC.Compat.Plugins ( + -- * Plugin Compat Types, and initialisation Plugin(..), defaultPlugin, PluginWithArgs(..), @@ -12,32 +13,58 @@ module Development.IDE.GHC.Compat.Plugins ( -- * Static plugins StaticPlugin(..), hsc_static_plugins, + + -- * Plugin messages + PsMessages(..), + getPsMessages ) where #if MIN_VERSION_ghc(9,0,0) #if MIN_VERSION_ghc(9,2,0) -import qualified GHC.Driver.Env as Env +import qualified GHC.Driver.Env as Env #endif -import GHC.Driver.Plugins (Plugin (..), - PluginWithArgs (..), - StaticPlugin (..), - defaultPlugin, withPlugins) +import GHC.Driver.Plugins (Plugin (..), + PluginWithArgs (..), + StaticPlugin (..), + defaultPlugin, + withPlugins) #if MIN_VERSION_ghc(9,3,0) -import GHC.Driver.Plugins (ParsedResult (..), - PsMessages (..), - staticPlugins) +import GHC.Driver.Plugins (ParsedResult (..), + PsMessages (..), + staticPlugins) +import qualified GHC.Parser.Lexer as Lexer +#else +import Data.Bifunctor (bimap) #endif -import qualified GHC.Runtime.Loader as Loader +import qualified GHC.Runtime.Loader as Loader #else -import qualified DynamicLoading as Loader +import qualified DynamicLoading as Loader import Plugins #endif import Development.IDE.GHC.Compat.Core -import Development.IDE.GHC.Compat.Env (hscSetFlags, hsc_dflags) -import Development.IDE.GHC.Compat.Parser as Parser -import Debug.Trace -import GHC.Driver.Env (hsc_plugins) -import GHC.Driver.Plugins +import Development.IDE.GHC.Compat.Env (hscSetFlags, hsc_dflags) +import Development.IDE.GHC.Compat.Outputable as Out +import Development.IDE.GHC.Compat.Parser as Parser +import Development.IDE.GHC.Compat.Util (Bag) + + +#if !MIN_VERSION_ghc(9,3,0) +type PsMessages = (Bag WarnMsg, Bag ErrMsg) +#endif + +getPsMessages :: PState -> DynFlags -> PsMessages +getPsMessages pst dflags = +#if MIN_VERSION_ghc(9,3,0) + uncurry PsMessages $ Lexer.getPsMessages pst +#else +#if MIN_VERSION_ghc(9,2,0) + bimap (fmap pprWarning) (fmap pprError) $ +#endif + getMessages pst +#if !MIN_VERSION_ghc(9,2,0) + dflags +#endif +#endif applyPluginsParsedResultAction :: HscEnv -> DynFlags -> ModSummary -> Parser.ApiAnns -> ParsedSource -> PsMessages -> IO (ParsedSource, PsMessages) applyPluginsParsedResultAction env dflags ms hpm_annotations parsed msgs = do @@ -46,7 +73,7 @@ applyPluginsParsedResultAction env dflags ms hpm_annotations parsed msgs = do #if MIN_VERSION_ghc(9,3,0) fmap (\result -> (hpm_module (parsedResultModule result), (parsedResultMessages result))) $ runHsc env $ withPlugins #else - fmap ((, msgs), hpm_module) $ runHsc env $ withPlugins + fmap (\parsed_module -> (hpm_module parsed_module, msgs)) $ runHsc env $ withPlugins #endif #if MIN_VERSION_ghc(9,3,0) (Env.hsc_plugins env) From 3801b23343c21102b8b61cfa5f7801960a2076a2 Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 12:51:30 +0100 Subject: [PATCH 4/8] Enable test for source plugins --- ghcide/test/exe/Main.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/ghcide/test/exe/Main.hs b/ghcide/test/exe/Main.hs index 6b196e5653..57a3dd6a62 100644 --- a/ghcide/test/exe/Main.hs +++ b/ghcide/test/exe/Main.hs @@ -1212,7 +1212,6 @@ checkFileCompiles fp diag = pluginSimpleTests :: TestTree pluginSimpleTests = ignoreInWindowsForGHC810 $ - ignoreForGHC92Plus "blocked on ghc-typelits-natnormalise" $ testSessionWithExtraFiles "plugin-knownnat" "simple plugin" $ \dir -> do _ <- openDoc (dir "KnownNat.hs") "haskell" liftIO $ writeFile (dir"hie.yaml") From 4a44857243e16b4dd8ee02185cc5bfe791b6e4bc Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 12:53:13 +0100 Subject: [PATCH 5/8] Turn into haddock comment --- ghcide/src/Development/IDE/GHC/Compat/Plugins.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs index 990ad2d0dc..79e1602e02 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs @@ -98,7 +98,7 @@ initializePlugins env = do pure $ hscSetFlags newDf env #endif --- Plugins aren't stored in ModSummary anymore since GHC 9.0, but this +-- | Plugins aren't stored in ModSummary anymore since GHC 9.2, but this -- function still returns it for compatibility with 8.10 initPlugins :: HscEnv -> ModSummary -> IO (ModSummary, HscEnv) initPlugins session modSummary = do From a550f388721a13b25872056238f9485196c16963 Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 13:23:08 +0100 Subject: [PATCH 6/8] Move plugin initialisation to 'GetModSummary' rule --- ghcide/src/Development/IDE/Core/Compile.hs | 7 ++++--- ghcide/src/Development/IDE/Core/RuleTypes.hs | 6 ++++++ ghcide/src/Development/IDE/Core/Rules.hs | 8 ++------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ghcide/src/Development/IDE/Core/Compile.hs b/ghcide/src/Development/IDE/Core/Compile.hs index 2f784b360c..ef8a41538f 100644 --- a/ghcide/src/Development/IDE/Core/Compile.hs +++ b/ghcide/src/Development/IDE/Core/Compile.hs @@ -1151,9 +1151,9 @@ getModSummaryFromImports env fp modTime contents = do then mkHomeModLocation dflags (pathToModuleName fp) fp else mkHomeModLocation dflags mod fp - let modl = mkHomeModule (hscHomeUnit (hscSetFlags dflags env)) mod + let modl = mkHomeModule (hscHomeUnit env) mod sourceType = if "-boot" `isSuffixOf` takeExtension fp then HsBootFile else HsSrcFile - msrModSummary = + msrModSummary2 = ModSummary { ms_mod = modl , ms_hie_date = Nothing @@ -1178,7 +1178,8 @@ getModSummaryFromImports env fp modTime contents = do , ms_textual_imps = textualImports } - msrFingerprint <- liftIO $ computeFingerprint opts msrModSummary + msrFingerprint <- liftIO $ computeFingerprint opts msrModSummary2 + (msrModSummary, msrHscEnv) <- liftIO $ initPlugins env msrModSummary2 return ModSummaryResult{..} where -- Compute a fingerprint from the contents of `ModSummary`, diff --git a/ghcide/src/Development/IDE/Core/RuleTypes.hs b/ghcide/src/Development/IDE/Core/RuleTypes.hs index 92145d494c..e72126bc23 100644 --- a/ghcide/src/Development/IDE/Core/RuleTypes.hs +++ b/ghcide/src/Development/IDE/Core/RuleTypes.hs @@ -357,6 +357,12 @@ data ModSummaryResult = ModSummaryResult { msrModSummary :: !ModSummary , msrImports :: [LImportDecl GhcPs] , msrFingerprint :: !Fingerprint + , msrHscEnv :: !HscEnv + -- ^ HscEnv for this particular ModSummary. + -- Contains initialised plugins, parsed options, etc... + -- + -- Implicit assumption: DynFlags in 'msrModSummary' are the same as + -- the DynFlags in 'msrHscEnv'. } instance Show ModSummaryResult where diff --git a/ghcide/src/Development/IDE/Core/Rules.hs b/ghcide/src/Development/IDE/Core/Rules.hs index 1095ea577c..71f278b798 100644 --- a/ghcide/src/Development/IDE/Core/Rules.hs +++ b/ghcide/src/Development/IDE/Core/Rules.hs @@ -253,9 +253,7 @@ getParsedModuleRule :: Recorder (WithPriority Log) -> Rules () getParsedModuleRule recorder = -- this rule does not have early cutoff since all its dependencies already have it define (cmapWithPrio LogShake recorder) $ \GetParsedModule file -> do - ModSummaryResult{msrModSummary = ms'} <- use_ GetModSummary file - sess <- use_ GhcSession file - (ms', hsc) <- liftIO $ initPlugins (hscEnv sess) ms' + ModSummaryResult{msrModSummary = ms', msrHscEnv = hsc} <- use_ GetModSummary file opt <- getIdeOptions modify_dflags <- getModifyDynFlags dynFlagsModifyParser let ms = ms' { ms_hspp_opts = modify_dflags $ ms_hspp_opts ms' } @@ -327,9 +325,7 @@ getParsedModuleWithCommentsRule recorder = -- The parse diagnostics are owned by the GetParsedModule rule -- For this reason, this rule does not produce any diagnostics defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetParsedModuleWithComments file -> do - ModSummaryResult{msrModSummary = ms} <- use_ GetModSummary file - sess <- use_ GhcSession file - (ms, hsc) <- liftIO $ initPlugins (hscEnv sess) ms + ModSummaryResult{msrModSummary = ms, msrHscEnv = hsc} <- use_ GetModSummary file opt <- getIdeOptions let ms' = withoutOption Opt_Haddock $ withOption Opt_KeepRawTokenStream ms From cd2cd214bc89770b4529eb3f800416ab7c685481 Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 13:27:34 +0100 Subject: [PATCH 7/8] Remove superfluous space --- ghcide/src/Development/IDE/Core/RuleTypes.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghcide/src/Development/IDE/Core/RuleTypes.hs b/ghcide/src/Development/IDE/Core/RuleTypes.hs index e72126bc23..edc2abe148 100644 --- a/ghcide/src/Development/IDE/Core/RuleTypes.hs +++ b/ghcide/src/Development/IDE/Core/RuleTypes.hs @@ -155,7 +155,7 @@ data TcModuleResult = TcModuleResult , tmrTypechecked :: TcGblEnv , tmrTopLevelSplices :: Splices -- ^ Typechecked splice information - , tmrDeferredError :: !Bool + , tmrDeferredError :: !Bool -- ^ Did we defer any type errors for this module? , tmrRuntimeModules :: !(ModuleEnv ByteString) -- ^ Which modules did we need at runtime while compiling this file? From e56dd59bb0e58cf1db29ba9ae64a551e17c2a536 Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 19 Dec 2022 15:33:12 +0100 Subject: [PATCH 8/8] Ignore plugin test on windows --- ghcide/test/exe/Main.hs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ghcide/test/exe/Main.hs b/ghcide/test/exe/Main.hs index 57a3dd6a62..f9236cb1fc 100644 --- a/ghcide/test/exe/Main.hs +++ b/ghcide/test/exe/Main.hs @@ -1209,9 +1209,32 @@ checkFileCompiles fp diag = void (openTestDataDoc (dir fp)) diag + pluginSimpleTests :: TestTree pluginSimpleTests = ignoreInWindowsForGHC810 $ + -- Build profile: -w ghc-9.4.2 -O1 + -- In order, the following will be built (use -v for more details): + -- - ghc-typelits-natnormalise-0.7.7 (lib) (requires build) + -- - ghc-typelits-knownnat-0.7.7 (lib) (requires build) + -- - plugin-1.0.0 (lib) (first run) + -- Starting ghc-typelits-natnormalise-0.7.7 (lib) + -- Building ghc-typelits-natnormalise-0.7.7 (lib) + + -- Failed to build ghc-typelits-natnormalise-0.7.7. + -- Build log ( + -- C:\cabal\logs\ghc-9.4.2\ghc-typelits-_-0.7.7-3f036a52a0d9bfc3389d1852a87da2e87c6de2e4.log + -- ): + -- Preprocessing library for ghc-typelits-natnormalise-0.7.7.. + -- Building library for ghc-typelits-natnormalise-0.7.7.. + -- [1 of 3] Compiling GHC.TypeLits.Normalise.SOP ( src\GHC\TypeLits\Normalise\SOP.hs, dist\build\GHC\TypeLits\Normalise\SOP.o ) + -- [2 of 3] Compiling GHC.TypeLits.Normalise.Unify ( src\GHC\TypeLits\Normalise\Unify.hs, dist\build\GHC\TypeLits\Normalise\Unify.o ) + -- [3 of 3] Compiling GHC.TypeLits.Normalise ( src-ghc-9.4\GHC\TypeLits\Normalise.hs, dist\build\GHC\TypeLits\Normalise.o ) + -- C:\tools\ghc-9.4.2\lib\../mingw/bin/llvm-ar.exe: error: dist\build\objs-5156\libHSghc-typelits-_-0.7.7-3f036a52a0d9bfc3389d1852a87da2e87c6de2e4.a: No such file or directory + + -- Error: cabal: Failed to build ghc-typelits-natnormalise-0.7.7 (which is + -- required by plugin-1.0.0). See the build log above for details. + ignoreFor (BrokenSpecific Windows [GHC94]) "ghc-typelist-natnormalise fails to build on GHC 9.4.2 for windows only" $ testSessionWithExtraFiles "plugin-knownnat" "simple plugin" $ \dir -> do _ <- openDoc (dir "KnownNat.hs") "haskell" liftIO $ writeFile (dir"hie.yaml")