diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca67b53dc4..d7f4399130 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,9 @@ jobs: fail-fast: false matrix: ghc: - [ "9.0.1" - , '8.10.7' + [ "9.2.1" + , "9.0.1" + , "8.10.7" , "8.10.6" , "8.8.4" , "8.6.5" @@ -56,6 +57,9 @@ jobs: - name: (GHC 9.0) Use modified cabal.project for GHC 9.0 if: ${{ matrix.ghc == '9.0.1' }} run: cp cabal-ghc901.project cabal.project + - name: Use modified cabal.project for ghc9.2 + if: ${{ matrix.ghc == '9.2.1' }} + run: cp cabal-ghc921.project cabal.project - name: Shorten binary names run: | diff --git a/.github/workflows/caching.yml b/.github/workflows/caching.yml index bb8dcb3583..0620b12e11 100644 --- a/.github/workflows/caching.yml +++ b/.github/workflows/caching.yml @@ -76,7 +76,8 @@ jobs: strategy: fail-fast: false matrix: - ghc: [ "9.0.1" + ghc: [ "9.2.1" + , "9.0.1" , "8.10.7" , "8.10.6" , "8.8.4" @@ -109,20 +110,10 @@ jobs: # repeating builds to workaround segfaults in windows and ghc-8.8.4 # This build agenda in not to have successful code, - # but to cache what can be cached, so step is fault tolerant & would always succeed. - # 2021-12-11: NOTE: Need to building all targets (build the project also), since - # current Cabal does not allow `all --enable-tests --enable-benchmarks --only-dependencies` combination - - - if: steps.compiled-deps.outputs.cache-hit != 'true' && runner.os == 'Linux' && matrix.ghc == '8.10.7' - name: (For Bench workflow) Build benchmark targets - continue-on-error: true - # Downloaded separately, to match the tested work/PR workflow guarantees - run: | - cabal $cabalBuild --enable-benchmarks || cabal $cabalBuild --enable-benchmarks || cabal $cabalBuild --enable-benchmarks - + # but to cache what can be cached, so step is fault tolerant & would always succseed. + # 2021-12-11: NOTE: Building all targets, since + # current Cabal does not allow `all --enable-tests --enable-benchmarks --only-dependencies` - if: steps.compiled-deps.outputs.cache-hit != 'true' - name: Build targets; try 3 times - continue-on-error: true - # Done separately, matching the tested work/PR workflow guarantees + name: Build all targets; try 3 times run: | - cabal $cabalBuild --enable-test || cabal $cabalBuild --enable-test || cabal $cabalBuild --enable-test + cabal $cabalBuild || cabal $cabalBuild || cabal $cabalBuild diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc72dd3e30..7442eb41ae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,7 +56,8 @@ jobs: strategy: fail-fast: true matrix: - ghc: [ "9.0.1" + ghc: [ "9.2.1" + , "9.0.1" , "8.10.7" , "8.10.6" , "8.8.4" @@ -66,33 +67,34 @@ jobs: , "macOS-latest" ] include: - # only test supported ghc major versions - - os: ubuntu-latest - ghc: '9.0.1' - test: true - - os: ubuntu-latest - ghc: '8.10.7' - test: true - - os: ubuntu-latest - ghc: '8.8.4' - test: true - - os: ubuntu-latest - ghc: '8.6.5' - test: true - - os: windows-latest - ghc: '9.0.1' - test: true - - os: windows-latest - ghc: '8.10.7' - test: true - - os: windows-latest - ghc: '8.6.5' - test: true - # only build rest of supported ghc versions for windows - - os: windows-latest - ghc: '8.10.6' - - os: windows-latest - ghc: '8.8.4' + # only test supported ghc major versions + - os: ubuntu-latest + ghc: '9.2.1' + test: true + - os: ubuntu-latest + ghc: '9.0.1' + test: true + - os: ubuntu-latest + ghc: '8.10.7' + test: true + - os: ubuntu-latest + ghc: '8.8.4' + test: true + - os: ubuntu-latest + ghc: '8.6.5' + test: true + - os: windows-latest + ghc: '9.2.1' + test: true + - os: windows-latest + ghc: '9.0.1' + test: true + - os: windows-latest + ghc: '8.10.7' + test: true + - os: windows-latest + ghc: '8.6.5' + test: true steps: - uses: actions/checkout@v2 @@ -144,15 +146,15 @@ jobs: run: cabal test wrapper-test --test-options="$TEST_OPTS --rerun-log-file .tasty-rerun-log-wrapper" || cabal test wrapper-test --test-options="$TEST_OPTS --rerun-log-file .tasty-rerun-log-wrapper" || cabal test wrapper-test --test-options="$TEST_OPTS --rerun-log-file .tasty-rerun-log-wrapper" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-brittany-plugin run: cabal test hls-brittany-plugin --test-options="$TEST_OPTS" || cabal test hls-brittany-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-brittany-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-floskell-plugin run: cabal test hls-floskell-plugin --test-options="$TEST_OPTS" || cabal test hls-floskell-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-floskell-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-class-plugin run: cabal test hls-class-plugin --test-options="$TEST_OPTS" || cabal test hls-class-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-class-plugin --test-options="$TEST_OPTS" @@ -160,35 +162,35 @@ jobs: name: Test hls-pragmas-plugin run: cabal test hls-pragmas-plugin --test-options="$TEST_OPTS" || cabal test hls-pragmas-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-pragmas-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-eval-plugin run: cabal test hls-eval-plugin --test-options="$TEST_OPTS" || cabal test hls-eval-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-eval-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-haddock-comments-plugin run: cabal test hls-haddock-comments-plugin --test-options="$TEST_OPTS" || cabal test hls-haddock-comments-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-haddock-comments-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-splice-plugin run: cabal test hls-splice-plugin --test-options="$TEST_OPTS" || cabal test hls-splice-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-splice-plugin --test-options="$TEST_OPTS" - - if: matrix.test && matrix.ghc != '9.0.1' + - if: matrix.test && matrix.ghc != '9.0.1' && matrix.ghc != '9.2.1' name: Test hls-stylish-haskell-plugin run: cabal test hls-stylish-haskell-plugin --test-options="$TEST_OPTS" || cabal test hls-stylish-haskell-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-stylish-haskell-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-ormolu-plugin run: cabal test hls-ormolu-plugin --test-options="$TEST_OPTS" || cabal test hls-ormolu-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-ormolu-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-fourmolu-plugin run: cabal test hls-fourmolu-plugin --test-options="$TEST_OPTS" || cabal test hls-fourmolu-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-fourmolu-plugin --test-options="$TEST_OPTS" - - if: matrix.test && matrix.ghc != '9.0.1' && !(matrix.os == 'ubuntu-latest' && matrix.ghc == '8.6.5') + - if: matrix.test && matrix.ghc != '9.0.1' && matrix.ghc != '9.2.1' && !(matrix.os == 'ubuntu-latest' && matrix.ghc == '8.6.5') name: Test hls-tactics-plugin test suite run: cabal test hls-tactics-plugin --test-options="$TEST_OPTS" || cabal test hls-tactics-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-tactics-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-refine-imports-plugin test suite run: cabal test hls-refine-imports-plugin --test-options="$TEST_OPTS" || cabal test hls-refine-imports-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-refine-imports-plugin --test-options="$TEST_OPTS" @@ -200,19 +202,19 @@ jobs: name: Test hls-call-hierarchy-plugin test suite run: cabal test hls-call-hierarchy-plugin --test-options="$TEST_OPTS" || cabal test hls-call-hierarchy-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-call-hierarchy-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-rename-plugin test suite run: cabal test hls-rename-plugin --test-options="$TEST_OPTS" || cabal test hls-rename-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-rename-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-hlint-plugin test suite run: cabal test hls-hlint-plugin --test-options="$TEST_OPTS" || cabal test hls-hlint-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-hlint-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-alternate-number-format-plugin test suite run: cabal test hls-alternate-number-format-plugin --test-options="$TEST_OPTS" || cabal test hls-alternate-number-format-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-alternate-number-format-plugin --test-options="$TEST_OPTS" - - if: matrix.test + - if: matrix.test && matrix.ghc != '9.2.1' name: Test hls-qualify-imported-names-plugin test suite run: cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS" || cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS" diff --git a/cabal-ghc921.project b/cabal-ghc921.project index fe534c783c..0bfb0c086e 100644 --- a/cabal-ghc921.project +++ b/cabal-ghc921.project @@ -11,20 +11,38 @@ packages: -- ./plugins/hls-stylish-haskell-plugin -- ./plugins/hls-fourmolu-plugin ./plugins/hls-class-plugin - ./plugins/hls-eval-plugin + -- ./plugins/hls-eval-plugin ./plugins/hls-explicit-imports-plugin - ./plugins/hls-refine-imports-plugin - ./plugins/hls-hlint-plugin + -- ./plugins/hls-refine-imports-plugin + -- ./plugins/hls-hlint-plugin + ./plugins/hls-rename-plugin -- ./plugins/hls-retrie-plugin - ./plugins/hls-haddock-comments-plugin - -- ./plugins/hls-splice-plugin + -- ./plugins/hls-haddock-comments-plugin + -- ./plugins/hls-splice-plugin ./plugins/hls-qualify-imported-names-plugin - ./plugins/hls-floskell-plugin + -- ./plugins/hls-floskell-plugin ./plugins/hls-pragmas-plugin ./plugins/hls-module-name-plugin - ./plugins/hls-ormolu-plugin + -- ./plugins/hls-ormolu-plugin ./plugins/hls-call-hierarchy-plugin - ./plugins/hls-alternate-number-format-plugin + -- ./plugins/hls-alternate-number-format-plugin + +source-repository-package + type: git + location: https://github.com/tfausak/unix-compat + tag: 154c3a63f154cb49c51d5f9d13488e8119631d8a + -- To fix windows build + -- https://github.com/jacobstanley/unix-compat/pull/47 + +repository head.hackage.ghc.haskell.org + url: https://ghc.gitlab.haskell.org/head.hackage/ + secure: True + key-threshold: 3 + root-keys: + f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89 + 26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329 + 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d + with-compiler: ghc-9.2.1 @@ -36,11 +54,40 @@ package * write-ghc-environment-files: never -index-state: 2021-12-29T12:30:08Z +index-state: 2022-01-03T18:45:00Z constraints: - -- These plugins doesn't work on GHC92 yet - haskell-language-server +ignore-plugins-ghc-bounds -brittany -class -fourmolu -splice -stylishhaskell -tactic -refineImports -callhierarchy -retrie + -- These plugins don't build/work on GHC92 yet + haskell-language-server + +ignore-plugins-ghc-bounds + -alternateNumberFormat + -brittany + -callhierarchy + -class + -eval + -floskell + -fourmolu + -haddockComments + -hlint + -moduleName + -ormolu + -qualifyImportedNames + -refineImports + -retrie + -splice + -stylishhaskell + -tactic + -- the rename plugin builds, but doesn't work + -rename, + ghc-lib-parser ^>= 9.2, + attoparsec ^>= 0.14.3, + ghc-exactprint >= 1.3, + retrie >= 1.2, + direct-sqlite == 2.3.26, + lens >= 5.0.1, + primitive-unlifted ==0.1.3.1, + -- these constraints are for head.hackage + aeson ==1.5.6.0, allow-newer: Cabal, @@ -62,4 +109,10 @@ allow-newer: dependent-sum:constraints, diagrams:diagrams-core, Chart-diagrams:diagrams-core, - SVGFonts:diagrams-core + SVGFonts:diagrams-core, + + -- for head.hackage + primitive-unlifted:base + +allow-older: + primitive-extras:primitive-unlifted diff --git a/ghcide/.hlint.yaml b/ghcide/.hlint.yaml index 4f271f5e7d..52354291b3 100644 --- a/ghcide/.hlint.yaml +++ b/ghcide/.hlint.yaml @@ -114,6 +114,8 @@ - Development.IDE.Spans.AtPoint - Development.IDE.Spans.Pragmas - Development.IDE.Plugin.CodeAction + - Development.IDE.Plugin.CodeAction.Args + - Development.IDE.Plugin.CodeAction.ExactPrint - Development.IDE.Plugin.Completions - Development.IDE.Plugin.Completions.Logic - Development.IDE.Types.Location diff --git a/ghcide/bench/lib/Experiments.hs b/ghcide/bench/lib/Experiments.hs index d12c051aee..6fd08fe444 100644 --- a/ghcide/bench/lib/Experiments.hs +++ b/ghcide/bench/lib/Experiments.hs @@ -3,6 +3,7 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE ImpredicativeTypes #-} +{-# LANGUAGE PolyKinds #-} {-# OPTIONS_GHC -Wno-deprecations -Wno-unticked-promoted-constructors #-} module Experiments @@ -251,7 +252,7 @@ configP = <*> option auto (long "timeout" <> value 60 <> help "timeout for waiting for a ghcide response") <*> ( Example "name" <$> (Right <$> packageP) - <*> (some moduleOption <|> pure ["Distribution/Simple.hs"]) + <*> (some moduleOption <|> pure ["src/Distribution/Simple.hs"]) <*> pure [] <|> Example "name" @@ -263,7 +264,7 @@ configP = packageP = ExamplePackage <$> strOption (long "example-package-name" <> value "Cabal") - <*> option versionP (long "example-package-version" <> value (makeVersion [3,4,0,0])) + <*> option versionP (long "example-package-version" <> value (makeVersion [3,6,0,0])) pathP = strOption (long "example-path") versionP :: ReadM Version diff --git a/ghcide/ghcide.cabal b/ghcide/ghcide.cabal index acefcc407d..82791a1701 100644 --- a/ghcide/ghcide.cabal +++ b/ghcide/ghcide.cabal @@ -163,6 +163,7 @@ library Development.IDE.GHC.Compat Development.IDE.GHC.Compat.Core Development.IDE.GHC.Compat.Env + Development.IDE.GHC.Compat.ExactPrint Development.IDE.GHC.Compat.Iface Development.IDE.GHC.Compat.Logger Development.IDE.GHC.Compat.Outputable @@ -171,6 +172,7 @@ library Development.IDE.GHC.Compat.Units Development.IDE.GHC.Compat.Util Development.IDE.Core.Compile + Development.IDE.GHC.Dump Development.IDE.GHC.Error Development.IDE.GHC.ExactPrint Development.IDE.GHC.Orphans @@ -409,7 +411,7 @@ test-suite ghcide-tests tasty-rerun, text, unordered-containers, - if (impl(ghc >= 8.6)) + if (impl(ghc >= 8.6) && impl(ghc < 9.2)) build-depends: record-dot-preprocessor, record-hasfield diff --git a/ghcide/session-loader/Development/IDE/Session.hs b/ghcide/session-loader/Development/IDE/Session.hs index bf93c060cc..9f4222fec0 100644 --- a/ghcide/session-loader/Development/IDE/Session.hs +++ b/ghcide/session-loader/Development/IDE/Session.hs @@ -432,7 +432,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do newHscEnv <- -- Add the options for the current component to the HscEnv evalGhcEnv hscEnv $ do - _ <- setSessionDynFlags df + _ <- setSessionDynFlags $ setHomeUnitId_ fakeUid df getSession -- Modify the map so the hieYaml now maps to the newly created @@ -628,10 +628,7 @@ cradleToOptsAndLibDir logger cradle file = do emptyHscEnv :: IORef NameCache -> FilePath -> IO HscEnv emptyHscEnv nc libDir = do env <- runGhc (Just libDir) getSession - when (Compat.ghcVersion < Compat.GHC90) $ - -- This causes ghc9 to crash with the error: - -- Couldn't find a target code interpreter. Try with -fexternal-interpreter - initDynLinker env + initDynLinker env pure $ setNameCache nc (hscSetFlags ((hsc_dflags env){useUnicode = True }) env) data TargetDetails = TargetDetails diff --git a/ghcide/src/Development/IDE/Core/Compile.hs b/ghcide/src/Development/IDE/Core/Compile.hs index 46ca2bfd95..9279abd288 100644 --- a/ghcide/src/Development/IDE/Core/Compile.hs +++ b/ghcide/src/Development/IDE/Core/Compile.hs @@ -27,7 +27,6 @@ module Development.IDE.Core.Compile , loadHieFile , loadInterface , loadModulesHome - , setupFinderCache , getDocsBatch , lookupName ,mergeEnvs) where @@ -56,9 +55,9 @@ import HieDb import Language.LSP.Types (DiagnosticTag (..)) #if MIN_VERSION_ghc(8,10,0) -import Control.DeepSeq (force, rnf, liftRnf, rwhnf) +import Control.DeepSeq (force, liftRnf, rnf, rwhnf) #else -import Control.DeepSeq (rnf, liftRnf, rwhnf) +import Control.DeepSeq (liftRnf, rnf, rwhnf) import ErrUtils #endif @@ -69,6 +68,10 @@ import GHC.Tc.Gen.Splice import TcSplice #endif +#if MIN_VERSION_ghc(9,2,0) +import qualified GHC.Types.Error as Error +#endif + import Control.Exception (evaluate) import Control.Exception.Safe import Control.Lens hiding (List) @@ -79,6 +82,7 @@ import Data.Bifunctor (first, second) import qualified Data.ByteString as BS import qualified Data.DList as DL import Data.IORef +import qualified Data.IntMap.Strict as IntMap import Data.List.Extra import qualified Data.Map.Strict as Map import Data.Maybe @@ -102,6 +106,7 @@ import Data.Binary import Data.Coerce import Data.Functor import qualified Data.HashMap.Strict as HashMap +import Data.IntMap (IntMap) import Data.Map (Map) import Data.Tuple.Extra (dupe) import Data.Unique as Unique @@ -142,24 +147,27 @@ typecheckModule :: IdeDefer -> ParsedModule -> IO (IdeResult TcModuleResult) typecheckModule (IdeDefer defer) hsc keep_lbls pm = do - fmap (either (,Nothing) id) $ - catchSrcErrors (hsc_dflags hsc) "typecheck" $ do - let modSummary = pm_mod_summary pm dflags = ms_hspp_opts modSummary - - modSummary' <- initPlugins hsc modSummary - (warnings, tcm) <- withWarnings "typecheck" $ \tweak -> - let - session = tweak (hscSetFlags dflags hsc) - -- TODO: maybe settings ms_hspp_opts is unnecessary? - mod_summary'' = modSummary' { ms_hspp_opts = hsc_dflags session} - in - tcRnModule hsc keep_lbls $ demoteIfDefer pm{pm_mod_summary = mod_summary''} - let errorPipeline = unDefer . hideDiag dflags . tagDiag - diags = map errorPipeline warnings - deferedError = any fst diags - return (map snd diags, Just $ tcm{tmrDeferedError = deferedError}) + mmodSummary' <- catchSrcErrors (hsc_dflags hsc) "typecheck (initialize plugins)" + (initPlugins hsc modSummary) + case mmodSummary' of + Left errs -> return (errs, Nothing) + Right modSummary' -> do + (warnings, etcm) <- withWarnings "typecheck" $ \tweak -> + let + session = tweak (hscSetFlags dflags hsc) + -- TODO: maybe settings ms_hspp_opts is unnecessary? + mod_summary'' = modSummary' { ms_hspp_opts = hsc_dflags session} + in + catchSrcErrors (hsc_dflags hsc) "typecheck" $ do + tcRnModule session keep_lbls $ demoteIfDefer pm{pm_mod_summary = mod_summary''} + let errorPipeline = unDefer . hideDiag dflags . tagDiag + diags = map errorPipeline warnings + deferedError = any fst diags + case etcm of + Left errs -> return (map snd diags ++ errs, Nothing) + Right tcm -> return (map snd diags, Just $ tcm{tmrDeferedError = deferedError}) where demoteIfDefer = if defer then demoteTypeErrorsToWarnings else id @@ -208,7 +216,7 @@ tcRnModule hsc_env keep_lbls pmod = do unload hsc_env_tmp keep_lbls ((tc_gbl_env, mrn_info), splices) - <- liftIO $ captureSplices (hscSetFlags (ms_hspp_opts ms) hsc_env) $ \hsc_env_tmp -> + <- liftIO $ captureSplices hsc_env_tmp $ \hsc_env_tmp -> do hscTypecheckRename hsc_env_tmp ms $ HsParsedModule { hpm_module = parsedSource pmod, hpm_src_files = pm_extra_src_files pmod, @@ -305,6 +313,8 @@ compileModule (RunSimplifier simplify) session ms tcg = (warnings,desugared_guts) <- withWarnings "compile" $ \tweak -> do let session' = tweak (hscSetFlags (ms_hspp_opts ms) session) -- TODO: maybe settings ms_hspp_opts is unnecessary? + -- MP: the flags in ModSummary should be right, if they are wrong then + -- the correct place to fix this is when the ModSummary is created. desugar <- hscDesugar session' (ms { ms_hspp_opts = hsc_dflags session' }) tcg if simplify then do @@ -325,7 +335,7 @@ generateObjectCode session summary guts = do withWarnings "object" $ \tweak -> do let env' = tweak (hscSetFlags (ms_hspp_opts summary) session) target = platformDefaultBackend (hsc_dflags env') - newFlags = setBackend target $ updOptLevel 0 $ (hsc_dflags env') { outputFile = Just dot_o } + newFlags = setBackend target $ updOptLevel 0 $ setOutputFile dot_o $ hsc_dflags env' session' = hscSetFlags newFlags session #if MIN_VERSION_ghc(9,0,1) (outputFilename, _mStub, _foreign_files, _cinfos) <- hscGenHardCode session' guts @@ -465,12 +475,19 @@ generateHieAsts hscEnv tcm = top_ev_binds = tcg_ev_binds ts :: Util.Bag EvBind insts = tcg_insts ts :: [ClsInst] tcs = tcg_tcs ts :: [TyCon] - Just <$> GHC.enrichHie (fake_splice_binds `Util.unionBags` real_binds) (tmrRenamed tcm) top_ev_binds insts tcs + run ts $ + Just <$> GHC.enrichHie (fake_splice_binds `Util.unionBags` real_binds) (tmrRenamed tcm) top_ev_binds insts tcs #else Just <$> GHC.enrichHie (fake_splice_binds `Util.unionBags` real_binds) (tmrRenamed tcm) #endif where dflags = hsc_dflags hscEnv + run ts = +#if MIN_VERSION_ghc(9,2,0) + fmap (join . snd) . liftIO . initDs hscEnv ts +#else + id +#endif spliceExpresions :: Splices -> [LHsExpr GhcTc] spliceExpresions Splices{..} = @@ -655,30 +672,6 @@ handleGenerationErrors' dflags source action = . (("Error during " ++ T.unpack source) ++) . show @SomeException ] --- | Initialise the finder cache, dependencies should be topologically --- sorted. -setupFinderCache :: [ModSummary] -> HscEnv -> IO HscEnv -setupFinderCache mss session = do - - -- Make modules available for others that import them, - -- by putting them in the finder cache. - let ims = map (installedModule (homeUnitId_ $ hsc_dflags session) . moduleName . ms_mod) mss - ifrs = zipWith (\ms -> InstalledFound (ms_location ms)) mss ims - -- set the target and module graph in the session - graph = mkModuleGraph mss - - -- We have to create a new IORef here instead of modifying the existing IORef as - -- it is shared between concurrent compilations. - prevFinderCache <- readIORef $ hsc_FC session - let newFinderCache = - foldl' - (\fc (im, ifr) -> GHC.extendInstalledModuleEnv fc im ifr) prevFinderCache - $ zip ims ifrs - newFinderCacheVar <- newIORef $! newFinderCache - - pure $ session { hsc_FC = newFinderCacheVar, hsc_mod_graph = graph } - - -- | Load modules, quickly. Input doesn't need to be desugared. -- A module must be loaded before dependent modules can be typechecked. -- This variant of loadModuleHome will *never* cause recompilation, it just @@ -701,12 +694,18 @@ loadModulesHome mod_infos e = mergeEnvs :: HscEnv -> [ModSummary] -> [HomeModInfo] -> [HscEnv] -> IO HscEnv mergeEnvs env extraModSummaries extraMods envs = do prevFinderCache <- concatFC <$> mapM (readIORef . hsc_FC) envs - let ims = map (Compat.installedModule (homeUnitId_ $ hsc_dflags env) . moduleName . ms_mod) extraModSummaries + let ims = map (\ms -> Compat.installedModule (toUnitId $ moduleUnit $ ms_mod ms) (moduleName (ms_mod ms))) extraModSummaries ifrs = zipWith (\ms -> InstalledFound (ms_location ms)) extraModSummaries ims -- Very important to force this as otherwise the hsc_mod_graph field is not -- forced and ends up retaining a reference to all the old hsc_envs we have merged to get -- this new one, which in turn leads to the EPS referencing the HPT. module_graph_nodes = +#if MIN_VERSION_ghc(9,2,0) + -- We don't do any instantiation for backpack at this point of time, so it is OK to use + -- 'extendModSummaryNoDeps'. + -- This may have to change in the future. + map extendModSummaryNoDeps $ +#endif extraModSummaries ++ nubOrdOn ms_mod (concatMap (mgModSummaries . hsc_mod_graph) envs) newFinderCache <- newIORef $ @@ -765,8 +764,9 @@ getModSummaryFromImports env fp modTime contents = do implicit_prelude = xopt LangExt.ImplicitPrelude dflags implicit_imports = mkPrelImports mod main_loc implicit_prelude imps + convImport (L _ i) = (fmap sl_fs (ideclPkgQual i) - , ideclName i) + , reLoc $ ideclName i) srcImports = map convImport src_idecls textualImports = map convImport (implicit_imports ++ ordinary_imps) @@ -836,15 +836,11 @@ parseHeader parseHeader dflags filename contents = do let loc = mkRealSrcLoc (Util.mkFastString filename) 1 1 case unP Compat.parseHeader (initParserState (initParserOpts dflags) contents loc) of -#if MIN_VERSION_ghc(8,10,0) - PFailed pst -> - throwE $ diagFromErrMsgs "parser" dflags $ getErrorMessages pst dflags -#else - PFailed _ locErr msgErr -> - throwE $ diagFromErrMsg "parser" dflags $ mkPlainErrMsg dflags locErr msgErr -#endif + PFailedWithErrorMessages msgs -> + throwE $ diagFromErrMsgs "parser" dflags $ msgs dflags POk pst rdr_module -> do - let (warns, errs) = getMessages pst dflags + let (warns, errs) = getMessages' pst dflags + -- 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 @@ -855,9 +851,9 @@ parseHeader dflags filename contents = do -- errors are those from which a parse tree just can't -- be produced. unless (null errs) $ - throwE $ diagFromErrMsgs "parser" dflags (fmap pprError errs) + throwE $ diagFromErrMsgs "parser" dflags errs - let warnings = diagFromErrMsgs "parser" dflags (fmap pprWarning warns) + let warnings = diagFromErrMsgs "parser" dflags warns return (warnings, rdr_module) -- | Given a buffer, flags, and file path, produce a @@ -874,16 +870,11 @@ parseFileContents env customPreprocessor filename ms = do dflags = ms_hspp_opts ms contents = fromJust $ ms_hspp_buf ms case unP Compat.parseModule (initParserState (initParserOpts dflags) contents loc) of -#if MIN_VERSION_ghc(8,10,0) - PFailed pst -> throwE $ diagFromErrMsgs "parser" dflags $ getErrorMessages pst dflags -#else - PFailed _ locErr msgErr -> - throwE $ diagFromErrMsg "parser" dflags $ mkPlainErrMsg dflags locErr msgErr -#endif + PFailedWithErrorMessages msgs -> throwE $ diagFromErrMsgs "parser" dflags $ msgs dflags POk pst rdr_module -> let hpm_annotations = mkApiAnns pst - (warns, errs) = getMessages pst dflags + (warns, errs) = getMessages' pst dflags in do -- Just because we got a `POk`, it doesn't mean there @@ -933,7 +924,7 @@ parseFileContents env customPreprocessor filename ms = do -- filter them out: srcs2 <- liftIO $ filterM doesFileExist srcs1 - let pm = mkParsedModule ms parsed' srcs2 hpm_annotations + let pm = ParsedModule ms parsed' srcs2 hpm_annotations warnings = diagFromErrMsgs "parser" dflags warns pure (warnings ++ preproc_warnings, pm) @@ -1010,9 +1001,9 @@ getDocsBatch :: HscEnv -> Module -- ^ a moudle where the names are in scope -> [Name] - -> IO [Either String (Maybe HsDocString, Map.Map Int HsDocString)] + -> IO [Either String (Maybe HsDocString, IntMap HsDocString)] getDocsBatch hsc_env _mod _names = do - ((_warns,errs), res) <- initTc hsc_env HsSrcFile False _mod fakeSpan $ forM _names $ \name -> + (msgs, res) <- initTc hsc_env HsSrcFile False _mod fakeSpan $ forM _names $ \name -> case nameModule_maybe name of Nothing -> return (Left $ NameHasNoModule name) Just mod -> do @@ -1020,13 +1011,21 @@ getDocsBatch hsc_env _mod _names = do , mi_decl_docs = DeclDocMap dmap , mi_arg_docs = ArgDocMap amap } <- loadModuleInterface "getModuleInterface" mod - if isNothing mb_doc_hdr && Map.null dmap && Map.null amap + if isNothing mb_doc_hdr && Map.null dmap && null amap then pure (Left (NoDocsInIface mod $ compiled name)) - else pure (Right ( Map.lookup name dmap - , Map.findWithDefault Map.empty name amap)) + else pure (Right ( Map.lookup name dmap , +#if !MIN_VERSION_ghc(9,2,0) + IntMap.fromAscList $ Map.toAscList $ +#endif + Map.findWithDefault mempty name amap)) case res of Just x -> return $ map (first $ T.unpack . showGhc) x - Nothing -> throwErrors errs + Nothing -> throwErrors +#if MIN_VERSION_ghc(9,2,0) + $ Error.getErrorMessages msgs +#else + $ snd msgs +#endif where throwErrors = liftIO . throwIO . mkSrcErr compiled n = diff --git a/ghcide/src/Development/IDE/Core/Rules.hs b/ghcide/src/Development/IDE/Core/Rules.hs index 5ce7017713..8c601917a2 100644 --- a/ghcide/src/Development/IDE/Core/Rules.hs +++ b/ghcide/src/Development/IDE/Core/Rules.hs @@ -106,8 +106,7 @@ import Development.IDE.Core.PositionMapping import Development.IDE.Core.RuleTypes import Development.IDE.Core.Service import Development.IDE.Core.Shake -import Development.IDE.GHC.Compat.Env -import Development.IDE.GHC.Compat.Core hiding +import Development.IDE.GHC.Compat hiding (parseModule, TargetId(..), loadInterface, @@ -520,7 +519,7 @@ getHieAstsRule :: Rules () getHieAstsRule = define $ \GetHieAst f -> do tmr <- use_ TypeCheck f - hsc <- hscEnv <$> use_ GhcSession f + hsc <- hscEnv <$> use_ GhcSessionDeps f getHieAstRuleDefinition f hsc tmr persistentHieFileRule :: Rules () diff --git a/ghcide/src/Development/IDE/Core/Shake.hs b/ghcide/src/Development/IDE/Core/Shake.hs index 1d807beeb1..da727cadd2 100644 --- a/ghcide/src/Development/IDE/Core/Shake.hs +++ b/ghcide/src/Development/IDE/Core/Shake.hs @@ -713,7 +713,6 @@ newSession extras@ShakeExtras{..} shakeDb acts reason = do ++ " (took " ++ showDuration runTime ++ ")" liftIO $ do logPriority logger (actionPriority d) msg - notifyTestingLogMessage extras msg -- The inferred type signature doesn't work in ghc >= 9.0.1 workRun :: (forall b. IO b -> IO b) -> IO (IO ()) diff --git a/ghcide/src/Development/IDE/GHC/Compat.hs b/ghcide/src/Development/IDE/GHC/Compat.hs index 79840ba37f..4b52ee1868 100644 --- a/ghcide/src/Development/IDE/GHC/Compat.hs +++ b/ghcide/src/Development/IDE/GHC/Compat.hs @@ -4,6 +4,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE PatternSynonyms #-} {-# OPTIONS -Wno-incomplete-uni-patterns -Wno-dodgy-imports #-} -- | Attempt at hiding the GHC version differences we can. @@ -15,11 +16,20 @@ module Development.IDE.GHC.Compat( setUpTypedHoles, upNameCache, disableWarningsAsErrors, + reLoc, + reLocA, + getMessages', + pattern PFailedWithErrorMessages, #if !MIN_VERSION_ghc(9,0,1) RefMap, #endif +#if MIN_VERSION_ghc(9,2,0) + extendModSummaryNoDeps, + emsModSummary, +#endif + nodeInfo', getNodeIds, @@ -43,6 +53,7 @@ module Development.IDE.GHC.Compat( -- * Compat modules module Development.IDE.GHC.Compat.Core, module Development.IDE.GHC.Compat.Env, + module Development.IDE.GHC.Compat.ExactPrint, module Development.IDE.GHC.Compat.Iface, module Development.IDE.GHC.Compat.Logger, module Development.IDE.GHC.Compat.Outputable, @@ -60,6 +71,7 @@ import GHC hiding (HasSrcSpan, ModLocation, getLoc, lookupName, RealSrcSpan) import Development.IDE.GHC.Compat.Core import Development.IDE.GHC.Compat.Env +import Development.IDE.GHC.Compat.ExactPrint import Development.IDE.GHC.Compat.Iface import Development.IDE.GHC.Compat.Logger import Development.IDE.GHC.Compat.Outputable @@ -71,7 +83,10 @@ import Development.IDE.GHC.Compat.Util #if MIN_VERSION_ghc(9,0,0) import GHC.Data.StringBuffer import GHC.Driver.Session hiding (ExposePackage) +import GHC.Utils.Error #if MIN_VERSION_ghc(9,2,0) +import Data.Bifunctor +import GHC.Unit.Module.ModSummary import GHC.Driver.Env as Env import GHC.Unit.Module.ModIface #else @@ -115,6 +130,18 @@ import Data.List (foldl') import qualified Data.Set as S #endif +#if !MIN_VERSION_ghc(8,10,0) +import Bag (unitBag) +#endif + +#if !MIN_VERSION_ghc(9,2,0) +reLoc :: Located a -> Located a +reLoc = id + +reLocA :: Located a -> Located a +reLocA = id +#endif + #if !MIN_VERSION_ghc(8,8,0) hPutStringBuffer :: Handle -> StringBuffer -> IO () hPutStringBuffer hdl (StringBuffer buf len cur) @@ -122,12 +149,45 @@ hPutStringBuffer hdl (StringBuffer buf len cur) hPutBuf hdl ptr len #endif +#if MIN_VERSION_ghc(9,2,0) +type ErrMsg = MsgEnvelope DecoratedSDoc +#endif + +getMessages' :: PState -> DynFlags -> (Bag WarnMsg, Bag ErrMsg) +getMessages' pst dflags = +#if MIN_VERSION_ghc(9,2,0) + bimap (fmap pprWarning) (fmap pprError) $ +#endif + getMessages pst +#if !MIN_VERSION_ghc(9,2,0) + dflags +#endif + +#if MIN_VERSION_ghc(9,2,0) +pattern PFailedWithErrorMessages :: forall a b. (b -> Bag (MsgEnvelope DecoratedSDoc)) -> ParseResult a +pattern PFailedWithErrorMessages msgs + <- PFailed (const . fmap pprError . getErrorMessages -> msgs) +#elif MIN_VERSION_ghc(8,10,0) +pattern PFailedWithErrorMessages :: (DynFlags -> ErrorMessages) -> ParseResult a +pattern PFailedWithErrorMessages msgs + <- PFailed (getErrorMessages -> msgs) +#else +pattern PFailedWithErrorMessages :: (DynFlags -> ErrorMessages) -> ParseResult a +pattern PFailedWithErrorMessages msgs + <- ((fmap.fmap) unitBag . mkPlainErrMsgIfPFailed -> Just msgs) + +mkPlainErrMsgIfPFailed (PFailed _ pst err) = Just (\dflags -> mkPlainErrMsg dflags pst err) +mkPlainErrMsgIfPFailed _ = Nothing +#endif +{-# COMPLETE PFailedWithErrorMessages #-} + supportsHieFiles :: Bool supportsHieFiles = True hieExportNames :: HieFile -> [(SrcSpan, Name)] hieExportNames = nameListFromAvails . hie_exports + upNameCache :: IORef NameCache -> (NameCache -> (NameCache, c)) -> IO c #if MIN_VERSION_ghc(8,8,0) upNameCache = updNameCache diff --git a/ghcide/src/Development/IDE/GHC/Compat/Core.hs b/ghcide/src/Development/IDE/GHC/Compat/Core.hs index 634b530c8b..f64984d0cf 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Core.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Core.hs @@ -34,6 +34,7 @@ module Development.IDE.GHC.Compat.Core ( refLevelHoleFits, maxRefHoleFits, maxValidHoleFits, + setOutputFile, #if MIN_VERSION_ghc(8,8,0) CommandLineOption, #if !MIN_VERSION_ghc(9,2,0) @@ -107,6 +108,11 @@ module Development.IDE.GHC.Compat.Core ( CgGuts(..), -- * ModDetails ModDetails(..), + -- * HsExpr, +#if !MIN_VERSION_ghc(9,2,0) + pattern HsLet, + pattern LetStmt, +#endif -- * Var Type ( TyCoRep.TyVarTy, @@ -121,7 +127,9 @@ module Development.IDE.GHC.Compat.Core ( TyCoRep.CoercionTy ), pattern FunTy, +#if !MIN_VERSION_ghc(9,2,0) Development.IDE.GHC.Compat.Core.splitForAllTyCoVars, +#endif Development.IDE.GHC.Compat.Core.mkVisFunTys, Development.IDE.GHC.Compat.Core.mkInfForAllTys, -- * Specs @@ -147,8 +155,7 @@ module Development.IDE.GHC.Compat.Core ( -- * TcGblEnv TcGblEnv(..), -- * Parsing and LExer types - HsParsedModule(..), - GHC.ParsedModule(..), + HsModule(..), GHC.ParsedSource, GHC.RenamedSource, -- * Compilation Main @@ -184,6 +191,16 @@ module Development.IDE.GHC.Compat.Core ( SrcLoc.Located, SrcLoc.unLoc, getLoc, + getLocA, + locA, + LocatedAn, +#if MIN_VERSION_ghc(9,2,0) + GHC.AnnListItem(..), + GHC.NameAnn(..), +#else + AnnListItem, + NameAnn, +#endif SrcLoc.RealLocated, SrcLoc.GenLocated(..), SrcLoc.SrcSpan(SrcLoc.UnhelpfulSpan), @@ -193,6 +210,10 @@ module Development.IDE.GHC.Compat.Core ( pattern RealSrcLoc, SrcLoc.SrcLoc(SrcLoc.UnhelpfulLoc), BufSpan, +#if MIN_VERSION_ghc(9,2,0) + SrcSpanAnn', + GHC.SrcAnn, +#endif SrcLoc.leftmost_smallest, SrcLoc.containsSpan, SrcLoc.mkGeneralSrcSpan, @@ -202,6 +223,7 @@ module Development.IDE.GHC.Compat.Core ( SrcLoc.realSrcLocSpan, SrcLoc.realSrcSpanStart, SrcLoc.realSrcSpanEnd, + isSubspanOfA, SrcLoc.isSubspanOf, SrcLoc.wiredInSrcSpan, SrcLoc.mkSrcSpan, @@ -275,6 +297,17 @@ module Development.IDE.GHC.Compat.Core ( -- * Panic PlainGhcException, panic, + -- * Other + GHC.CoreModule(..), + GHC.SafeHaskellMode(..), + pattern GRE, + gre_name, + gre_imp, + gre_lcl, + gre_par, +#if MIN_VERSION_ghc(9,2,0) + collectHsBindsBinders, +#endif -- * Util Module re-exports #if MIN_VERSION_ghc(9,0,0) module GHC.Builtin.Names, @@ -307,7 +340,15 @@ module Development.IDE.GHC.Compat.Core ( module GHC.Iface.Syntax, #if MIN_VERSION_ghc(9,2,0) - module Language.Haskell.Syntax.Expr, + module GHC.Hs.Decls, + module GHC.Hs.Expr, + module GHC.Hs.Doc, + module GHC.Hs.Extension, + module GHC.Hs.ImpExp, + module GHC.Hs.Pat, + module GHC.Hs.Type, + module GHC.Hs.Utils, + module Language.Haskell.Syntax, #endif module GHC.Rename.Names, @@ -329,6 +370,7 @@ module Development.IDE.GHC.Compat.Core ( module GHC.Types.Name.Env, module GHC.Types.Name.Reader, #if MIN_VERSION_ghc(9,2,0) + module GHC.Types.Avail, module GHC.Types.SourceFile, module GHC.Types.SourceText, module GHC.Types.TyThing, @@ -417,33 +459,36 @@ module Development.IDE.GHC.Compat.Core ( import qualified GHC #if MIN_VERSION_ghc(9,0,0) -import GHC.Builtin.Names hiding (Unique, printName) +import GHC.Builtin.Names hiding (Unique, printName) import GHC.Builtin.Types import GHC.Builtin.Types.Prim import GHC.Builtin.Utils import GHC.Core.Class import GHC.Core.Coercion import GHC.Core.ConLike -import GHC.Core.DataCon hiding (dataConExTyCoVars) -import qualified GHC.Core.DataCon as DataCon -import GHC.Core.FamInstEnv +import GHC.Core.DataCon hiding (dataConExTyCoVars) +import qualified GHC.Core.DataCon as DataCon +import GHC.Core.FamInstEnv hiding (pprFamInst) import GHC.Core.InstEnv import GHC.Types.Unique.FM #if MIN_VERSION_ghc(9,2,0) -import GHC.Core.Multiplicity (scaledThing) +import GHC.Data.Bag +import GHC.Core.Multiplicity (scaledThing) #else -import GHC.Core.Ppr.TyThing hiding (pprFamInst) -import GHC.Core.TyCo.Rep (scaledThing) +import GHC.Core.Ppr.TyThing hiding (pprFamInst) +import GHC.Core.TyCo.Rep (scaledThing) #endif import GHC.Core.PatSyn import GHC.Core.Predicate import GHC.Core.TyCo.Ppr -import qualified GHC.Core.TyCo.Rep as TyCoRep +import qualified GHC.Core.TyCo.Rep as TyCoRep import GHC.Core.TyCon -import GHC.Core.Type hiding (mkInfForAllTys, mkVisFunTys) +import GHC.Core.Type hiding (mkInfForAllTys, + mkVisFunTys) import GHC.Core.Unify import GHC.Core.Utils + #if MIN_VERSION_ghc(9,2,0) import GHC.Driver.Env #else @@ -451,122 +496,146 @@ import GHC.Driver.Finder import GHC.Driver.Types import GHC.Driver.Ways #endif -import GHC.Driver.CmdLine (Warn (..)) +import GHC.Driver.CmdLine (Warn (..)) import GHC.Driver.Hooks import GHC.Driver.Main import GHC.Driver.Monad import GHC.Driver.Phases import GHC.Driver.Pipeline import GHC.Driver.Plugins -import GHC.Driver.Session hiding (ExposePackage) -import qualified GHC.Driver.Session as DynFlags +import GHC.Driver.Session hiding (ExposePackage) +import qualified GHC.Driver.Session as DynFlags +#if MIN_VERSION_ghc(9,2,0) +import GHC.Hs (HsModule (..), SrcSpanAnn') +import GHC.Hs.Decls hiding (FunDep) +import GHC.Hs.Doc +import GHC.Hs.Expr +import GHC.Hs.Extension +import GHC.Hs.ImpExp +import GHC.Hs.Pat +import GHC.Hs.Type +import GHC.Hs.Utils hiding (collectHsBindsBinders) +import qualified GHC.Hs.Utils as GHC +#endif #if !MIN_VERSION_ghc(9,2,0) -import GHC.Hs +import GHC.Hs hiding (HsLet, LetStmt) #endif import GHC.HsToCore.Docs import GHC.HsToCore.Expr import GHC.HsToCore.Monad import GHC.Iface.Load -import GHC.Iface.Make (mkFullIface, mkIfaceTc, - mkPartialIface) +import GHC.Iface.Make (mkFullIface, mkIfaceTc, + mkPartialIface) import GHC.Iface.Recomp import GHC.Iface.Syntax import GHC.Iface.Tidy import GHC.IfaceToCore import GHC.Parser -import GHC.Parser.Header hiding (getImports) -import GHC.Parser.Lexer +import GHC.Parser.Header hiding (getImports) #if MIN_VERSION_ghc(9,2,0) -import GHC.Linker.Loader +import qualified GHC.Linker.Loader as Linker import GHC.Linker.Types +import GHC.Parser.Lexer hiding (initParserState) import GHC.Platform.Ways +import GHC.Runtime.Context (InteractiveImport (..)) #else -import GHC.Runtime.Linker +import GHC.Parser.Lexer +import qualified GHC.Runtime.Linker as Linker #endif import GHC.Rename.Names import GHC.Rename.Splice -import GHC.Runtime.Interpreter +import qualified GHC.Runtime.Interpreter as GHCi import GHC.Tc.Instance.Family import GHC.Tc.Module import GHC.Tc.Types -import GHC.Tc.Types.Evidence hiding ((<.>)) +import GHC.Tc.Types.Evidence hiding ((<.>)) import GHC.Tc.Utils.Env -import GHC.Tc.Utils.Monad hiding (Applicative (..), IORef, - MonadFix (..), MonadIO (..), allM, - anyM, concatMapM, mapMaybeM, (<$>)) -import GHC.Tc.Utils.TcType as TcType -import qualified GHC.Types.Avail as Avail +import GHC.Tc.Utils.Monad hiding (Applicative (..), IORef, + MonadFix (..), MonadIO (..), + allM, anyM, concatMapM, + mapMaybeM, (<$>)) +import GHC.Tc.Utils.TcType as TcType +import qualified GHC.Types.Avail as Avail +#if MIN_VERSION_ghc(9,2,0) +import GHC.Types.Avail (greNamePrintableName) +import GHC.Types.Fixity (LexicalFixity (..)) +#endif #if MIN_VERSION_ghc(9,2,0) import GHC.Types.Meta #endif import GHC.Types.Basic import GHC.Types.Id -import GHC.Types.Name hiding (varName) +import GHC.Types.Name hiding (varName) import GHC.Types.Name.Cache import GHC.Types.Name.Env -import GHC.Types.Name.Reader +import GHC.Types.Name.Reader hiding (GRE, gre_name, gre_imp, gre_lcl, gre_par) +import qualified GHC.Types.Name.Reader as RdrName #if MIN_VERSION_ghc(9,2,0) import GHC.Types.Name.Set -import GHC.Types.SourceFile (HscSource (..), - SourceModified (..)) +import GHC.Types.SourceFile (HscSource (..), + SourceModified (..)) import GHC.Types.SourceText +import GHC.Types.Target (Target (..), TargetId (..)) import GHC.Types.TyThing import GHC.Types.TyThing.Ppr #else import GHC.Types.Name.Set #endif -import GHC.Types.SrcLoc (BufPos, BufSpan, - SrcLoc (UnhelpfulLoc), - SrcSpan (UnhelpfulSpan)) -import qualified GHC.Types.SrcLoc as SrcLoc +import GHC.Types.SrcLoc (BufPos, BufSpan, + SrcLoc (UnhelpfulLoc), + SrcSpan (UnhelpfulSpan)) +import qualified GHC.Types.SrcLoc as SrcLoc import GHC.Types.Unique.Supply -import GHC.Types.Var (Var (varName), setTyVarUnique, - setVarUnique) +import GHC.Types.Var (Var (varName), setTyVarUnique, + setVarUnique) #if MIN_VERSION_ghc(9,2,0) import GHC.Unit.Finder import GHC.Unit.Home.ModInfo #endif -import GHC.Unit.Info (PackageName (..)) -import GHC.Unit.Module hiding (ModLocation (..), UnitId, - addBootSuffixLocnOut, moduleUnit, - toUnitId) -import qualified GHC.Unit.Module as Module +import GHC.Unit.Info (PackageName (..)) +import GHC.Unit.Module hiding (ModLocation (..), UnitId, + addBootSuffixLocnOut, moduleUnit, + toUnitId) +import qualified GHC.Unit.Module as Module #if MIN_VERSION_ghc(9,2,0) +import GHC.Unit.Module.Graph (mkModuleGraph) import GHC.Unit.Module.Imported import GHC.Unit.Module.ModDetails import GHC.Unit.Module.ModGuts -import GHC.Unit.Module.ModIface (IfaceExport) +import GHC.Unit.Module.ModIface (IfaceExport, ModIface (..), + ModIface_ (..)) +import GHC.Unit.Module.ModSummary (ModSummary (..)) #endif -import GHC.Unit.State (ModuleOrigin (..)) -import GHC.Utils.Error (Severity (..)) -import GHC.Utils.Panic hiding (try) -import qualified GHC.Utils.Panic.Plain as Plain +import GHC.Unit.State (ModuleOrigin (..)) +import GHC.Utils.Error (Severity (..)) +import GHC.Utils.Panic hiding (try) +import qualified GHC.Utils.Panic.Plain as Plain #else import qualified Avail -import BasicTypes hiding (Version) +import BasicTypes hiding (Version) import Class -import CmdLineParser (Warn (..)) +import CmdLineParser (Warn (..)) import ConLike import CoreUtils -import DataCon hiding (dataConExTyCoVars) +import DataCon hiding (dataConExTyCoVars) import qualified DataCon import DriverPhases import DriverPipeline import DsExpr -import DsMonad hiding (foldrM) -import DynFlags hiding (ExposePackage) +import DsMonad hiding (foldrM) +import DynFlags hiding (ExposePackage) import qualified DynFlags -import ErrUtils hiding (logInfo, mkWarnMsg) +import ErrUtils hiding (logInfo, mkWarnMsg) import ExtractDocs import FamInst import FamInstEnv import Finder #if MIN_VERSION_ghc(8,10,0) -import GHC.Hs +import GHC.Hs hiding (HsLet, LetStmt) #endif -import GHCi +import qualified GHCi import GhcMonad -import HeaderInfo hiding (getImports) +import HeaderInfo hiding (getImports) import Hooks import HscMain import HscTypes @@ -575,89 +644,97 @@ import HscTypes import HsBinds import HsDecls import HsDoc -import HsExpr +import HsExpr hiding (HsLet, LetStmt) import HsExtension import HsImpExp import HsLit import HsPat -import HsSyn hiding (wildCardName) -import HsTypes hiding (wildCardName) +import HsSyn hiding (wildCardName, HsLet, LetStmt) +import HsTypes hiding (wildCardName) import HsUtils #endif import Id import IfaceSyn import InstEnv -import Lexer hiding (getSrcLoc) -import Linker +import Lexer hiding (getSrcLoc) +import qualified Linker import LoadIface import MkIface -import Module hiding (ModLocation (..), UnitId, - addBootSuffixLocnOut, moduleUnitId) +import Module hiding (ModLocation (..), UnitId, + addBootSuffixLocnOut, + moduleUnitId) import qualified Module -import Name hiding (varName) +import Name hiding (varName) import NameCache import NameEnv import NameSet import Packages #if MIN_VERSION_ghc(8,8,0) -import Panic hiding (try) -import qualified PlainPanic as Plain +import Panic hiding (try) +import qualified PlainPanic as Plain #else -import Panic hiding (GhcException, try) -import qualified Panic as Plain +import Panic hiding (GhcException, try) +import qualified Panic as Plain #endif import Parser import PatSyn #if MIN_VERSION_ghc(8,8,0) import Plugins #endif -import PprTyThing hiding (pprFamInst) +import PprTyThing hiding (pprFamInst) import PrelInfo -import PrelNames hiding (Unique, printName) -import RdrName +import PrelNames hiding (Unique, printName) +import RdrName hiding (GRE, gre_name, gre_imp, gre_lcl, gre_par) +import qualified RdrName import RnNames import RnSplice import qualified SrcLoc import TcEnv -import TcEvidence hiding ((<.>)) +import TcEvidence hiding ((<.>)) import TcIface import TcRnDriver -import TcRnMonad hiding (Applicative (..), IORef, - MonadFix (..), MonadIO (..), allM, - anyM, concatMapM, foldrM, - mapMaybeM, (<$>)) +import TcRnMonad hiding (Applicative (..), IORef, + MonadFix (..), MonadIO (..), + allM, anyM, concatMapM, foldrM, + mapMaybeM, (<$>)) import TcRnTypes -import TcType hiding (mkVisFunTys) +import TcType hiding (mkVisFunTys) import qualified TcType import TidyPgm import qualified TyCoRep import TyCon -import Type hiding (mkVisFunTys) +import Type hiding (mkVisFunTys) import TysPrim import TysWiredIn import Unify import UniqFM import UniqSupply -import Var (Var (varName), setTyVarUnique, - setVarUnique, varType) +import Var (Var (varName), setTyVarUnique, + setVarUnique, varType) #if MIN_VERSION_ghc(8,10,0) -import Coercion (coercionKind) +import Coercion (coercionKind) import Predicate -import SrcLoc (SrcLoc (UnhelpfulLoc), - SrcSpan (UnhelpfulSpan)) +import SrcLoc (Located, SrcLoc (UnhelpfulLoc), + SrcSpan (UnhelpfulSpan)) #else -import SrcLoc (RealLocated, SrcLoc (UnhelpfulLoc), - SrcSpan (UnhelpfulSpan)) +import SrcLoc (RealLocated, + SrcLoc (UnhelpfulLoc), + SrcSpan (UnhelpfulSpan)) #endif #endif #if !MIN_VERSION_ghc(8,8,0) -import Data.List (isSuffixOf) +import Data.List (isSuffixOf) import System.FilePath #endif + +#if MIN_VERSION_ghc(9,2,0) +import Language.Haskell.Syntax hiding (FunDep) +#endif + #if !MIN_VERSION_ghc(9,0,0) type BufSpan = () type BufPos = () @@ -733,11 +810,22 @@ pattern FunTy arg res <- TyCoRep.FunTy arg res class HasSrcSpan a where getLoc :: a -> SrcSpan +instance HasSrcSpan SrcSpan where + getLoc = id + instance HasSrcSpan (SrcLoc.GenLocated SrcSpan a) where getLoc = GHC.getLoc --- getLoc :: GenLocated l a -> l --- getLoc = GHC.getLoc +#if MIN_VERSION_ghc(9,2,0) +instance HasSrcSpan (SrcSpanAnn' ann) where + getLoc = locA +instance HasSrcSpan (SrcLoc.GenLocated (SrcSpanAnn' ann) a) where + getLoc (L l _) = l + +pattern L :: HasSrcSpan a => SrcSpan -> e -> SrcLoc.GenLocated a e +pattern L l a <- GHC.L (getLoc -> l) a +{-# COMPLETE L #-} +#endif #elif MIN_VERSION_ghc(8,8,0) type HasSrcSpan = SrcLoc.HasSrcSpan @@ -806,11 +894,9 @@ mkInfForAllTys = mkInvForAllTys #endif +#if !MIN_VERSION_ghc(9,2,0) splitForAllTyCoVars :: Type -> ([TyCoVar], Type) splitForAllTyCoVars = -#if MIN_VERSION_ghc(9,2,0) - TcType.splitForAllTyCoVars -#else splitForAllTys #endif @@ -865,3 +951,100 @@ type PlainGhcException = Plain.PlainGhcException #else type PlainGhcException = Plain.GhcException #endif + +initDynLinker, initObjLinker :: HscEnv -> IO () +initDynLinker = +#if !MIN_VERSION_ghc(9,0,0) + Linker.initDynLinker +#else + -- It errors out in GHC 9.0 and doesn't exist in 9.2 + const $ return () +#endif + +initObjLinker env = +#if !MIN_VERSION_ghc(9,2,0) + GHCi.initObjLinker env +#else + GHCi.initObjLinker (GHCi.hscInterp env) +#endif + +loadDLL :: HscEnv -> String -> IO (Maybe String) +loadDLL env = +#if !MIN_VERSION_ghc(9,2,0) + GHCi.loadDLL env +#else + GHCi.loadDLL (GHCi.hscInterp env) +#endif + +unload :: HscEnv -> [Linkable] -> IO () +unload hsc_env linkables = + Linker.unload +#if MIN_VERSION_ghc(9,2,0) + (GHCi.hscInterp hsc_env) +#endif + hsc_env linkables + +setOutputFile :: FilePath -> DynFlags -> DynFlags +setOutputFile f d = d { +#if MIN_VERSION_ghc(9,2,0) + outputFile_ = Just f +#else + outputFile = Just f +#endif + } + +isSubspanOfA :: LocatedAn la a -> LocatedAn lb b -> Bool +#if MIN_VERSION_ghc(9,2,0) +isSubspanOfA a b = SrcLoc.isSubspanOf (GHC.getLocA a) (GHC.getLocA b) +#else +isSubspanOfA a b = SrcLoc.isSubspanOf (GHC.getLoc a) (GHC.getLoc b) +#endif + +#if MIN_VERSION_ghc(9,2,0) +type LocatedAn a = GHC.LocatedAn a +#else +type LocatedAn a = GHC.Located +#endif + +#if MIN_VERSION_ghc(9,2,0) +locA :: SrcSpanAnn' a -> SrcSpan +locA = GHC.locA +#else +locA = id +#endif + +#if MIN_VERSION_ghc(9,2,0) +getLocA :: SrcLoc.GenLocated (SrcSpanAnn' a) e -> SrcSpan +getLocA = GHC.getLocA +#else +-- getLocA :: HasSrcSpan a => a -> SrcSpan +getLocA x = GHC.getLoc x +#endif + +#if !MIN_VERSION_ghc(9,2,0) +type AnnListItem = SrcLoc.SrcSpan +#endif + +#if !MIN_VERSION_ghc(9,2,0) +type NameAnn = SrcLoc.SrcSpan +#endif + +pattern GRE :: Name -> Parent -> Bool -> [ImportSpec] -> RdrName.GlobalRdrElt +{-# COMPLETE GRE #-} +#if MIN_VERSION_ghc(9,2,0) +pattern GRE{gre_name, gre_par, gre_lcl, gre_imp} <- RdrName.GRE + {gre_name = (greNamePrintableName -> gre_name) + ,gre_par, gre_lcl, gre_imp} +#else +pattern GRE{gre_name, gre_par, gre_lcl, gre_imp} = RdrName.GRE{..} +#endif + +#if MIN_VERSION_ghc(9,2,0) +collectHsBindsBinders :: CollectPass p => Bag (XRec p (HsBindLR p idR)) -> [IdP p] +collectHsBindsBinders x = GHC.collectHsBindsBinders CollNoDictBinders x +#endif + +#if !MIN_VERSION_ghc(9,2,0) +pattern HsLet xlet localBinds expr <- GHC.HsLet xlet (SrcLoc.unLoc -> localBinds) expr +pattern LetStmt xlet localBinds <- GHC.LetStmt xlet (SrcLoc.unLoc -> localBinds) +#endif diff --git a/ghcide/src/Development/IDE/GHC/Compat/Env.hs b/ghcide/src/Development/IDE/GHC/Compat/Env.hs index dfce6d1841..7662587898 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Env.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Env.hs @@ -81,8 +81,10 @@ import Module #endif #if MIN_VERSION_ghc(9,0,0) +#if !MIN_VERSION_ghc(9,2,0) import qualified Data.Set as Set #endif +#endif #if !MIN_VERSION_ghc(9,2,0) import Data.IORef #endif @@ -103,12 +105,7 @@ setHomeUnitId_ uid df = df { thisInstalledUnitId = toInstalledUnitId uid } #endif hscSetFlags :: DynFlags -> HscEnv -> HscEnv -hscSetFlags df env = -#if MIN_VERSION_ghc(9,2,0) - hscSetFlags df env -#else - env { Env.hsc_dflags = df } -#endif +hscSetFlags df env = env { Env.hsc_dflags = df } initTempFs :: HscEnv -> IO HscEnv initTempFs env = do diff --git a/ghcide/src/Development/IDE/GHC/Compat/ExactPrint.hs b/ghcide/src/Development/IDE/GHC/Compat/ExactPrint.hs new file mode 100644 index 0000000000..aae6e6f4f8 --- /dev/null +++ b/ghcide/src/Development/IDE/GHC/Compat/ExactPrint.hs @@ -0,0 +1,28 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleInstances #-} + +-- | This module contains compatibility constructs to write type signatures across +-- multiple ghc-exactprint versions, accepting that anything more ambitious is +-- pretty much impossible with the GHC 9.2 redesign of ghc-exactprint +module Development.IDE.GHC.Compat.ExactPrint + ( ExactPrint + , exactPrint + , makeDeltaAst +#if !MIN_VERSION_ghc(9,2,0) + , Annotated(..) +#endif + ) where + +import Language.Haskell.GHC.ExactPrint +#if !MIN_VERSION_ghc(9,2,0) +import Retrie.ExactPrint (Annotated (..)) +#endif + +#if !MIN_VERSION_ghc(9,2,0) +class ExactPrint ast where + makeDeltaAst :: ast -> ast + makeDeltaAst = id + +instance ExactPrint ast +#endif + diff --git a/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs b/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs index e3b6d2a453..e3a4ecabe2 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Outputable.hs @@ -31,17 +31,18 @@ module Development.IDE.GHC.Compat.Outputable ( #if MIN_VERSION_ghc(9,2,0) +import GHC.Driver.Env import GHC.Driver.Ppr import GHC.Driver.Session import GHC.Parser.Errors import qualified GHC.Parser.Errors.Ppr as Ppr import qualified GHC.Types.Error as Error import GHC.Types.Name.Ppr +import GHC.Types.Name.Reader import GHC.Types.SourceError import GHC.Types.SrcLoc import GHC.Unit.State import GHC.Utils.Error hiding (mkWarnMsg) -import GHC.Utils.Logger import GHC.Utils.Outputable import GHC.Utils.Panic #elif MIN_VERSION_ghc(9,0,0) @@ -136,7 +137,15 @@ pprError = formatErrorWithQual :: DynFlags -> MsgEnvelope DecoratedSDoc -> String formatErrorWithQual dflags e = #if MIN_VERSION_ghc(9,2,0) - showSDoc dflags (pprLocMsgEnvelope e) + showSDoc dflags (pprNoLocMsgEnvelope e) + +pprNoLocMsgEnvelope :: Error.RenderableDiagnostic e => MsgEnvelope e -> SDoc +pprNoLocMsgEnvelope (MsgEnvelope { errMsgDiagnostic = e + , errMsgContext = unqual }) + = sdocWithContext $ \ctx -> + withErrStyle unqual $ + (formatBulleted ctx $ Error.renderDiagnostic e) + #else Out.showSDoc dflags $ Out.withPprStyle (oldMkErrStyle dflags $ errMsgContext e) @@ -152,9 +161,15 @@ type PsWarning = ErrMsg type PsError = ErrMsg #endif -mkPrintUnqualifiedDefault :: GlobalRdrEnv -> PrintUnqualified -mkPrintUnqualifiedDefault = - HscTypes.mkPrintUnqualified unsafeGlobalDynFlags +mkPrintUnqualifiedDefault :: HscEnv -> GlobalRdrEnv -> PrintUnqualified +mkPrintUnqualifiedDefault env = +#if MIN_VERSION_ghc(9,2,0) + -- GHC 9.2.1 version + -- mkPrintUnqualified :: UnitEnv -> GlobalRdrEnv -> PrintUnqualified + mkPrintUnqualified (hsc_unit_env env) +#else + HscTypes.mkPrintUnqualified (hsc_dflags env) +#endif mkWarnMsg :: DynFlags -> SrcSpan -> PrintUnqualified -> SDoc -> MsgEnvelope DecoratedSDoc mkWarnMsg = diff --git a/ghcide/src/Development/IDE/GHC/Compat/Parser.hs b/ghcide/src/Development/IDE/GHC/Compat/Parser.hs index 0a2375cd99..976f09ded1 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Parser.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Parser.hs @@ -1,4 +1,6 @@ -{-# LANGUAGE CPP #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE PatternSynonyms #-} +{-# HLINT ignore "Unused LANGUAGE pragma" #-} -- | Parser compaibility module. module Development.IDE.GHC.Compat.Parser ( @@ -17,25 +19,49 @@ module Development.IDE.GHC.Compat.Parser ( #if MIN_VERSION_ghc(9,0,0) PsSpan(..), #endif - mkHsParsedModule, - mkParsedModule, +#if MIN_VERSION_ghc(9,2,0) + pattern HsParsedModule, + type GHC.HsParsedModule, + Development.IDE.GHC.Compat.Parser.hpm_module, + Development.IDE.GHC.Compat.Parser.hpm_src_files, + Development.IDE.GHC.Compat.Parser.hpm_annotations, + pattern ParsedModule, + Development.IDE.GHC.Compat.Parser.pm_parsed_source, + type GHC.ParsedModule, + Development.IDE.GHC.Compat.Parser.pm_mod_summary, + Development.IDE.GHC.Compat.Parser.pm_extra_src_files, + Development.IDE.GHC.Compat.Parser.pm_annotations, +#else + GHC.HsParsedModule(..), + GHC.ParsedModule(..), +#endif mkApiAnns, -- * API Annotations Anno.AnnKeywordId(..), +#if !MIN_VERSION_ghc(9,2,0) Anno.AnnotationComment(..), +#endif ) where #if MIN_VERSION_ghc(9,0,0) +#if !MIN_VERSION_ghc(9,2,0) +import qualified GHC.Driver.Types as GHC +#endif +import qualified GHC.Parser.Annotation as Anno import qualified GHC.Parser.Lexer as Lexer import GHC.Types.SrcLoc (PsSpan (..)) #if MIN_VERSION_ghc(9,2,0) +import GHC (pm_extra_src_files, + pm_mod_summary, + pm_parsed_source) +import qualified GHC import qualified GHC.Driver.Config as Config +import GHC.Hs (hpm_module, hpm_src_files) import GHC.Parser.Lexer hiding (initParserState) -#else -import qualified GHC.Parser.Annotation as Anno #endif #else import qualified ApiAnnotation as Anno +import qualified HscTypes as GHC import Lexer import qualified SrcLoc #endif @@ -44,6 +70,7 @@ import Development.IDE.GHC.Compat.Util #if !MIN_VERSION_ghc(9,2,0) import qualified Data.Map as Map +import qualified GHC #endif #if !MIN_VERSION_ghc(9,0,0) @@ -78,27 +105,36 @@ type ApiAnns = () type ApiAnns = Anno.ApiAnns #endif - -mkHsParsedModule :: ParsedSource -> [FilePath] -> ApiAnns -> HsParsedModule -mkHsParsedModule parsed fps hpm_annotations = - HsParsedModule - parsed - fps -#if !MIN_VERSION_ghc(9,2,0) - hpm_annotations +#if MIN_VERSION_ghc(9,2,0) +pattern HsParsedModule :: Located HsModule -> [FilePath] -> ApiAnns -> GHC.HsParsedModule +pattern HsParsedModule + { hpm_module + , hpm_src_files + , hpm_annotations + } <- ( (,()) -> (GHC.HsParsedModule{..}, hpm_annotations)) + where + HsParsedModule hpm_module hpm_src_files hpm_annotations = + GHC.HsParsedModule hpm_module hpm_src_files #endif -mkParsedModule :: ModSummary -> ParsedSource -> [FilePath] -> ApiAnns -> ParsedModule -mkParsedModule ms parsed extra_src_files _hpm_annotations = - ParsedModule { - pm_mod_summary = ms - , pm_parsed_source = parsed - , pm_extra_src_files = extra_src_files -#if !MIN_VERSION_ghc(9,2,0) - , pm_annotations = _hpm_annotations +#if MIN_VERSION_ghc(9,2,0) +pattern ParsedModule :: ModSummary -> ParsedSource -> [FilePath] -> ApiAnns -> GHC.ParsedModule +pattern ParsedModule + { pm_mod_summary + , pm_parsed_source + , pm_extra_src_files + , pm_annotations + } <- ( (,()) -> (GHC.ParsedModule{..}, pm_annotations)) + where + ParsedModule ms parsed extra_src_files _anns = + GHC.ParsedModule + { pm_mod_summary = ms + , pm_parsed_source = parsed + , pm_extra_src_files = extra_src_files + } +{-# COMPLETE ParsedModule :: GHC.ParsedModule #-} #endif - } mkApiAnns :: PState -> ApiAnns #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 6621b70e9c..6fd5834f63 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Plugins.hs @@ -17,7 +17,6 @@ module Development.IDE.GHC.Compat.Plugins ( #endif ) where -import GHC #if MIN_VERSION_ghc(9,0,0) #if MIN_VERSION_ghc(9,2,0) import qualified GHC.Driver.Env as Env @@ -51,7 +50,7 @@ applyPluginsParsedResultAction env dflags ms hpm_annotations parsed = do dflags #endif applyPluginAction - (mkHsParsedModule parsed [] hpm_annotations) + (HsParsedModule parsed [] hpm_annotations) initializePlugins :: HscEnv -> IO HscEnv initializePlugins env = do diff --git a/ghcide/src/Development/IDE/GHC/Compat/Units.hs b/ghcide/src/Development/IDE/GHC/Compat/Units.hs index 61f8d82644..9077745aef 100644 --- a/ghcide/src/Development/IDE/GHC/Compat/Units.hs +++ b/ghcide/src/Development/IDE/GHC/Compat/Units.hs @@ -46,12 +46,14 @@ module Development.IDE.GHC.Compat.Units ( -- * Utils filterInplaceUnits, FinderCache, + showSDocForUser', ) where #if MIN_VERSION_ghc(9,0,0) #if MIN_VERSION_ghc(9,2,0) import qualified GHC.Data.ShortText as ST import GHC.Driver.Env (hsc_unit_dbs) +import GHC.Driver.Ppr import GHC.Unit.Env import GHC.Unit.External import GHC.Unit.Finder @@ -67,9 +69,11 @@ import GHC.Unit.State (LookupResult, UnitInfo, import qualified GHC.Unit.State as State import GHC.Unit.Types hiding (moduleUnit, toUnitId) import qualified GHC.Unit.Types as Unit +import GHC.Utils.Outputable #else import qualified DynFlags import FastString +import GhcPlugins (SDoc, showSDocForUser) import HscTypes import Module hiding (moduleUnitId) import qualified Module @@ -89,6 +93,7 @@ import Data.Map (Map) #endif import Data.Either import Data.Version +import qualified GHC #if MIN_VERSION_ghc(9,0,0) type PreloadUnitClosure = UniqSet UnitId @@ -131,12 +136,12 @@ initUnits env = do let cached_unit_dbs = hsc_unit_dbs env (dbs,unit_state,home_unit,mconstants) <- State.initUnits (hsc_logger env) dflags1 cached_unit_dbs - dflags <- updatePlatformConstants dflags1 mconstants + dflags <- DynFlags.updatePlatformConstants dflags1 mconstants let unit_env = UnitEnv { ue_platform = targetPlatform dflags - , ue_namever = ghcNameVersion dflags + , ue_namever = DynFlags.ghcNameVersion dflags , ue_home_unit = home_unit , ue_units = unit_state } @@ -274,8 +279,11 @@ unitHaddockInterfaces = -- ------------------------------------------------------------------ #if MIN_VERSION_ghc(9,2,0) +definiteUnitId :: Definite uid -> GenUnit uid definiteUnitId = RealUnit +defUnitId :: unit -> Definite unit defUnitId = Definite +installedModule :: unit -> ModuleName -> GenModule unit installedModule = Module #elif MIN_VERSION_ghc(9,0,0) @@ -340,3 +348,10 @@ filterInplaceUnits us packageFlags = else Right p #endif isInplace p = Right p + +showSDocForUser' :: HscEnv -> GHC.PrintUnqualified -> SDoc -> String +#if MIN_VERSION_ghc(9,2,0) +showSDocForUser' env = showSDocForUser (hsc_dflags env) (unitState env) +#else +showSDocForUser' env = showSDocForUser (hsc_dflags env) +#endif diff --git a/ghcide/src/Development/IDE/GHC/Dump.hs b/ghcide/src/Development/IDE/GHC/Dump.hs new file mode 100644 index 0000000000..40bd97b54c --- /dev/null +++ b/ghcide/src/Development/IDE/GHC/Dump.hs @@ -0,0 +1,337 @@ +{-# LANGUAGE CPP #-} +module Development.IDE.GHC.Dump(showAstDataHtml) where +import Data.Data hiding (Fixity) +import Development.IDE.GHC.Compat hiding (NameAnn) +#if MIN_VERSION_ghc(8,10,1) +import GHC.Hs.Dump +#else +import HsDumpAst +#endif +#if MIN_VERSION_ghc(9,2,1) +import qualified Data.ByteString as B +import Development.IDE.GHC.Compat.Util +import GHC.Hs +import Generics.SYB (ext1Q, ext2Q, extQ) +#endif +#if MIN_VERSION_ghc(9,0,1) +import GHC.Plugins +#else +import GhcPlugins +#endif +import Prelude hiding ((<>)) + +-- | Show a GHC syntax tree in HTML. +#if MIN_VERSION_ghc(9,2,1) +showAstDataHtml :: (Data a, ExactPrint a, Outputable a) => a -> SDoc +#else +showAstDataHtml :: (Data a, Outputable a) => a -> SDoc +#endif +showAstDataHtml a0 = html $ + header $$ + body (tag' [("id",text (show @String "myUL"))] "ul" $ vcat + [ +#if MIN_VERSION_ghc(9,2,1) + li (pre $ text (exactPrint a0)), + li (showAstDataHtml' a0), + li (nested "Raw" $ pre $ showAstData NoBlankSrcSpan NoBlankEpAnnotations a0) +#else + li (nested "Raw" $ pre $ showAstData NoBlankSrcSpan a0) +#endif + ]) + where + tag = tag' [] + tag' attrs t cont = + angleBrackets (text t <+> hcat [text a<>char '=' <>v | (a,v) <- attrs]) + <> cont + <> angleBrackets (char '/' <> text t) + ul = tag' [("class", text (show @String "nested"))] "ul" + li = tag "li" + caret x = tag' [("class", text "caret")] "span" "" <+> x + nested foo cts +#if MIN_VERSION_ghc(9,2,1) + | cts == empty = foo +#endif + | otherwise = foo $$ (caret $ ul cts) + body cts = tag "body" $ cts $$ tag "script" (text js) + header = tag "head" $ tag "style" $ text css + html = tag "html" + pre = tag "pre" +#if MIN_VERSION_ghc(9,2,1) + showAstDataHtml' :: Data a => a -> SDoc + showAstDataHtml' = + (generic + `ext1Q` list + `extQ` string `extQ` fastString `extQ` srcSpan `extQ` realSrcSpan + `extQ` annotation + `extQ` annotationModule + `extQ` annotationAddEpAnn + `extQ` annotationGrhsAnn + `extQ` annotationEpAnnHsCase + `extQ` annotationEpAnnHsLet + `extQ` annotationAnnList + `extQ` annotationEpAnnImportDecl + `extQ` annotationAnnParen + `extQ` annotationTrailingAnn + `extQ` annotationEpaLocation + `extQ` addEpAnn + `extQ` lit `extQ` litr `extQ` litt + `extQ` sourceText + `extQ` deltaPos + `extQ` epaAnchor + `extQ` anchorOp + `extQ` bytestring + `extQ` name `extQ` occName `extQ` moduleName `extQ` var + `extQ` dataCon + `extQ` bagName `extQ` bagRdrName `extQ` bagVar `extQ` nameSet + `extQ` fixity + `ext2Q` located + `extQ` srcSpanAnnA + `extQ` srcSpanAnnL + `extQ` srcSpanAnnP + `extQ` srcSpanAnnC + `extQ` srcSpanAnnN + ) + + where generic :: Data a => a -> SDoc + generic t = nested (text $ showConstr (toConstr t)) + (vcat (gmapQ (li . showAstDataHtml') t)) + + string :: String -> SDoc + string = text . normalize_newlines . show + + fastString :: FastString -> SDoc + fastString s = braces $ + text "FastString:" + <+> text (normalize_newlines . show $ s) + + bytestring :: B.ByteString -> SDoc + bytestring = text . normalize_newlines . show + + list [] = brackets empty + list [x] = "[]" $$ showAstDataHtml' x + list xs = nested "[]" (vcat $ map (li . showAstDataHtml') xs) + + -- Eliminate word-size dependence + lit :: HsLit GhcPs -> SDoc + lit (HsWordPrim s x) = numericLit "HsWord{64}Prim" x s + lit (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s + lit (HsIntPrim s x) = numericLit "HsInt{64}Prim" x s + lit (HsInt64Prim s x) = numericLit "HsInt{64}Prim" x s + lit l = generic l + + litr :: HsLit GhcRn -> SDoc + litr (HsWordPrim s x) = numericLit "HsWord{64}Prim" x s + litr (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s + litr (HsIntPrim s x) = numericLit "HsInt{64}Prim" x s + litr (HsInt64Prim s x) = numericLit "HsInt{64}Prim" x s + litr l = generic l + + litt :: HsLit GhcTc -> SDoc + litt (HsWordPrim s x) = numericLit "HsWord{64}Prim" x s + litt (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s + litt (HsIntPrim s x) = numericLit "HsInt{64}Prim" x s + litt (HsInt64Prim s x) = numericLit "HsInt{64}Prim" x s + litt l = generic l + + numericLit :: String -> Integer -> SourceText -> SDoc + numericLit tag x s = braces $ hsep [ text tag + , generic x + , generic s ] + + sourceText :: SourceText -> SDoc + sourceText NoSourceText = text "NoSourceText" + sourceText (SourceText src) = text "SourceText" <+> text src + + epaAnchor :: EpaLocation -> SDoc + epaAnchor (EpaSpan r) = text "EpaSpan" <+> realSrcSpan r + epaAnchor (EpaDelta d cs) = text "EpaDelta" <+> deltaPos d <+> showAstDataHtml' cs + + anchorOp :: AnchorOperation -> SDoc + anchorOp UnchangedAnchor = "UnchangedAnchor" + anchorOp (MovedAnchor dp) = "MovedAnchor " <> deltaPos dp + + deltaPos :: DeltaPos -> SDoc + deltaPos (SameLine c) = text "SameLine" <+> ppr c + deltaPos (DifferentLine l c) = text "DifferentLine" <+> ppr l <+> ppr c + + name :: Name -> SDoc + name nm = braces $ text "Name:" <+> ppr nm + + occName n = braces $ + text "OccName:" + <+> text (occNameString n) + + moduleName :: ModuleName -> SDoc + moduleName m = braces $ text "ModuleName:" <+> ppr m + + srcSpan :: SrcSpan -> SDoc + srcSpan ss = char ' ' <> + (hang (ppr ss) 1 + -- TODO: show annotations here + (text "")) + + realSrcSpan :: RealSrcSpan -> SDoc + realSrcSpan ss = braces $ char ' ' <> + (hang (ppr ss) 1 + -- TODO: show annotations here + (text "")) + + addEpAnn :: AddEpAnn -> SDoc + addEpAnn (AddEpAnn a s) = text "AddEpAnn" <+> ppr a <+> epaAnchor s + + var :: Var -> SDoc + var v = braces $ text "Var:" <+> ppr v + + dataCon :: DataCon -> SDoc + dataCon c = braces $ text "DataCon:" <+> ppr c + + bagRdrName:: Bag (LocatedA (HsBind GhcPs)) -> SDoc + bagRdrName bg = braces $ + text "Bag(LocatedA (HsBind GhcPs)):" + $$ (list . bagToList $ bg) + + bagName :: Bag (LocatedA (HsBind GhcRn)) -> SDoc + bagName bg = braces $ + text "Bag(LocatedA (HsBind Name)):" + $$ (list . bagToList $ bg) + + bagVar :: Bag (LocatedA (HsBind GhcTc)) -> SDoc + bagVar bg = braces $ + text "Bag(LocatedA (HsBind Var)):" + $$ (list . bagToList $ bg) + + nameSet ns = braces $ + text "NameSet:" + $$ (list . nameSetElemsStable $ ns) + + fixity :: Fixity -> SDoc + fixity fx = braces $ + text "Fixity:" + <+> ppr fx + + located :: (Data a, Data b) => GenLocated a b -> SDoc + located (L ss a) + = nested "L" $ (li (showAstDataHtml' ss) $$ li (showAstDataHtml' a)) + + -- ------------------------- + + annotation :: EpAnn [AddEpAnn] -> SDoc + annotation = annotation' (text "EpAnn [AddEpAnn]") + + annotationModule :: EpAnn AnnsModule -> SDoc + annotationModule = annotation' (text "EpAnn AnnsModule") + + annotationAddEpAnn :: EpAnn AddEpAnn -> SDoc + annotationAddEpAnn = annotation' (text "EpAnn AddEpAnn") + + annotationGrhsAnn :: EpAnn GrhsAnn -> SDoc + annotationGrhsAnn = annotation' (text "EpAnn GrhsAnn") + + annotationEpAnnHsCase :: EpAnn EpAnnHsCase -> SDoc + annotationEpAnnHsCase = annotation' (text "EpAnn EpAnnHsCase") + + annotationEpAnnHsLet :: EpAnn AnnsLet -> SDoc + annotationEpAnnHsLet = annotation' (text "EpAnn AnnsLet") + + annotationAnnList :: EpAnn AnnList -> SDoc + annotationAnnList = annotation' (text "EpAnn AnnList") + + annotationEpAnnImportDecl :: EpAnn EpAnnImportDecl -> SDoc + annotationEpAnnImportDecl = annotation' (text "EpAnn EpAnnImportDecl") + + annotationAnnParen :: EpAnn AnnParen -> SDoc + annotationAnnParen = annotation' (text "EpAnn AnnParen") + + annotationTrailingAnn :: EpAnn TrailingAnn -> SDoc + annotationTrailingAnn = annotation' (text "EpAnn TrailingAnn") + + annotationEpaLocation :: EpAnn EpaLocation -> SDoc + annotationEpaLocation = annotation' (text "EpAnn EpaLocation") + + annotation' :: forall a .(Data a, Typeable a) + => SDoc -> EpAnn a -> SDoc + annotation' tag anns = nested (text $ showConstr (toConstr anns)) + (vcat (map li $ gmapQ showAstDataHtml' anns)) + + -- ------------------------- + + srcSpanAnnA :: SrcSpanAnn' (EpAnn AnnListItem) -> SDoc + srcSpanAnnA = locatedAnn'' (text "SrcSpanAnnA") + + srcSpanAnnL :: SrcSpanAnn' (EpAnn AnnList) -> SDoc + srcSpanAnnL = locatedAnn'' (text "SrcSpanAnnL") + + srcSpanAnnP :: SrcSpanAnn' (EpAnn AnnPragma) -> SDoc + srcSpanAnnP = locatedAnn'' (text "SrcSpanAnnP") + + srcSpanAnnC :: SrcSpanAnn' (EpAnn AnnContext) -> SDoc + srcSpanAnnC = locatedAnn'' (text "SrcSpanAnnC") + + srcSpanAnnN :: SrcSpanAnn' (EpAnn NameAnn) -> SDoc + srcSpanAnnN = locatedAnn'' (text "SrcSpanAnnN") + + locatedAnn'' :: forall a. (Typeable a, Data a) + => SDoc -> SrcSpanAnn' a -> SDoc + locatedAnn'' tag ss = + case cast ss of + Just ((SrcSpanAnn ann s) :: SrcSpanAnn' a) -> + nested "SrcSpanAnn" $ ( + li(showAstDataHtml' ann) + $$ li(srcSpan s)) + Nothing -> text "locatedAnn:unmatched" <+> tag + <+> (text (showConstr (toConstr ss))) +#endif + + +normalize_newlines :: String -> String +normalize_newlines ('\\':'r':'\\':'n':xs) = '\\':'n':normalize_newlines xs +normalize_newlines (x:xs) = x:normalize_newlines xs +normalize_newlines [] = [] + +css :: String +css = unlines + [ "body {background-color: black; color: white ;}" + , "/* Remove default bullets */" + , "ul, #myUL {" + , " list-style-type: none;" + , "}" + , "/* Remove margins and padding from the parent ul */" + , "#myUL {" + , " margin: 0; " + , " padding: 0; " + , "} " + , "/* Style the caret/arrow */ " + , ".caret { " + , " cursor: pointer; " + , " user-select: none; /* Prevent text selection */" + , "} " + , "/* Create the caret/arrow with a unicode, and style it */" + , ".caret::before { " + , " content: \"\\25B6 \"; " + , " color: white; " + , " display: inline-block; " + , " margin-right: 6px; " + , "} " + , "/* Rotate the caret/arrow icon when clicked on (using JavaScript) */" + , ".caret-down::before { " + , " transform: rotate(90deg); " + , "} " + , "/* Hide the nested list */ " + , ".nested { " + , " display: none; " + , "} " + , "/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */" + , ".active { " + , " display: block;}" + ] + +js :: String +js = unlines + [ "var toggler = document.getElementsByClassName(\"caret\");" + , "var i;" + , "for (i = 0; i < toggler.length; i++) {" + , " toggler[i].addEventListener(\"click\", function() {" + , " this.parentElement.querySelector(\".nested\").classList.toggle(\"active\");" + , " this.classList.toggle(\"caret-down\");" + , " }); }" + ] diff --git a/ghcide/src/Development/IDE/GHC/ExactPrint.hs b/ghcide/src/Development/IDE/GHC/ExactPrint.hs index 2f081cdedb..5d3f3e07c5 100644 --- a/ghcide/src/Development/IDE/GHC/ExactPrint.hs +++ b/ghcide/src/Development/IDE/GHC/ExactPrint.hs @@ -1,9 +1,12 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE DerivingVia #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE TypeFamilies #-} - +{-# LANGUAGE CPP #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeFamilies #-} + +-- | This module hosts various abstractions and utility functions to work with ghc-exactprint. module Development.IDE.GHC.ExactPrint ( Graft(..), graftDecls, @@ -18,7 +21,23 @@ module Development.IDE.GHC.ExactPrint graftSmallestDeclsWithM, transform, transformM, + ExactPrint(..), +#if !MIN_VERSION_ghc(9,2,0) useAnnotatedSource, + Anns, + Annotate, + setPrecedingLinesT, +#else + addParens, + addParensToCtxt, + modifyAnns, + removeComma, + -- * Helper function + eqSrcSpan, + epl, + epAnn, + removeTrailingComma, +#endif annotateParsedSource, getAnnotatedParsedSourceRule, GetAnnotatedParsedSource(..), @@ -26,22 +45,18 @@ module Development.IDE.GHC.ExactPrint ExceptStringT (..), Annotated(..), TransformT, - Anns, - Annotate, - setPrecedingLinesT, - -- * Helper function - eqSrcSpan, ) where import Control.Applicative (Alternative) -import Control.Arrow +import Control.Arrow (right, (***)) import Control.Monad import qualified Control.Monad.Fail as Fail import Control.Monad.IO.Class (MonadIO) import Control.Monad.Trans.Class import Control.Monad.Trans.Except import Control.Monad.Zip +import Data.Bifunctor import Data.Bool (bool) import qualified Data.DList as DL import Data.Either.Extra (mapLeft) @@ -64,7 +79,6 @@ import qualified GHC.Generics as GHC import Generics.SYB import Generics.SYB.GHC import Ide.PluginUtils -import Language.Haskell.GHC.ExactPrint import Language.Haskell.GHC.ExactPrint.Parsers import Language.LSP.Types import Language.LSP.Types.Capabilities (ClientCapabilities) @@ -72,7 +86,19 @@ import Retrie.ExactPrint hiding (parseDecl, parseExpr, parsePattern, parseType) - +#if MIN_VERSION_ghc(9,2,0) +import GHC (EpAnn (..), + NameAdornment (NameParens), + NameAnn (..), + SrcSpanAnn' (SrcSpanAnn), + SrcSpanAnnA, + TrailingAnn (AddCommaAnn), + emptyComments, + spanAsAnchor) +import GHC.Parser.Annotation (AnnContext (..), + DeltaPos (SameLine), + EpaLocation (EpaDelta)) +#endif ------------------------------------------------------------------------------ @@ -81,7 +107,11 @@ data GetAnnotatedParsedSource = GetAnnotatedParsedSource instance Hashable GetAnnotatedParsedSource instance NFData GetAnnotatedParsedSource +#if MIN_VERSION_ghc(9,2,0) +type instance RuleResult GetAnnotatedParsedSource = ParsedSource +#else type instance RuleResult GetAnnotatedParsedSource = Annotated ParsedSource +#endif -- | Get the latest version of the annotated parse source with comments. getAnnotatedParsedSourceRule :: Rules () @@ -89,9 +119,16 @@ getAnnotatedParsedSourceRule = define $ \GetAnnotatedParsedSource nfp -> do pm <- use GetParsedModuleWithComments nfp return ([], fmap annotateParsedSource pm) +#if MIN_VERSION_ghc(9,2,0) +annotateParsedSource :: ParsedModule -> ParsedSource +annotateParsedSource (ParsedModule _ ps _ _) = makeDeltaAst ps + +#else annotateParsedSource :: ParsedModule -> Annotated ParsedSource annotateParsedSource = fixAnns +#endif +#if !MIN_VERSION_ghc(9,2,0) useAnnotatedSource :: String -> IdeState -> @@ -99,6 +136,8 @@ useAnnotatedSource :: IO (Maybe (Annotated ParsedSource)) useAnnotatedSource herald state nfp = runAction herald state (use GetAnnotatedParsedSource nfp) +#endif + ------------------------------------------------------------------------------ {- | A transformation for grafting source trees together. Use the semigroup @@ -214,8 +253,8 @@ needsParensSpace _ = mempty ast@, or this is a no-op. -} graft' :: - forall ast a. - (Data a, ASTElement ast) => + forall ast a l. + (Data a, Typeable l, ASTElement l ast) => -- | Do we need to insert a space before this grafting? In do blocks, the -- answer is no, or we will break layout. But in function applications, -- the answer is yes, or the function call won't get its argument. Yikes! @@ -223,21 +262,26 @@ graft' :: -- More often the answer is yes, so when in doubt, use that. Bool -> SrcSpan -> - Located ast -> + LocatedAn l ast -> Graft (Either String) a graft' needs_space dst val = Graft $ \dflags a -> do +#if MIN_VERSION_ghc(9,2,0) + val' <- annotate dflags needs_space val +#else (anns, val') <- annotate dflags needs_space val modifyAnnsT $ mappend anns +#endif pure $ everywhere' ( mkT $ \case - (L src _ :: Located ast) - | src `eqSrcSpan` dst -> val' + (L src _ :: LocatedAn l ast) + | locA src `eqSrcSpan` dst -> val' l -> l ) a + -- | Like 'graft', but specialized to 'LHsExpr', and intelligently inserts -- parentheses if they're necessary. graftExpr :: @@ -254,12 +298,11 @@ graftExpr dst val = Graft $ \dflags a -> do dflags a - getNeedsSpaceAndParenthesize :: - (ASTElement ast, Data a) => + (ASTElement l ast, Data a) => SrcSpan -> a -> - (Bool, Located ast -> Located ast) + (Bool, LocatedAn l ast -> LocatedAn l ast) getNeedsSpaceAndParenthesize dst a = -- Traverse the tree, looking for our replacement node. But keep track of -- the context (parent HsExpr constructor) we're in while we do it. This @@ -267,7 +310,7 @@ getNeedsSpaceAndParenthesize dst a = let (needs_parens, needs_space) = everythingWithContext (Nothing, Nothing) (<>) ( mkQ (mempty, ) $ \x s -> case x of - (L src _ :: LHsExpr GhcPs) | src `eqSrcSpan` dst -> + (L src _ :: LHsExpr GhcPs) | locA src `eqSrcSpan` dst -> (s, s) L _ x' -> (mempty, Just *** Just $ needsParensSpace x') ) a @@ -291,40 +334,54 @@ graftExprWithM dst trans = Graft $ \dflags a -> do ( mkM $ \case val@(L src _ :: LHsExpr GhcPs) - | src `eqSrcSpan` dst -> do + | locA src `eqSrcSpan` dst -> do mval <- trans val case mval of Just val' -> do +#if MIN_VERSION_ghc(9,2,0) + val'' <- + hoistTransform (either Fail.fail pure) + (annotate @AnnListItem @(HsExpr GhcPs) dflags needs_space (mk_parens val')) + pure val'' +#else (anns, val'') <- hoistTransform (either Fail.fail pure) - (annotate @(HsExpr GhcPs) dflags needs_space (mk_parens val')) + (annotate @AnnListItem @(HsExpr GhcPs) dflags needs_space (mk_parens val')) modifyAnnsT $ mappend anns pure val'' +#endif Nothing -> pure val l -> pure l ) a graftWithM :: - forall ast m a. - (Fail.MonadFail m, Data a, ASTElement ast) => + forall ast m a l. + (Fail.MonadFail m, Data a, Typeable l, ASTElement l ast) => SrcSpan -> - (Located ast -> TransformT m (Maybe (Located ast))) -> + (LocatedAn l ast -> TransformT m (Maybe (LocatedAn l ast))) -> Graft m a graftWithM dst trans = Graft $ \dflags a -> do everywhereM' ( mkM $ \case - val@(L src _ :: Located ast) - | src `eqSrcSpan` dst -> do + val@(L src _ :: LocatedAn l ast) + | locA src `eqSrcSpan` dst -> do mval <- trans val case mval of Just val' -> do +#if MIN_VERSION_ghc(9,2,0) + val'' <- + hoistTransform (either Fail.fail pure) $ + annotate dflags True $ maybeParensAST val' + pure val'' +#else (anns, val'') <- hoistTransform (either Fail.fail pure) $ annotate dflags True $ maybeParensAST val' modifyAnnsT $ mappend anns pure val'' +#endif Nothing -> pure val l -> pure l ) @@ -368,7 +425,7 @@ graftDecls dst decs0 = Graft $ \dflags a -> do annotateDecl dflags decl let go [] = DL.empty go (L src e : rest) - | src `eqSrcSpan` dst = DL.fromList decs <> DL.fromList rest + | locA src `eqSrcSpan` dst = DL.fromList decs <> DL.fromList rest | otherwise = DL.singleton (L src e) <> go rest modifyDeclsT (pure . DL.toList . go) a @@ -381,7 +438,7 @@ graftSmallestDeclsWithM :: graftSmallestDeclsWithM dst toDecls = Graft $ \dflags a -> do let go [] = pure DL.empty go (e@(L src _) : rest) - | dst `isSubspanOf` src = toDecls e >>= \case + | dst `isSubspanOf` locA src = toDecls e >>= \case Just decs0 -> do decs <- forM decs0 $ \decl -> annotateDecl dflags decl @@ -399,7 +456,7 @@ graftDeclsWithM :: graftDeclsWithM dst toDecls = Graft $ \dflags a -> do let go [] = pure DL.empty go (e@(L src _) : rest) - | src `eqSrcSpan` dst = toDecls e >>= \case + | locA src `eqSrcSpan` dst = toDecls e >>= \case Just decs0 -> do decs <- forM decs0 $ \decl -> hoistTransform (either Fail.fail pure) $ @@ -410,9 +467,9 @@ graftDeclsWithM dst toDecls = Graft $ \dflags a -> do modifyDeclsT (fmap DL.toList . go) a -class (Data ast, Outputable ast) => ASTElement ast where - parseAST :: Parser (Located ast) - maybeParensAST :: Located ast -> Located ast +class (Data ast, Typeable l, Outputable l, Outputable ast) => ASTElement l ast | ast -> l where + parseAST :: Parser (LocatedAn l ast) + maybeParensAST :: LocatedAn l ast -> LocatedAn l ast {- | Construct a 'Graft', replacing the node at the given 'SrcSpan' with the given @Located ast@. The node at that position must already be a @Located ast@, or this is a no-op. @@ -421,16 +478,16 @@ class (Data ast, Outputable ast) => ASTElement ast where forall a. (Data a) => SrcSpan -> - Located ast -> + LocatedAn l ast -> Graft (Either String) a graft dst = graft' True dst . maybeParensAST -instance p ~ GhcPs => ASTElement (HsExpr p) where +instance p ~ GhcPs => ASTElement AnnListItem (HsExpr p) where parseAST = parseExpr maybeParensAST = parenthesize graft = graftExpr -instance p ~ GhcPs => ASTElement (Pat p) where +instance p ~ GhcPs => ASTElement AnnListItem (Pat p) where #if __GLASGOW_HASKELL__ == 808 parseAST = fmap (fmap $ right $ second dL) . parsePattern maybeParensAST = dL . parenthesizePat appPrec . unLoc @@ -439,41 +496,53 @@ instance p ~ GhcPs => ASTElement (Pat p) where maybeParensAST = parenthesizePat appPrec #endif -instance p ~ GhcPs => ASTElement (HsType p) where +instance p ~ GhcPs => ASTElement AnnListItem (HsType p) where parseAST = parseType maybeParensAST = parenthesizeHsType appPrec -instance p ~ GhcPs => ASTElement (HsDecl p) where +instance p ~ GhcPs => ASTElement AnnListItem (HsDecl p) where parseAST = parseDecl maybeParensAST = id -instance p ~ GhcPs => ASTElement (ImportDecl p) where +instance p ~ GhcPs => ASTElement AnnListItem (ImportDecl p) where parseAST = parseImport maybeParensAST = id -instance ASTElement RdrName where +instance ASTElement NameAnn RdrName where parseAST df fp = parseWith df fp parseIdentifier maybeParensAST = id ------------------------------------------------------------------------------ +#if !MIN_VERSION_ghc(9,2,0) -- | Dark magic I stole from retrie. No idea what it does. fixAnns :: ParsedModule -> Annotated ParsedSource fixAnns ParsedModule {..} = let ranns = relativiseApiAnns pm_parsed_source pm_annotations in unsafeMkA pm_parsed_source ranns 0 +#endif ------------------------------------------------------------------------------ -- | Given an 'LHSExpr', compute its exactprint annotations. -- Note that this function will throw away any existing annotations (and format) -annotate :: ASTElement ast => DynFlags -> Bool -> Located ast -> TransformT (Either String) (Anns, Located ast) +annotate :: (ASTElement l ast, Outputable l) +#if MIN_VERSION_ghc(9,2,0) + => DynFlags -> Bool -> LocatedAn l ast -> TransformT (Either String) (LocatedAn l ast) +#else + => DynFlags -> Bool -> LocatedAn l ast -> TransformT (Either String) (Anns, LocatedAn l ast) +#endif annotate dflags needs_space ast = do uniq <- show <$> uniqueSrcSpanT let rendered = render dflags ast +#if MIN_VERSION_ghc(9,2,0) + expr' <- lift $ mapLeft show $ parseAST dflags uniq rendered + pure expr' +#else (anns, expr') <- lift $ mapLeft show $ parseAST dflags uniq rendered let anns' = setPrecedingLines expr' 0 (bool 0 1 needs_space) anns - pure (anns', expr') + pure (anns',expr') +#endif -- | Given an 'LHsDecl', compute its exactprint annotations. annotateDecl :: DynFlags -> LHsDecl GhcPs -> TransformT (Either String) (LHsDecl GhcPs) @@ -489,6 +558,17 @@ annotateDecl dflags let set_matches matches = ValD ext fb { fun_matches = mg { mg_alts = L alt_src matches }} +#if MIN_VERSION_ghc(9,2,0) + alts' <- for alts $ \alt -> do + uniq <- show <$> uniqueSrcSpanT + let rendered = render dflags $ set_matches [alt] + lift (mapLeft show $ parseDecl dflags uniq rendered) >>= \case + (L _ (ValD _ FunBind { fun_matches = MG { mg_alts = L _ [alt']}})) + -> pure alt' + _ -> lift $ Left "annotateDecl: didn't parse a single FunBind match" + + pure $ L src $ set_matches alts' +#else (anns', alts') <- fmap unzip $ for alts $ \alt -> do uniq <- show <$> uniqueSrcSpanT let rendered = render dflags $ set_matches [alt] @@ -499,13 +579,18 @@ annotateDecl dflags modifyAnnsT $ mappend $ fold anns' pure $ L src $ set_matches alts' +#endif annotateDecl dflags ast = do uniq <- show <$> uniqueSrcSpanT let rendered = render dflags ast +#if MIN_VERSION_ghc(9,2,0) + lift $ mapLeft show $ parseDecl dflags uniq rendered +#else (anns, expr') <- lift $ mapLeft show $ parseDecl dflags uniq rendered let anns' = setPrecedingLines expr' 1 0 anns modifyAnnsT $ mappend anns' pure expr' +#endif ------------------------------------------------------------------------------ @@ -525,3 +610,60 @@ parenthesize = parenthesizeHsExpr appPrec -- Ignores the (Maybe BufSpan) field of SrcSpan's. eqSrcSpan :: SrcSpan -> SrcSpan -> Bool eqSrcSpan l r = leftmost_smallest l r == EQ + +-- | Equality on SrcSpan's. +-- Ignores the (Maybe BufSpan) field of SrcSpan's. +#if MIN_VERSION_ghc(9,2,0) +eqSrcSpanA :: SrcAnn la -> SrcAnn b -> Bool +eqSrcSpanA l r = leftmost_smallest (locA l) (locA r) == EQ +#else +eqSrcSpanA :: SrcSpan -> SrcSpan -> Bool +eqSrcSpanA l r = leftmost_smallest l r == EQ +#endif + +#if MIN_VERSION_ghc(9,2,0) +addParensToCtxt :: Maybe EpaLocation -> AnnContext -> AnnContext +addParensToCtxt close_dp = addOpen . addClose + where + addOpen it@AnnContext{ac_open = []} = it{ac_open = [epl 0]} + addOpen other = other + addClose it + | Just c <- close_dp = it{ac_close = [c]} + | AnnContext{ac_close = []} <- it = it{ac_close = [epl 0]} + | otherwise = it + +epl :: Int -> EpaLocation +epl n = EpaDelta (SameLine n) [] + +epAnn :: SrcSpan -> ann -> EpAnn ann +epAnn srcSpan anns = EpAnn (spanAsAnchor srcSpan) anns emptyComments + +modifyAnns :: LocatedAn a ast -> (a -> a) -> LocatedAn a ast +modifyAnns x f = first ((fmap.fmap) f) x + +removeComma :: SrcSpanAnnA -> SrcSpanAnnA +removeComma it@(SrcSpanAnn EpAnnNotUsed _) = it +removeComma (SrcSpanAnn (EpAnn anc (AnnListItem as) cs) l) + = (SrcSpanAnn (EpAnn anc (AnnListItem (filter (not . isCommaAnn) as)) cs) l) + where + isCommaAnn AddCommaAnn{} = True + isCommaAnn _ = False + +addParens :: Bool -> GHC.NameAnn -> GHC.NameAnn +addParens True it@NameAnn{} = + it{nann_adornment = NameParens, nann_open = epl 0, nann_close = epl 0 } +addParens True it@NameAnnCommas{} = + it{nann_adornment = NameParens, nann_open = epl 0, nann_close = epl 0 } +addParens True it@NameAnnOnly{} = + it{nann_adornment = NameParens, nann_open = epl 0, nann_close = epl 0 } +addParens True NameAnnTrailing{..} = + NameAnn{nann_adornment = NameParens, nann_open = epl 0, nann_close = epl 0, nann_name = epl 0, ..} +addParens _ it = it + +removeTrailingComma :: GenLocated SrcSpanAnnA ast -> GenLocated SrcSpanAnnA ast +removeTrailingComma = flip modifyAnns $ \(AnnListItem l) -> AnnListItem $ filter (not . isCommaAnn) l + +isCommaAnn :: TrailingAnn -> Bool +isCommaAnn AddCommaAnn{} = True +isCommaAnn _ = False +#endif diff --git a/ghcide/src/Development/IDE/GHC/Orphans.hs b/ghcide/src/Development/IDE/GHC/Orphans.hs index 50aaa544ac..3c28900a26 100644 --- a/ghcide/src/Development/IDE/GHC/Orphans.hs +++ b/ghcide/src/Development/IDE/GHC/Orphans.hs @@ -9,6 +9,9 @@ -- Note that the 'NFData' instances may not be law abiding. module Development.IDE.GHC.Orphans() where +#if MIN_VERSION_ghc(9,2,0) +import GHC.Parser.Annotation +#endif #if MIN_VERSION_ghc(9,0,0) import GHC.Data.Bag import GHC.Data.FastString @@ -25,7 +28,6 @@ import qualified StringBuffer as SB import Unique (getKey) #endif -import GHC import Retrie.ExactPrint (Annotated) @@ -34,6 +36,7 @@ import Development.IDE.GHC.Util import Control.DeepSeq import Data.Aeson +import Data.Bifunctor (Bifunctor (..)) import Data.Hashable import Data.String (IsString (fromString)) @@ -92,6 +95,19 @@ instance NFData FastString where rnf = rwhnf #endif +#if MIN_VERSION_ghc(9,2,0) +instance Ord FastString where + compare a b = if a == b then EQ else compare (fs_sbs a) (fs_sbs b) + +instance NFData (SrcSpanAnn' a) where + rnf = rwhnf + +instance Bifunctor (GenLocated) where + bimap f g (L l x) = L (f l) (g x) + +deriving instance Functor SrcSpanAnn' +#endif + instance NFData ParsedModule where rnf = rwhnf diff --git a/ghcide/src/Development/IDE/GHC/Util.hs b/ghcide/src/Development/IDE/GHC/Util.hs index 1e3568086b..4e002b13ec 100644 --- a/ghcide/src/Development/IDE/GHC/Util.hs +++ b/ghcide/src/Development/IDE/GHC/Util.hs @@ -28,49 +28,25 @@ module Development.IDE.GHC.Util( setHieDir, dontWriteHieFiles, disableWarningsAsErrors, - ) where + traceAst) where #if MIN_VERSION_ghc(9,2,0) -import GHC -import GHC.Core.Multiplicity -import qualified GHC.Core.TyCo.Rep as TyCoRep import GHC.Data.FastString import GHC.Data.StringBuffer import GHC.Driver.Env -import GHC.Driver.Env.Types import GHC.Driver.Monad import GHC.Driver.Session hiding (ExposePackage) -import qualified GHC.Driver.Session as DynFlags -import GHC.Hs.Extension -import qualified GHC.Hs.Type as GHC -import GHC.Iface.Env (updNameCache) -import GHC.Iface.Make (mkIfaceExports) -import qualified GHC.Linker.Types as LinkerTypes import GHC.Parser.Lexer import GHC.Runtime.Context -import GHC.Tc.Types (TcGblEnv (tcg_exports)) -import GHC.Tc.Utils.TcType (pprSigmaType) -import GHC.Types.Avail -import GHC.Types.Name.Cache import GHC.Types.Name.Occurrence import GHC.Types.Name.Reader import GHC.Types.SrcLoc -import qualified GHC.Types.SrcLoc as SrcLoc -import GHC.Unit.Env -import GHC.Unit.Info (PackageName) -import qualified GHC.Unit.Info as Packages -import qualified GHC.Unit.Module.Location as Module import GHC.Unit.Module.ModDetails import GHC.Unit.Module.ModGuts -import GHC.Unit.Module.ModIface (mi_mod_hash) -import GHC.Unit.Module.Name (moduleNameSlashes) -import qualified GHC.Unit.State as Packages -import GHC.Unit.Types (IsBootInterface (..), - unitString) -import qualified GHC.Unit.Types as Module import GHC.Utils.Fingerprint import GHC.Utils.Outputable -import qualified GHC.Utils.Outputable as Outputable +#else +import Development.IDE.GHC.Compat.Util #endif import Control.Concurrent import Control.Exception as E @@ -79,17 +55,22 @@ import qualified Data.ByteString as BS import Data.ByteString.Internal (ByteString (..)) import qualified Data.ByteString.Internal as BS import qualified Data.ByteString.Lazy as LBS +import Data.Data (Data) import Data.IORef import Data.List.Extra import Data.Maybe import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding.Error as T +import Data.Time.Clock.POSIX (POSIXTime, getCurrentTime, + utcTimeToPOSIXSeconds) import Data.Typeable +import qualified Data.Unique as U +import Debug.Trace import Development.IDE.GHC.Compat as GHC import qualified Development.IDE.GHC.Compat.Parser as Compat import qualified Development.IDE.GHC.Compat.Units as Compat -import Development.IDE.GHC.Compat.Util +import Development.IDE.GHC.Dump (showAstDataHtml) import Development.IDE.Types.Location import Foreign.ForeignPtr import Foreign.Ptr @@ -101,8 +82,11 @@ import GHC.IO.Encoding import GHC.IO.Exception import GHC.IO.Handle.Internals import GHC.IO.Handle.Types - +import GHC.Stack +import System.Environment.Blank (getEnvDefault) import System.FilePath +import System.IO.Unsafe +import Text.Printf ---------------------------------------------------------------------- @@ -300,3 +284,38 @@ ioe_dupHandlesNotCompatible :: Handle -> IO a ioe_dupHandlesNotCompatible h = ioException (IOError (Just h) IllegalOperation "hDuplicateTo" "handles are incompatible" Nothing Nothing) + +-------------------------------------------------------------------------------- +-- Tracing exactprint terms + +{-# NOINLINE timestamp #-} +timestamp :: POSIXTime +timestamp = utcTimeToPOSIXSeconds $ unsafePerformIO getCurrentTime + +debugAST :: Bool +debugAST = unsafePerformIO (getEnvDefault "GHCIDE_DEBUG_AST" "0") == "1" + +-- | Prints an 'Outputable' value to stderr and to an HTML file for further inspection +traceAst :: (Data a, ExactPrint a, Outputable a, HasCallStack) => String -> a -> a +traceAst lbl x + | debugAST = trace doTrace x + | otherwise = x + where +#if MIN_VERSION_ghc(9,2,0) + renderDump = renderWithContext defaultSDocContext{sdocStyle = defaultDumpStyle, sdocPprDebug = True} +#else + renderDump = unsafePrintSDoc +#endif + htmlDump = showAstDataHtml x + doTrace = unsafePerformIO $ do + u <- U.newUnique + let htmlDumpFileName = printf "/tmp/hls/%s-%s-%d.html" (show timestamp) lbl (U.hashUnique u) + writeFile htmlDumpFileName $ renderDump htmlDump + return $ unlines + [prettyCallStack callStack ++ ":" +#if MIN_VERSION_ghc(9,2,0) + , exactPrint x +#endif + , "file://" ++ htmlDumpFileName] + + diff --git a/ghcide/src/Development/IDE/LSP/Outline.hs b/ghcide/src/Development/IDE/LSP/Outline.hs index 1056e5dbc4..17d6622312 100644 --- a/ghcide/src/Development/IDE/LSP/Outline.hs +++ b/ghcide/src/Development/IDE/LSP/Outline.hs @@ -29,6 +29,9 @@ import Language.LSP.Types (DocumentSymbol (..), SymbolKind (SkConstructor, SkField, SkFile, SkFunction, SkInterface, SkMethod, SkModule, SkObject, SkStruct, SkTypeParameter, SkUnknown), TextDocumentIdentifier (TextDocumentIdentifier), type (|?) (InL), uriToFilePath) +#if MIN_VERSION_ghc(9,2,0) +import Data.List.NonEmpty (nonEmpty, toList) +#endif moduleOutline :: IdeState -> DocumentSymbolParams -> LspM c (Either ResponseError (List DocumentSymbol |? List SymbolInformation)) @@ -42,7 +45,7 @@ moduleOutline ideState DocumentSymbolParams{ _textDocument = TextDocumentIdentif -> let declSymbols = mapMaybe documentSymbolForDecl hsmodDecls moduleSymbol = hsmodName >>= \case - (L (RealSrcSpan l _) m) -> Just $ + (L (locA -> (RealSrcSpan l _)) m) -> Just $ (defDocumentSymbol l :: DocumentSymbol) { _name = pprText m , _kind = SkFile @@ -64,8 +67,8 @@ moduleOutline ideState DocumentSymbolParams{ _textDocument = TextDocumentIdentif Nothing -> pure $ Right $ InL (List []) -documentSymbolForDecl :: Located (HsDecl GhcPs) -> Maybe DocumentSymbol -documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ FamDecl { tcdFam = FamilyDecl { fdLName = L _ n, fdInfo, fdTyVars } })) +documentSymbolForDecl :: LHsDecl GhcPs -> Maybe DocumentSymbol +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (TyClD _ FamDecl { tcdFam = FamilyDecl { fdLName = L _ n, fdInfo, fdTyVars } })) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName n <> (case pprText fdTyVars of @@ -75,7 +78,7 @@ documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ FamDecl { tcdFam = FamilyDec , _detail = Just $ pprText fdInfo , _kind = SkFunction } -documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ ClassDecl { tcdLName = L _ name, tcdSigs, tcdTyVars })) +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (TyClD _ ClassDecl { tcdLName = L _ name, tcdSigs, tcdTyVars })) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName name <> (case pprText tcdTyVars of @@ -91,11 +94,11 @@ documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ ClassDecl { tcdLName = L _ n , _kind = SkMethod , _selectionRange = realSrcSpanToRange l' } - | L (RealSrcSpan l _) (ClassOpSig _ False names _) <- tcdSigs - , L (RealSrcSpan l' _) n <- names + | L (locA -> (RealSrcSpan l _)) (ClassOpSig _ False names _) <- tcdSigs + , L (locA -> (RealSrcSpan l' _)) n <- names ] } -documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ DataDecl { tcdLName = L _ name, tcdDataDefn = HsDataDefn { dd_cons } })) +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (TyClD _ DataDecl { tcdLName = L _ name, tcdDataDefn = HsDataDefn { dd_cons } })) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName name , _kind = SkStruct @@ -105,10 +108,30 @@ documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ DataDecl { tcdLName = L _ na { _name = showRdrName n , _kind = SkConstructor , _selectionRange = realSrcSpanToRange l' - , _children = conArgRecordFields (con_args x) +#if MIN_VERSION_ghc(9,2,0) + , _children = List . toList <$> nonEmpty childs } - | L (RealSrcSpan l _ ) x <- dd_cons - , L (RealSrcSpan l' _) n <- getConNames' x + | con <- dd_cons + , let (cs, flds) = hsConDeclsBinders con + , let childs = mapMaybe cvtFld flds + , L (locA -> RealSrcSpan l' _) n <- cs + , let l = case con of + L (locA -> RealSrcSpan l _) _ -> l + _ -> l' + ] + } + where + cvtFld :: LFieldOcc GhcPs -> Maybe DocumentSymbol + cvtFld (L (RealSrcSpan l _) n) = Just $ (defDocumentSymbol l :: DocumentSymbol) + { _name = showRdrName (unLoc (rdrNameFieldOcc n)) + , _kind = SkField + } + cvtFld _ = Nothing +#else + , _children = conArgRecordFields (con_args x) + } + | L (locA -> (RealSrcSpan l _ )) x <- dd_cons + , L (locA -> (RealSrcSpan l' _)) n <- getConNames' x ] } where @@ -119,48 +142,57 @@ documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ DataDecl { tcdLName = L _ na , _kind = SkField } | L _ cdf <- lcdfs - , L (RealSrcSpan l _) n <- rdrNameFieldOcc . unLoc <$> cd_fld_names cdf + , L (locA -> (RealSrcSpan l _)) n <- rdrNameFieldOcc . unLoc <$> cd_fld_names cdf ] conArgRecordFields _ = Nothing -documentSymbolForDecl (L (RealSrcSpan l _) (TyClD _ SynDecl { tcdLName = L (RealSrcSpan l' _) n })) = Just +#endif +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (TyClD _ SynDecl { tcdLName = L (locA -> (RealSrcSpan l' _)) n })) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName n , _kind = SkTypeParameter , _selectionRange = realSrcSpanToRange l' } -documentSymbolForDecl (L (RealSrcSpan l _) (InstD _ ClsInstD { cid_inst = ClsInstDecl { cid_poly_ty } })) +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (InstD _ ClsInstD { cid_inst = ClsInstDecl { cid_poly_ty } })) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = pprText cid_poly_ty , _kind = SkInterface } +#if MIN_VERSION_ghc(9,2,0) +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (InstD _ DataFamInstD { dfid_inst = DataFamInstDecl FamEqn { feqn_tycon, feqn_pats } })) +#else documentSymbolForDecl (L (RealSrcSpan l _) (InstD _ DataFamInstD { dfid_inst = DataFamInstDecl HsIB { hsib_body = FamEqn { feqn_tycon, feqn_pats } } })) +#endif = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName (unLoc feqn_tycon) <> " " <> T.unwords (map pprText feqn_pats) , _kind = SkInterface } +#if MIN_VERSION_ghc(9,2,0) +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (InstD _ TyFamInstD { tfid_inst = TyFamInstDecl _ FamEqn { feqn_tycon, feqn_pats } })) +#else documentSymbolForDecl (L (RealSrcSpan l _) (InstD _ TyFamInstD { tfid_inst = TyFamInstDecl HsIB { hsib_body = FamEqn { feqn_tycon, feqn_pats } } })) +#endif = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName (unLoc feqn_tycon) <> " " <> T.unwords (map pprText feqn_pats) , _kind = SkInterface } -documentSymbolForDecl (L (RealSrcSpan l _) (DerivD _ DerivDecl { deriv_type })) = +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (DerivD _ DerivDecl { deriv_type })) = gfindtype deriv_type <&> \(L (_ :: SrcSpan) name) -> (defDocumentSymbol l :: DocumentSymbol) { _name = pprText @(HsType GhcPs) name , _kind = SkInterface } -documentSymbolForDecl (L (RealSrcSpan l _) (ValD _ FunBind{fun_id = L _ name})) = Just +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (ValD _ FunBind{fun_id = L _ name})) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName name , _kind = SkFunction } -documentSymbolForDecl (L (RealSrcSpan l _) (ValD _ PatBind{pat_lhs})) = Just +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (ValD _ PatBind{pat_lhs})) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = pprText pat_lhs , _kind = SkFunction } -documentSymbolForDecl (L (RealSrcSpan l _) (ForD _ x)) = Just +documentSymbolForDecl (L (locA -> (RealSrcSpan l _)) (ForD _ x)) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = case x of ForeignImport{} -> name @@ -193,8 +225,8 @@ documentSymbolForImportSummary importSymbols = , _children = Just (List importSymbols) } -documentSymbolForImport :: Located (ImportDecl GhcPs) -> Maybe DocumentSymbol -documentSymbolForImport (L (RealSrcSpan l _) ImportDecl { ideclName, ideclQualified }) = Just +documentSymbolForImport :: LImportDecl GhcPs -> Maybe DocumentSymbol +documentSymbolForImport (L (locA -> (RealSrcSpan l _)) ImportDecl { ideclName, ideclQualified }) = Just (defDocumentSymbol l :: DocumentSymbol) { _name = "import " <> pprText ideclName , _kind = SkModule @@ -224,6 +256,7 @@ pprText :: Outputable a => a -> Text pprText = pack . showSDocUnsafe . ppr -- the version of getConNames for ghc9 is restricted to only the renaming phase +#if !MIN_VERSION_ghc(9,2,0) getConNames' :: ConDecl GhcPs -> [Located (IdP GhcPs)] getConNames' ConDeclH98 {con_name = name} = [name] getConNames' ConDeclGADT {con_names = names} = names @@ -232,3 +265,44 @@ getConNames' (XConDecl NoExt) = [] #elif !MIN_VERSION_ghc(9,0,0) getConNames' (XConDecl x) = noExtCon x #endif +#else +hsConDeclsBinders :: LConDecl GhcPs + -> ([LIdP GhcPs], [LFieldOcc GhcPs]) + -- See hsLTyClDeclBinders for what this does + -- The function is boringly complicated because of the records + -- And since we only have equality, we have to be a little careful +hsConDeclsBinders cons + = go cons + where + go :: LConDecl GhcPs + -> ([LIdP GhcPs], [LFieldOcc GhcPs]) + go r + -- Don't re-mangle the location of field names, because we don't + -- have a record of the full location of the field declaration anyway + = case unLoc r of + -- remove only the first occurrence of any seen field in order to + -- avoid circumventing detection of duplicate fields (#9156) + ConDeclGADT { con_names = names, con_g_args = args } + -> (names, flds) + where + flds = get_flds_gadt args + + ConDeclH98 { con_name = name, con_args = args } + -> ([name], flds) + where + flds = get_flds_h98 args + + get_flds_h98 :: HsConDeclH98Details GhcPs + -> [LFieldOcc GhcPs] + get_flds_h98 (RecCon flds) = get_flds (reLoc flds) + get_flds_h98 _ = [] + + get_flds_gadt :: HsConDeclGADTDetails GhcPs + -> ([LFieldOcc GhcPs]) + get_flds_gadt (RecConGADT flds) = get_flds (reLoc flds) + get_flds_gadt _ = [] + + get_flds :: Located [LConDeclField GhcPs] + -> ([LFieldOcc GhcPs]) + get_flds flds = concatMap (cd_fld_names . unLoc) (unLoc flds) +#endif diff --git a/ghcide/src/Development/IDE/Main.hs b/ghcide/src/Development/IDE/Main.hs index 74929b3673..1a101cdc1d 100644 --- a/ghcide/src/Development/IDE/Main.hs +++ b/ghcide/src/Development/IDE/Main.hs @@ -80,7 +80,7 @@ import Development.IDE.Types.Options (IdeGhcSession, defaultIdeOptions, optModifyDynFlags, optTesting) -import Development.IDE.Types.Shake (Key (Key), fromKeyType) +import Development.IDE.Types.Shake (fromKeyType) import GHC.Conc (getNumProcessors) import GHC.IO.Encoding (setLocaleEncoding) import GHC.IO.Handle (hDuplicate) diff --git a/ghcide/src/Development/IDE/Plugin/CodeAction.hs b/ghcide/src/Development/IDE/Plugin/CodeAction.hs index 57213ddf96..e1667ef627 100644 --- a/ghcide/src/Development/IDE/Plugin/CodeAction.hs +++ b/ghcide/src/Development/IDE/Plugin/CodeAction.hs @@ -3,6 +3,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE GADTs #-} -- | Go to the definition of a variable. @@ -22,7 +23,8 @@ import Control.Applicative ((<|>)) import Control.Arrow (second, (>>>)) import Control.Concurrent.STM.Stats (atomically) -import Control.Monad (guard, join) +import Control.Monad (guard, join, + msum) import Control.Monad.IO.Class import Data.Char import qualified Data.DList as DL @@ -45,8 +47,10 @@ import Development.IDE.Core.Service import Development.IDE.GHC.Compat import Development.IDE.GHC.Compat.Util import Development.IDE.GHC.Error +import Development.IDE.GHC.ExactPrint import Development.IDE.GHC.Util (prettyPrint, printRdrName, + traceAst, unsafePrintSDoc) import Development.IDE.Plugin.CodeAction.Args import Development.IDE.Plugin.CodeAction.ExactPrint @@ -141,7 +145,7 @@ fillHolePluginDescriptor = mkGhcideCAPlugin $ wrap suggestFillHole ------------------------------------------------------------------------------------------------- -findSigOfDecl :: (IdP p -> Bool) -> [LHsDecl p] -> Maybe (Sig p) +findSigOfDecl :: p ~ GhcPass p0 => (IdP p -> Bool) -> [LHsDecl p] -> Maybe (Sig p) findSigOfDecl pred decls = listToMaybe [ sig @@ -149,7 +153,7 @@ findSigOfDecl pred decls = any (pred . unLoc) idsSig ] -findSigOfDeclRanged :: Range -> [LHsDecl p] -> Maybe (Sig p) +findSigOfDeclRanged :: forall p p0 . p ~ GhcPass p0 => Range -> [LHsDecl p] -> Maybe (Sig p) findSigOfDeclRanged range decls = do dec <- findDeclContainingLoc (_start range) decls case dec of @@ -157,7 +161,7 @@ findSigOfDeclRanged range decls = do L _ (ValD _ (bind :: HsBind p)) -> findSigOfBind range bind _ -> Nothing -findSigOfBind :: Range -> HsBind p -> Maybe (Sig p) +findSigOfBind :: forall p p0. p ~ GhcPass p0 => Range -> HsBind p -> Maybe (Sig p) findSigOfBind range bind = case bind of FunBind {} -> findSigOfLMatch (unLoc $ mg_alts (fun_matches bind)) @@ -166,30 +170,38 @@ findSigOfBind range bind = findSigOfLMatch :: [LMatch p (LHsExpr p)] -> Maybe (Sig p) findSigOfLMatch ls = do match <- findDeclContainingLoc (_start range) ls - findSigOfGRHSs (m_grhss (unLoc match)) - - findSigOfGRHSs :: GRHSs p (LHsExpr p) -> Maybe (Sig p) - findSigOfGRHSs grhs = do - if _start range `isInsideSrcSpan` (getLoc $ grhssLocalBinds grhs) + let grhs = m_grhss $ unLoc match +#if !MIN_VERSION_ghc(9,2,0) + span = getLoc $ reLoc $ grhssLocalBinds grhs + if _start range `isInsideSrcSpan` span then findSigOfBinds range (unLoc (grhssLocalBinds grhs)) -- where clause else do - grhs <- findDeclContainingLoc (_start range) (grhssGRHSs grhs) + grhs <- findDeclContainingLoc (_start range) (map reLocA $ grhssGRHSs grhs) case unLoc grhs of GRHS _ _ bd -> findSigOfExpr (unLoc bd) _ -> Nothing +#else + msum + [findSigOfBinds range (grhssLocalBinds grhs) -- where clause + , do + grhs <- findDeclContainingLoc (_start range) (map reLocA $ grhssGRHSs grhs) + case unLoc grhs of + GRHS _ _ bd -> findSigOfExpr (unLoc bd) + ] +#endif findSigOfExpr :: HsExpr p -> Maybe (Sig p) findSigOfExpr = go where - go (HsLet _ binds _) = findSigOfBinds range (unLoc binds) + go (HsLet _ binds _) = findSigOfBinds range binds go (HsDo _ _ stmts) = do stmtlr <- unLoc <$> findDeclContainingLoc (_start range) (unLoc stmts) case stmtlr of - LetStmt _ lhsLocalBindsLR -> findSigOfBinds range $ unLoc lhsLocalBindsLR - _ -> Nothing + LetStmt _ lhsLocalBindsLR -> findSigOfBinds range lhsLocalBindsLR + _ -> Nothing go _ = Nothing -findSigOfBinds :: Range -> HsLocalBinds p -> Maybe (Sig p) +findSigOfBinds :: p ~ GhcPass p0 => Range -> HsLocalBinds p -> Maybe (Sig p) findSigOfBinds range = go where go (HsValBinds _ (ValBinds _ binds lsigs)) = @@ -200,17 +212,27 @@ findSigOfBinds range = go findSigOfBind range (unLoc lHsBindLR) go _ = Nothing -findInstanceHead :: (Outputable (HsType p)) => DynFlags -> String -> [LHsDecl p] -> Maybe (LHsType p) +findInstanceHead :: (Outputable (HsType p), p ~ GhcPass p0) => DynFlags -> String -> [LHsDecl p] -> Maybe (LHsType p) findInstanceHead df instanceHead decls = listToMaybe +#if !MIN_VERSION_ghc(9,2,0) [ hsib_body | L _ (InstD _ (ClsInstD _ ClsInstDecl {cid_poly_ty = HsIB {hsib_body}})) <- decls, showSDoc df (ppr hsib_body) == instanceHead ] +#else + [ hsib_body + | L _ (InstD _ (ClsInstD _ ClsInstDecl {cid_poly_ty = (unLoc -> HsSig {sig_body = hsib_body})})) <- decls, + showSDoc df (ppr hsib_body) == instanceHead + ] +#endif -findDeclContainingLoc :: Position -> [Located a] -> Maybe (Located a) -findDeclContainingLoc loc = find (\(L l _) -> loc `isInsideSrcSpan` l) - +#if MIN_VERSION_ghc(9,2,0) +findDeclContainingLoc :: Foldable t => Position -> t (GenLocated (SrcSpanAnn' a) e) -> Maybe (GenLocated (SrcSpanAnn' a) e) +#else +-- TODO populate this type signature for GHC versions <9.2 +#endif +findDeclContainingLoc loc = find (\(L l _) -> loc `isInsideSrcSpan` locA l) -- Single: -- This binding for ‘mod’ shadows the existing binding @@ -281,8 +303,8 @@ isUnusedImportedId imv_name == mkModuleName modName, isTheSameLine imv_span importSpan ], - [GRE {..}] <- lookupGlobalRdrEnv rdrEnv occ, - importedIdentifier <- Right gre_name, + [GRE {gre_name = name}] <- lookupGlobalRdrEnv rdrEnv occ, + importedIdentifier <- Right name, refs <- M.lookup importedIdentifier refMap = maybe True (not . any (\(_, IdentifierDetails {..}) -> identInfo == S.singleton Use)) refs | otherwise = False @@ -291,7 +313,7 @@ suggestRemoveRedundantImport :: ParsedModule -> Maybe T.Text -> Diagnostic -> [( suggestRemoveRedundantImport ParsedModule{pm_parsed_source = L _ HsModule{hsmodImports}} contents Diagnostic{_range=_range,..} -- The qualified import of ‘many’ from module ‘Control.Applicative’ is redundant | Just [_, bindings] <- matchRegexUnifySpaces _message "The( qualified)? import of ‘([^’]*)’ from module [^ ]* is redundant" - , Just (L _ impDecl) <- find (\(L l _) -> _start _range `isInsideSrcSpan` l && _end _range `isInsideSrcSpan` l ) hsmodImports + , Just (L _ impDecl) <- find (\(L (locA -> l) _) -> _start _range `isInsideSrcSpan` l && _end _range `isInsideSrcSpan` l ) hsmodImports , Just c <- contents , ranges <- map (rangesForBindingImport impDecl . T.unpack) (T.splitOn ", " bindings) , ranges' <- extendAllToIncludeCommaIfPossible False (indexedByPosition $ T.unpack c) (concat ranges) @@ -391,7 +413,7 @@ suggestRemoveRedundantExport :: ParsedModule -> Diagnostic -> Maybe (T.Text, [Ra suggestRemoveRedundantExport ParsedModule{pm_parsed_source = L _ HsModule{..}} Diagnostic{..} | msg <- unifySpaces _message , Just export <- hsmodExports - , Just exportRange <- getLocatedRange export + , Just exportRange <- getLocatedRange $ reLoc export , exports <- unLoc export , Just (removeFromExport, !ranges) <- fmap (getRanges exports . notInScope) (extractNotInScopeName msg) <|> (,[_range]) <$> matchExportItem msg @@ -419,7 +441,7 @@ suggestDeleteUnusedBinding | otherwise = [] where relatedRanges indexedContent name = - concatMap (findRelatedSpans indexedContent name) hsmodDecls + concatMap (findRelatedSpans indexedContent name . reLoc) hsmodDecls toRange = realSrcSpanToRange extendForSpaces = extendToIncludePreviousNewlineIfPossible @@ -434,7 +456,7 @@ suggestDeleteUnusedBinding findSig _ = [] in extendForSpaces indexedContent (toRange l) : - concatMap findSig hsmodDecls + concatMap (findSig . reLoc) hsmodDecls _ -> concatMap (findRelatedSpanForMatch indexedContent name) matches findRelatedSpans _ _ _ = [] @@ -445,7 +467,7 @@ suggestDeleteUnusedBinding FunBind { fun_id=lname , fun_matches=MG {mg_alts=L _ matches} - } = Just (lname, matches) + } = Just (reLoc lname, matches) extractNameAndMatchesFromFunBind _ = Nothing findRelatedSigSpan :: PositionIndexedString -> String -> RealSrcSpan -> Sig GhcPs -> [Range] @@ -462,16 +484,16 @@ suggestDeleteUnusedBinding let maybeIdx = findIndex (\(L _ id) -> isSameName id name) lnames in case maybeIdx of Nothing -> Nothing - Just _ | length lnames == 1 -> Just (getLoc $ head lnames, True) + Just _ | length lnames == 1 -> Just (getLoc $ reLoc $ head lnames, True) Just idx -> - let targetLname = getLoc $ lnames !! idx + let targetLname = getLoc $ reLoc $ lnames !! idx startLoc = srcSpanStart targetLname endLoc = srcSpanEnd targetLname startLoc' = if idx == 0 then startLoc - else srcSpanEnd . getLoc $ lnames !! (idx - 1) + else srcSpanEnd . getLoc . reLoc $ lnames !! (idx - 1) endLoc' = if idx == 0 && idx < length lnames - 1 - then srcSpanStart . getLoc $ lnames !! (idx + 1) + then srcSpanStart . getLoc . reLoc $ lnames !! (idx + 1) else endLoc in Just (mkSrcSpan startLoc' endLoc', False) findRelatedSigSpan1 _ _ = Nothing @@ -486,12 +508,19 @@ suggestDeleteUnusedBinding indexedContent name (L _ Match{m_grhss=GRHSs{grhssLocalBinds}}) = do + let go bag lsigs = + if isEmptyBag bag + then [] + else concatMap (findRelatedSpanForHsBind indexedContent name lsigs) bag +#if !MIN_VERSION_ghc(9,2,0) case grhssLocalBinds of - (L _ (HsValBinds _ (ValBinds _ bag lsigs))) -> - if isEmptyBag bag - then [] - else concatMap (findRelatedSpanForHsBind indexedContent name lsigs) bag - _ -> [] + (L _ (HsValBinds _ (ValBinds _ bag lsigs))) -> go bag lsigs + _ -> [] +#else + case grhssLocalBinds of + (HsValBinds _ (ValBinds _ bag lsigs)) -> go bag lsigs + _ -> [] +#endif findRelatedSpanForMatch _ _ _ = [] findRelatedSpanForHsBind @@ -504,12 +533,12 @@ suggestDeleteUnusedBinding indexedContent name lsigs - (L (RealSrcSpan l _) (extractNameAndMatchesFromFunBind -> Just (lname, matches))) = + (L (locA -> (RealSrcSpan l _)) (extractNameAndMatchesFromFunBind -> Just (lname, matches))) = if isTheBinding (getLoc lname) then let findSig (L (RealSrcSpan l _) sig) = findRelatedSigSpan indexedContent name l sig findSig _ = [] - in extendForSpaces indexedContent (toRange l) : concatMap findSig lsigs + in extendForSpaces indexedContent (toRange l) : concatMap (findSig . reLoc) lsigs else concatMap (findRelatedSpanForMatch indexedContent name) matches findRelatedSpanForHsBind _ _ _ _ = [] @@ -536,11 +565,11 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul <|> matchRegexUnifySpaces _message ".*Defined but not used: data constructor ‘([^ ]+)’" , Just (exportType, _) <- find (matchWithDiagnostic _range . snd) . mapMaybe - (\(L l b) -> if maybe False isTopLevel $ srcSpanToRange l + (\(L (locA -> l) b) -> if maybe False isTopLevel $ srcSpanToRange l then exportsAs b else Nothing) $ hsmodDecls - , Just pos <- fmap _end . getLocatedRange =<< hsmodExports - , Just needComma <- needsComma source <$> hsmodExports + , Just pos <- (fmap _end . getLocatedRange) . reLoc =<< hsmodExports + , Just needComma <- needsComma source <$> fmap reLoc hsmodExports , let exportName = (if needComma then ", " else "") <> printExport exportType name insertPos = pos {_character = pred $ _character pos} = [("Export ‘" <> name <> "’", TextEdit (Range insertPos insertPos) exportName)] @@ -551,7 +580,7 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul needsComma _ (L _ []) = False needsComma source (L (RealSrcSpan l _) exports) = let closeParan = _end $ realSrcSpanToRange l - lastExport = fmap _end . getLocatedRange $ last exports + lastExport = fmap _end . getLocatedRange $ last $ fmap reLoc exports in case lastExport of Just lastExport -> not $ T.isInfixOf "," $ textInRange (Range lastExport closeParan) source _ -> False @@ -578,13 +607,13 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul isTopLevel :: Range -> Bool isTopLevel l = (_character . _start) l == 0 - exportsAs :: HsDecl p -> Maybe (ExportsAs, Located (IdP p)) - exportsAs (ValD _ FunBind {fun_id}) = Just (ExportName, fun_id) - exportsAs (ValD _ (PatSynBind _ PSB {psb_id})) = Just (ExportPattern, psb_id) - exportsAs (TyClD _ SynDecl{tcdLName}) = Just (ExportName, tcdLName) - exportsAs (TyClD _ DataDecl{tcdLName}) = Just (ExportAll, tcdLName) - exportsAs (TyClD _ ClassDecl{tcdLName}) = Just (ExportAll, tcdLName) - exportsAs (TyClD _ FamDecl{tcdFam}) = Just (ExportAll, fdLName tcdFam) + exportsAs :: HsDecl GhcPs -> Maybe (ExportsAs, Located (IdP GhcPs)) + exportsAs (ValD _ FunBind {fun_id}) = Just (ExportName, reLoc fun_id) + exportsAs (ValD _ (PatSynBind _ PSB {psb_id})) = Just (ExportPattern, reLoc psb_id) + exportsAs (TyClD _ SynDecl{tcdLName}) = Just (ExportName, reLoc tcdLName) + exportsAs (TyClD _ DataDecl{tcdLName}) = Just (ExportAll, reLoc tcdLName) + exportsAs (TyClD _ ClassDecl{tcdLName}) = Just (ExportAll, reLoc tcdLName) + exportsAs (TyClD _ FamDecl{tcdFam}) = Just (ExportAll, reLoc $ fdLName tcdFam) exportsAs _ = Nothing suggestAddTypeAnnotationToSatisfyContraints :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])] @@ -677,7 +706,7 @@ newDefinitionAction :: IdeOptions -> ParsedModule -> Range -> T.Text -> T.Text - newDefinitionAction IdeOptions{..} parsedModule Range{_start} name typ | Range _ lastLineP : _ <- [ realSrcSpanToRange sp - | (L l@(RealSrcSpan sp _) _) <- hsmodDecls + | (L (locA -> l@(RealSrcSpan sp _)) _) <- hsmodDecls , _start `isInsideSrcSpan` l] , nextLineP <- Position{ _line = _line lastLineP + 1, _character = 0} = [ ("Define " <> sig @@ -725,8 +754,8 @@ suggestModuleTypo Diagnostic{_range=_range,..} where extractModule line = case T.words line of [modul, "(from", _] -> Just modul - _ -> Nothing - + _ -> Nothing + suggestFillHole :: Diagnostic -> [(T.Text, TextEdit)] suggestFillHole Diagnostic{_range=_range,..} @@ -864,12 +893,10 @@ data HidingMode Bool -- ^ Parenthesised? ModuleName - deriving (Show) data ModuleTarget = ExistingImp (NonEmpty (LImportDecl GhcPs)) | ImplicitPrelude [LImportDecl GhcPs] - deriving (Show) targetImports :: ModuleTarget -> [LImportDecl GhcPs] targetImports (ExistingImp ne) = NE.toList ne @@ -1022,13 +1049,13 @@ disambiguateSymbol pm fileContents Diagnostic {..} (T.unpack -> symbol) = \case liftParseAST @(HsExpr GhcPs) df $ prettyPrint $ HsVar @GhcPs noExtField $ - L (mkGeneralSrcSpan "") rdr + reLocA $ L (mkGeneralSrcSpan "") rdr else Rewrite (rangeToSrcSpan "" _range) $ \df -> liftParseAST @RdrName df $ prettyPrint $ L (mkGeneralSrcSpan "") rdr ] findImportDeclByRange :: [LImportDecl GhcPs] -> Range -> Maybe (LImportDecl GhcPs) -findImportDeclByRange xs range = find (\(L l _)-> srcSpanToRange l == Just range) xs +findImportDeclByRange xs range = find (\(L (locA -> l) _)-> srcSpanToRange l == Just range) xs suggestFixConstructorImport :: Diagnostic -> [(T.Text, TextEdit)] suggestFixConstructorImport Diagnostic{_range=_range,..} @@ -1043,9 +1070,10 @@ suggestFixConstructorImport Diagnostic{_range=_range,..} = let fixedImport = typ <> "(" <> constructor <> ")" in [("Fix import of " <> fixedImport, TextEdit _range fixedImport)] | otherwise = [] + -- | Suggests a constraint for a declaration for which a constraint is missing. suggestConstraint :: DynFlags -> ParsedSource -> Diagnostic -> [(T.Text, Rewrite)] -suggestConstraint df parsedModule diag@Diagnostic {..} +suggestConstraint df (makeDeltaAst -> parsedModule) diag@Diagnostic {..} | Just missingConstraint <- findMissingConstraint _message = let codeAction = if _message =~ ("the type signature for:" :: String) then suggestFunctionConstraint df parsedModule @@ -1090,7 +1118,11 @@ suggestInstanceConstraint df (L _ HsModule {hsmodDecls}) Diagnostic {..} missing -- (Pair x x') == (Pair y y') = x == y && x' == y' | Just [instanceLineStr, constraintFirstCharStr] <- matchRegexUnifySpaces _message "bound by the instance declaration at .+:([0-9]+):([0-9]+)" +#if !MIN_VERSION_ghc(9,2,0) , Just (L _ (InstD _ (ClsInstD _ ClsInstDecl {cid_poly_ty = HsIB{hsib_body}}))) +#else + , Just (L _ (InstD _ (ClsInstD _ ClsInstDecl {cid_poly_ty = (unLoc -> HsSig{sig_body = hsib_body})}))) +#endif <- findDeclContainingLoc (Position (readPositionNumber instanceLineStr) (readPositionNumber constraintFirstCharStr)) hsmodDecls = Just hsib_body | otherwise @@ -1110,7 +1142,12 @@ suggestImplicitParameter :: suggestImplicitParameter (L _ HsModule {hsmodDecls}) Diagnostic {_message, _range} | Just [implicitT] <- matchRegexUnifySpaces _message "Unbound implicit parameter \\(([^:]+::.+)\\) arising", Just (L _ (ValD _ FunBind {fun_id = L _ funId})) <- findDeclContainingLoc (_start _range) hsmodDecls, - Just (TypeSig _ _ HsWC {hswc_body = HsIB {hsib_body}}) <- findSigOfDecl (== funId) hsmodDecls +#if !MIN_VERSION_ghc(9,2,0) + Just (TypeSig _ _ HsWC {hswc_body = HsIB {hsib_body}}) +#else + Just (TypeSig _ _ HsWC {hswc_body = (unLoc -> HsSig {sig_body = hsib_body})}) +#endif + <- findSigOfDecl (== funId) hsmodDecls = [( "Add " <> implicitT <> " to the context of " <> T.pack (printRdrName funId) , appendConstraint (T.unpack implicitT) hsib_body)] @@ -1145,7 +1182,11 @@ suggestFunctionConstraint df (L _ HsModule {hsmodDecls}) Diagnostic {..} missing -- In an equation for ‘eq’: -- eq (Pair x y) (Pair x' y') = x == x' && y == y' | Just typeSignatureName <- findTypeSignatureName _message +#if !MIN_VERSION_ghc(9,2,0) , Just (TypeSig _ _ HsWC{hswc_body = HsIB {hsib_body = sig}}) +#else + , Just (TypeSig _ _ HsWC{hswc_body = (unLoc -> HsSig {sig_body = sig})}) +#endif <- findSigOfDecl ((T.unpack typeSignatureName ==) . showSDoc df . ppr) hsmodDecls , title <- actionTitle missingConstraint typeSignatureName = [(title, appendConstraint (T.unpack missingConstraint) sig)] @@ -1168,8 +1209,12 @@ removeRedundantConstraints df (L _ HsModule {hsmodDecls}) Diagnostic{..} -- Account for both "Redundant constraint" and "Redundant constraints". | "Redundant constraint" `T.isInfixOf` _message , Just typeSignatureName <- findTypeSignatureName _message +#if !MIN_VERSION_ghc(9,2,0) , Just (TypeSig _ _ HsWC{hswc_body = HsIB {hsib_body = sig}}) - <- findSigOfDeclRanged _range hsmodDecls +#else + , Just (TypeSig _ _ HsWC{hswc_body = (unLoc -> HsSig {sig_body = sig})}) +#endif + <- fmap(traceAst "redundantConstraint") $ findSigOfDeclRanged _range hsmodDecls , Just redundantConstraintList <- findRedundantConstraints _message , rewrite <- removeConstraint (toRemove df redundantConstraintList) sig = [(actionTitle redundantConstraintList typeSignatureName, rewrite)] @@ -1188,12 +1233,23 @@ removeRedundantConstraints df (L _ HsModule {hsmodDecls}) Diagnostic{..} then constraints & T.drop 1 & T.dropEnd 1 & T.strip else constraints +{- +9.2: "message": "/private/var/folders/4m/d38fhm3936x_gy_9883zbq8h0000gn/T/extra-dir-53173393699/Testing.hs:4:1: warning: + ⢠Redundant constraints: (Eq a, Show a) + ⢠In the type signature for: + foo :: forall a. (Eq a, Show a) => a -> Bool", + +9.0: "message": "⢠Redundant constraints: (Eq a, Show a) + ⢠In the type signature for: + foo :: forall a. (Eq a, Show a) => a -> Bool", +-} findRedundantConstraints :: T.Text -> Maybe [T.Text] findRedundantConstraints t = t & T.lines - & head - & T.strip - & (`matchRegexUnifySpaces` "Redundant constraints?: (.+)") + -- In <9.2 it's the first line, in 9.2 it' the second line + & take 2 + & mapMaybe ((`matchRegexUnifySpaces` "Redundant constraints?: (.+)") . T.strip) + & listToMaybe <&> (head >>> parseConstraints) formatConstraints :: [T.Text] -> T.Text @@ -1307,8 +1363,8 @@ newImportToEdit (unNewImport -> imp) ps fileContents newImportInsertRange :: ParsedSource -> T.Text -> Maybe (Range, Int) newImportInsertRange (L _ HsModule {..}) fileContents | Just ((l, c), col) <- case hsmodImports of - [] -> findPositionNoImports hsmodName hsmodExports fileContents - _ -> findPositionFromImportsOrModuleDecl hsmodImports last True + [] -> findPositionNoImports (fmap reLoc hsmodName) (fmap reLoc hsmodExports) fileContents + _ -> findPositionFromImportsOrModuleDecl (map reLoc hsmodImports) last True , let insertPos = Position (fromIntegral l) (fromIntegral c) = Just (Range insertPos insertPos, col) | otherwise = Nothing @@ -1551,22 +1607,35 @@ smallerRangesForBindingExport lies b = where unqualify = snd . breakOnEnd "." b' = wrapOperatorInParens . unqualify $ b +#if !MIN_VERSION_ghc(9,2,0) ranges' (L _ (IEThingWith _ thing _ inners labels)) | showSDocUnsafe (ppr thing) == b' = [] | otherwise = - [ l' | L l' x <- inners, showSDocUnsafe (ppr x) == b'] ++ - [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b'] + [ locA l' | L l' x <- inners, showSDocUnsafe (ppr x) == b'] + ++ [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b'] +#else + ranges' (L _ (IEThingWith _ thing _ inners)) + | showSDocUnsafe (ppr thing) == b' = [] + | otherwise = + [ locA l' | L l' x <- inners, showSDocUnsafe (ppr x) == b'] +#endif ranges' _ = [] rangesForBinding' :: String -> LIE GhcPs -> [SrcSpan] -rangesForBinding' b (L l x@IEVar{}) | showSDocUnsafe (ppr x) == b = [l] -rangesForBinding' b (L l x@IEThingAbs{}) | showSDocUnsafe (ppr x) == b = [l] -rangesForBinding' b (L l (IEThingAll _ x)) | showSDocUnsafe (ppr x) == b = [l] +rangesForBinding' b (L (locA -> l) x@IEVar{}) | showSDocUnsafe (ppr x) == b = [l] +rangesForBinding' b (L (locA -> l) x@IEThingAbs{}) | showSDocUnsafe (ppr x) == b = [l] +rangesForBinding' b (L (locA -> l) (IEThingAll _ x)) | showSDocUnsafe (ppr x) == b = [l] +#if !MIN_VERSION_ghc(9,2,0) rangesForBinding' b (L l (IEThingWith _ thing _ inners labels)) +#else +rangesForBinding' b (L (locA -> l) (IEThingWith _ thing _ inners)) +#endif | showSDocUnsafe (ppr thing) == b = [l] | otherwise = - [ l' | L l' x <- inners, showSDocUnsafe (ppr x) == b] ++ - [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b] + [ locA l' | L l' x <- inners, showSDocUnsafe (ppr x) == b] +#if !MIN_VERSION_ghc(9,2,0) + ++ [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b] +#endif rangesForBinding' _ _ = [] -- | 'matchRegex' combined with 'unifySpaces' diff --git a/ghcide/src/Development/IDE/Plugin/CodeAction/Args.hs b/ghcide/src/Development/IDE/Plugin/CodeAction/Args.hs index 21f9fc5832..e5b606485b 100644 --- a/ghcide/src/Development/IDE/Plugin/CodeAction/Args.hs +++ b/ghcide/src/Development/IDE/Plugin/CodeAction/Args.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} module Development.IDE.Plugin.CodeAction.Args @@ -54,9 +55,10 @@ runGhcideCodeAction :: LSP.MonadLsp Config m => IdeState -> MessageParams TextDo runGhcideCodeAction state (CodeActionParams _ _ (TextDocumentIdentifier uri) _range CodeActionContext {_diagnostics = List diags}) codeAction = do let mbFile = toNormalizedFilePath' <$> uriToFilePath uri runRule key = runAction ("GhcideCodeActions." <> show key) state $ runMaybeT $ MaybeT (pure mbFile) >>= MaybeT . use key + caaGhcSession <- onceIO $ runRule GhcSession caaExportsMap <- onceIO $ - runRule GhcSession >>= \case + caaGhcSession >>= \case Just env -> do pkgExports <- envPackageExports env localExports <- readTVarIO (exportsMap $ shakeExtras state) @@ -117,8 +119,12 @@ instance ToTextEdit Rewrite where toTextEdit CodeActionArgs {..} rw = fmap (fromMaybe []) $ runMaybeT $ do df <- MaybeT caaDf +#if !MIN_VERSION_ghc(9,2,0) ps <- MaybeT caaAnnSource let r = rewriteToEdit df (annsA ps) rw +#else + let r = rewriteToEdit df rw +#endif pure $ fromRight [] r instance ToTextEdit a => ToTextEdit [a] where @@ -134,11 +140,16 @@ instance (ToTextEdit a, ToTextEdit b) => ToTextEdit (Either a b) where data CodeActionArgs = CodeActionArgs { caaExportsMap :: IO ExportsMap, + caaGhcSession :: IO (Maybe HscEnvEq), caaIdeOptions :: IO IdeOptions, caaParsedModule :: IO (Maybe ParsedModule), caaContents :: IO (Maybe T.Text), caaDf :: IO (Maybe DynFlags), +#if !MIN_VERSION_ghc(9,2,0) caaAnnSource :: IO (Maybe (Annotated ParsedSource)), +#else + caaAnnSource :: IO (Maybe ParsedSource), +#endif caaTmr :: IO (Maybe TcModuleResult), caaHar :: IO (Maybe HieAstResult), caaBindings :: IO (Maybe Bindings), @@ -205,10 +216,15 @@ toCodeAction2 get f = ReaderT $ \caa -> toCodeAction3 :: (ToCodeAction r) => (CodeActionArgs -> IO a) -> (a -> r) -> GhcideCodeAction toCodeAction3 get f = ReaderT $ \caa -> get caa >>= flip runReaderT caa . toCodeAction . f +-- | this instance returns a delta AST, useful for exactprint transforms instance ToCodeAction r => ToCodeAction (ParsedSource -> r) where toCodeAction f = ReaderT $ \caa@CodeActionArgs {caaAnnSource = x} -> x >>= \case +#if !MIN_VERSION_ghc(9,2,0) Just s -> flip runReaderT caa . toCodeAction . f . astA $ s +#else + Just s -> flip runReaderT caa . toCodeAction . f $ s +#endif _ -> pure [] instance ToCodeAction r => ToCodeAction (ExportsMap -> r) where @@ -238,11 +254,17 @@ instance ToCodeAction r => ToCodeAction (Maybe DynFlags -> r) where instance ToCodeAction r => ToCodeAction (DynFlags -> r) where toCodeAction = toCodeAction2 caaDf +#if !MIN_VERSION_ghc(9,2,0) instance ToCodeAction r => ToCodeAction (Maybe (Annotated ParsedSource) -> r) where toCodeAction = toCodeAction1 caaAnnSource instance ToCodeAction r => ToCodeAction (Annotated ParsedSource -> r) where toCodeAction = toCodeAction2 caaAnnSource +#else +-- | this instance returns a delta AST, useful for exactprint transforms +instance ToCodeAction r => ToCodeAction (Maybe ParsedSource -> r) where + toCodeAction = toCodeAction1 caaAnnSource +#endif instance ToCodeAction r => ToCodeAction (Maybe TcModuleResult -> r) where toCodeAction = toCodeAction1 caaTmr @@ -267,3 +289,9 @@ instance ToCodeAction r => ToCodeAction (Maybe GlobalBindingTypeSigsResult -> r) instance ToCodeAction r => ToCodeAction (GlobalBindingTypeSigsResult -> r) where toCodeAction = toCodeAction2 caaGblSigs + +instance ToCodeAction r => ToCodeAction (Maybe HscEnvEq -> r) where + toCodeAction = toCodeAction1 caaGhcSession + +instance ToCodeAction r => ToCodeAction (Maybe HscEnv -> r) where + toCodeAction = toCodeAction1 ((fmap.fmap.fmap) hscEnv caaGhcSession) diff --git a/ghcide/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs b/ghcide/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs index b79775c8c4..9810cf98d5 100644 --- a/ghcide/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs +++ b/ghcide/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs @@ -2,12 +2,16 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleInstances #-} module Development.IDE.Plugin.CodeAction.ExactPrint ( Rewrite (..), rewriteToEdit, rewriteToWEdit, +#if !MIN_VERSION_ghc(9,2,0) transferAnn, +#endif -- * Utilities appendConstraint, @@ -30,16 +34,28 @@ import Data.Maybe (fromJust, isNothing, mapMaybe) import qualified Data.Text as T import Development.IDE.GHC.Compat -import qualified Development.IDE.GHC.Compat.Util as Util import Development.IDE.GHC.Error -import Development.IDE.GHC.ExactPrint (ASTElement (parseAST), - Annotate) +import Development.IDE.GHC.ExactPrint import Development.IDE.Spans.Common import GHC.Exts (IsList (fromList)) import Language.Haskell.GHC.ExactPrint +#if !MIN_VERSION_ghc(9,2,0) +import qualified Development.IDE.GHC.Compat.Util as Util import Language.Haskell.GHC.ExactPrint.Types (DeltaPos (DP), KeywordId (G), mkAnnKey) +#else +import Data.Default +import GHC (AddEpAnn (..), AnnContext (..), AnnParen (..), + DeltaPos (SameLine), EpAnn (..), EpaLocation (EpaDelta), + IsUnicodeSyntax (NormalSyntax), + NameAdornment (NameParens), NameAnn (..), addAnns, ann, emptyComments, + reAnnL, AnnList (..)) +#endif import Language.LSP.Types +import Development.IDE.GHC.Util +import Data.Bifunctor (first) +import Control.Lens (_head, _last, over) +import GHC.Stack (HasCallStack) ------------------------------------------------------------------------------ @@ -47,35 +63,83 @@ import Language.LSP.Types -- given 'ast'. data Rewrite where Rewrite :: +#if !MIN_VERSION_ghc(9,2,0) Annotate ast => +#else + (ExactPrint (GenLocated (Anno ast) ast), ResetEntryDP (Anno ast), Outputable (GenLocated (Anno ast) ast), Data (GenLocated (Anno ast) ast)) => +#endif -- | The 'SrcSpan' that we want to rewrite SrcSpan -> -- | The ast that we want to graft +#if !MIN_VERSION_ghc(9,2,0) (DynFlags -> TransformT (Either String) (Located ast)) -> +#else + (DynFlags -> TransformT (Either String) (GenLocated (Anno ast) ast)) -> +#endif Rewrite ------------------------------------------------------------------------------ +#if MIN_VERSION_ghc(9,2,0) +class ResetEntryDP ann where + resetEntryDP :: GenLocated ann ast -> GenLocated ann ast +instance {-# OVERLAPPING #-} Default an => ResetEntryDP (SrcAnn an) where + -- resetEntryDP = flip setEntryDP (SameLine 0) + resetEntryDP (L srcAnn x) = setEntryDP (L srcAnn{ann=EpAnnNotUsed} x) (SameLine 0) +instance {-# OVERLAPPABLE #-} ResetEntryDP fallback where + resetEntryDP = id +#endif -- | Convert a 'Rewrite' into a list of '[TextEdit]'. -rewriteToEdit :: +rewriteToEdit :: HasCallStack => DynFlags -> +#if !MIN_VERSION_ghc(9,2,0) Anns -> +#endif Rewrite -> Either String [TextEdit] -rewriteToEdit dflags anns (Rewrite dst f) = do - (ast, (anns, _), _) <- runTransformT anns $ do +rewriteToEdit dflags +#if !MIN_VERSION_ghc(9,2,0) + anns +#endif + (Rewrite dst f) = do + (ast, anns , _) <- runTransformT +#if !MIN_VERSION_ghc(9,2,0) + anns +#endif + $ do ast <- f dflags +#if !MIN_VERSION_ghc(9,2,0) ast <$ setEntryDPT ast (DP (0, 0)) +#else + pure $ traceAst "REWRITE_result" $ resetEntryDP ast +#endif let editMap = [ TextEdit (fromJust $ srcSpanToRange dst) $ - T.pack $ exactPrint ast anns + T.pack $ exactPrint ast +#if !MIN_VERSION_ghc(9,2,0) + (fst anns) +#endif ] pure editMap -- | Convert a 'Rewrite' into a 'WorkspaceEdit' -rewriteToWEdit :: DynFlags -> Uri -> Anns -> Rewrite -> Either String WorkspaceEdit -rewriteToWEdit dflags uri anns r = do - edits <- rewriteToEdit dflags anns r +rewriteToWEdit :: DynFlags + -> Uri +#if !MIN_VERSION_ghc(9,2,0) + -> Anns +#endif + -> Rewrite + -> Either String WorkspaceEdit +rewriteToWEdit dflags uri +#if !MIN_VERSION_ghc(9,2,0) + anns +#endif + r = do + edits <- rewriteToEdit dflags +#if !MIN_VERSION_ghc(9,2,0) + anns +#endif + r return $ WorkspaceEdit { _changes = Just (fromList [(uri, List edits)]) @@ -85,16 +149,20 @@ rewriteToWEdit dflags uri anns r = do ------------------------------------------------------------------------------ +#if !MIN_VERSION_ghc(9,2,0) -- | Fix the parentheses around a type context fixParens :: - (Monad m, Data (HsType pass)) => + (Monad m, Data (HsType pass), pass ~ GhcPass p0) => Maybe DeltaPos -> Maybe DeltaPos -> LHsContext pass -> TransformT m [LHsType pass] -fixParens openDP closeDP ctxt@(L _ elems) = do +fixParens + openDP closeDP + ctxt@(L _ elems) = do -- Paren annotation for type contexts are usually quite screwed up -- we remove duplicates and fix negative DPs + let parens = Map.fromList [(G AnnOpenP, dp00), (G AnnCloseP, dp00)] modifyAnnsT $ Map.adjust ( \x -> @@ -109,28 +177,44 @@ fixParens openDP closeDP ctxt@(L _ elems) = do ) (mkAnnKey ctxt) return $ map dropHsParTy elems - where - parens = Map.fromList [(G AnnOpenP, dp00), (G AnnCloseP, dp00)] +#endif - dropHsParTy :: LHsType pass -> LHsType pass - dropHsParTy (L _ (HsParTy _ ty)) = ty - dropHsParTy other = other +dropHsParTy :: LHsType (GhcPass pass) -> LHsType (GhcPass pass) +dropHsParTy (L _ (HsParTy _ ty)) = ty +dropHsParTy other = other removeConstraint :: -- | Predicate: Which context to drop. (LHsType GhcPs -> Bool) -> LHsType GhcPs -> Rewrite -removeConstraint toRemove = go +removeConstraint toRemove = go . traceAst "REMOVE_CONSTRAINT_input" where - go (L l it@HsQualTy{hst_ctxt = L l' ctxt, hst_body}) = Rewrite l $ \_ -> do - let ctxt' = L l' $ filter (not . toRemove) ctxt - when ((toRemove <$> headMaybe ctxt) == Just True) $ + go :: LHsType GhcPs -> Rewrite +#if !MIN_VERSION_ghc(9,2,0) + go (L l it@HsQualTy{hst_ctxt = L l' ctxt, hst_body}) = Rewrite (locA l) $ \_ -> do +#else + go (L l it@HsQualTy{hst_ctxt = Just (L l' ctxt), hst_body}) = Rewrite (locA l) $ \_ -> do +#endif + let ctxt' = filter (not . toRemove) ctxt + removeStuff = (toRemove <$> headMaybe ctxt) == Just True +#if !MIN_VERSION_ghc(9,2,0) + when removeStuff $ setEntryDPT hst_body (DP (0, 0)) - return $ L l $ it{hst_ctxt = ctxt'} + return $ L l $ it{hst_ctxt = L l' ctxt'} +#else + let hst_body' = if removeStuff then resetEntryDP hst_body else hst_body + return $ case ctxt' of + [] -> hst_body' + _ -> do + let ctxt'' = over _last (first removeComma) ctxt' + L l $ it{ hst_ctxt = Just $ L l' ctxt'' + , hst_body = hst_body' + } +#endif go (L _ (HsParTy _ ty)) = go ty go (L _ HsForAllTy{hst_body}) = go hst_body - go (L l other) = Rewrite l $ \_ -> return $ L l other + go (L l other) = Rewrite (locA l) $ \_ -> return $ L l other -- | Append a constraint at the end of a type context. -- If no context is present, a new one will be created. @@ -140,30 +224,47 @@ appendConstraint :: -- | The type signature where the constraint is to be inserted, also assuming annotated LHsType GhcPs -> Rewrite -appendConstraint constraintT = go +appendConstraint constraintT = go . traceAst "appendConstraint" where - go (L l it@HsQualTy{hst_ctxt = L l' ctxt}) = Rewrite l $ \df -> do +#if !MIN_VERSION_ghc(9,2,0) + go (L l it@HsQualTy{hst_ctxt = L l' ctxt}) = Rewrite (locA l) $ \df -> do +#else + go (L l it@HsQualTy{hst_ctxt = Just (L l' ctxt)}) = Rewrite (locA l) $ \df -> do +#endif constraint <- liftParseAST df constraintT +#if !MIN_VERSION_ghc(9,2,0) setEntryDPT constraint (DP (0, 1)) -- Paren annotations are usually attached to the first and last constraints, -- rather than to the constraint list itself, so to preserve them we need to reposition them closeParenDP <- lookupAnn (G AnnCloseP) `mapM` lastMaybe ctxt openParenDP <- lookupAnn (G AnnOpenP) `mapM` headMaybe ctxt - ctxt' <- fixParens (join openParenDP) (join closeParenDP) (L l' ctxt) - + ctxt' <- fixParens + (join openParenDP) (join closeParenDP) + (L l' ctxt) addTrailingCommaT (last ctxt') - return $ L l $ it{hst_ctxt = L l' $ ctxt' ++ [constraint]} +#else + constraint <- pure $ setEntryDP constraint (SameLine 1) + let l'' = (fmap.fmap) (addParensToCtxt close_dp) l' + -- For singleton constraints, the close Paren DP is attached to an HsPar wrapping the constraint + -- we have to reposition it manually into the AnnContext + close_dp = case ctxt of + [L _ (HsParTy EpAnn{anns=AnnParen{ap_close}} _)] -> Just ap_close + _ -> Nothing + ctxt' = over _last (first addComma) $ map dropHsParTy ctxt + return $ L l $ it{hst_ctxt = Just $ L l'' $ ctxt' ++ [constraint]} +#endif go (L _ HsForAllTy{hst_body}) = go hst_body go (L _ (HsParTy _ ty)) = go ty - go (L l other) = Rewrite l $ \df -> do + go ast@(L l _) = Rewrite (locA l) $ \df -> do -- there isn't a context, so we must create one constraint <- liftParseAST df constraintT lContext <- uniqueSrcSpanT lTop <- uniqueSrcSpanT +#if !MIN_VERSION_ghc(9,2,0) let context = L lContext [constraint] - addSimpleAnnT context (DP (0, 0)) $ + addSimpleAnnT context dp00 $ (G AnnDarrow, DP (0, 1)) : concat [ [ (G AnnOpenP, dp00) @@ -171,14 +272,29 @@ appendConstraint constraintT = go ] | hsTypeNeedsParens sigPrec $ unLoc constraint ] - return $ L lTop $ HsQualTy noExtField context (L l other) - -liftParseAST :: ASTElement ast => DynFlags -> String -> TransformT (Either String) (Located ast) +#else + let context = Just $ reAnnL annCtxt emptyComments $ L lContext [resetEntryDP constraint] + annCtxt = AnnContext (Just (NormalSyntax, epl 1)) [epl 0 | needsParens] [epl 0 | needsParens] + needsParens = hsTypeNeedsParens sigPrec $ unLoc constraint + ast <- pure $ setEntryDP ast (SameLine 1) +#endif + + return $ reLocA $ L lTop $ HsQualTy noExtField context ast + +liftParseAST + :: forall ast l. (ASTElement l ast, ExactPrint (LocatedAn l ast)) + => DynFlags -> String -> TransformT (Either String) (LocatedAn l ast) liftParseAST df s = case parseAST df "" s of +#if !MIN_VERSION_ghc(9,2,0) Right (anns, x) -> modifyAnnsT (anns <>) $> x +#else + Right x -> pure (makeDeltaAst x) +#endif Left _ -> lift $ Left $ "No parse: " <> s -lookupAnn :: (Data a, Monad m) => KeywordId -> Located a -> TransformT m (Maybe DeltaPos) +#if !MIN_VERSION_ghc(9,2,0) +lookupAnn :: (Data a, Monad m) + => KeywordId -> Located a -> TransformT m (Maybe DeltaPos) lookupAnn comment la = do anns <- getAnnsT return $ Map.lookup (mkAnnKey la) anns >>= lookup comment . annsDP @@ -186,6 +302,17 @@ lookupAnn comment la = do dp00 :: DeltaPos dp00 = DP (0, 0) +-- | Copy anns attached to a into b with modification, then delete anns of a +transferAnn :: (Data a, Data b) => Located a -> Located b -> (Annotation -> Annotation) -> TransformT (Either String) () +transferAnn la lb f = do + anns <- getAnnsT + let oldKey = mkAnnKey la + newKey = mkAnnKey lb + oldValue <- liftMaybe "Unable to find ann" $ Map.lookup oldKey anns + putAnnsT $ Map.delete oldKey $ Map.insert newKey (f oldValue) anns + +#endif + headMaybe :: [a] -> Maybe a headMaybe [] = Nothing headMaybe (a : _) = Just a @@ -198,24 +325,15 @@ liftMaybe :: String -> Maybe a -> TransformT (Either String) a liftMaybe _ (Just x) = return x liftMaybe s _ = lift $ Left s --- | Copy anns attached to a into b with modification, then delete anns of a -transferAnn :: (Data a, Data b) => Located a -> Located b -> (Annotation -> Annotation) -> TransformT (Either String) () -transferAnn la lb f = do - anns <- getAnnsT - let oldKey = mkAnnKey la - newKey = mkAnnKey lb - oldValue <- liftMaybe "Unable to find ann" $ Map.lookup oldKey anns - putAnnsT $ Map.delete oldKey $ Map.insert newKey (f oldValue) anns - ------------------------------------------------------------------------------ extendImport :: Maybe String -> String -> LImportDecl GhcPs -> Rewrite extendImport mparent identifier lDecl@(L l _) = - Rewrite l $ \df -> do + Rewrite (locA l) $ \df -> do case mparent of Just parent -> extendImportViaParent df parent identifier lDecl _ -> extendImportTopLevel identifier lDecl --- | Add an identifier or a data type to import list +-- | Add an identifier or a data type to import list. Expects a Delta AST -- -- extendImportTopLevel "foo" AST: -- @@ -232,19 +350,20 @@ extendImportTopLevel thing (L l it@ImportDecl{..}) , hasSibling <- not $ null lies = do src <- uniqueSrcSpanT top <- uniqueSrcSpanT - let rdr = L src $ mkRdrUnqual $ mkVarOcc thing - + let rdr = reLocA $ L src $ mkRdrUnqual $ mkVarOcc thing let alreadyImported = showNameWithoutUniques (occName (unLoc rdr)) `elem` map (showNameWithoutUniques @OccName) (listify (const True) lies) when alreadyImported $ lift (Left $ thing <> " already imported") - let lie = L src $ IEName rdr - x = L top $ IEVar noExtField lie + let lie = reLocA $ L src $ IEName rdr + x = reLocA $ L top $ IEVar noExtField lie + if x `elem` lies then lift (Left $ thing <> " already imported") else do +#if !MIN_VERSION_ghc(9,2,0) when hasSibling $ addTrailingCommaT (last lies) addSimpleAnnT x (DP (0, if hasSibling then 1 else 0)) [] @@ -254,6 +373,14 @@ extendImportTopLevel thing (L l it@ImportDecl{..}) unless hasSibling $ transferAnn (L l' lies) (L l' [x]) id return $ L l it{ideclHiding = Just (hide, L l' $ lies ++ [x])} +#else + + x <- pure $ setEntryDP x (SameLine $ if hasSibling then 1 else 0) + + let fixLast = if hasSibling then first addComma else id + lies' = over _last fixLast lies ++ [x] + return $ L l it{ideclHiding = Just (hide, L l' lies')} +#endif extendImportTopLevel _ _ = lift $ Left "Unable to extend the import list" -- | Add an identifier with its parent to import list @@ -277,39 +404,58 @@ extendImportViaParent :: extendImportViaParent df parent child (L l it@ImportDecl{..}) | Just (hide, L l' lies) <- ideclHiding = go hide l' [] lies where - go :: Bool -> SrcSpan -> [LIE GhcPs] -> [LIE GhcPs] -> TransformT (Either String) (LImportDecl GhcPs) go _hide _l' _pre ((L _ll' (IEThingAll _ (L _ ie))) : _xs) | parent == unIEWrappedName ie = lift . Left $ child <> " already included in " <> parent <> " imports" go hide l' pre (lAbs@(L ll' (IEThingAbs _ absIE@(L _ ie))) : xs) -- ThingAbs ie => ThingWith ie child | parent == unIEWrappedName ie = do srcChild <- uniqueSrcSpanT - let childRdr = L srcChild $ mkRdrUnqual $ mkVarOcc child - childLIE = L srcChild $ IEName childRdr + let childRdr = reLocA $ L srcChild $ mkRdrUnqual $ mkVarOcc child + childLIE = reLocA $ L srcChild $ IEName childRdr +#if !MIN_VERSION_ghc(9,2,0) x :: LIE GhcPs = L ll' $ IEThingWith noExtField absIE NoIEWildcard [childLIE] [] -- take anns from ThingAbs, and attatch parens to it transferAnn lAbs x $ \old -> old{annsDP = annsDP old ++ [(G AnnOpenP, DP (0, 1)), (G AnnCloseP, dp00)]} addSimpleAnnT childRdr dp00 [(G AnnVal, dp00)] +#else + x :: LIE GhcPs = L ll' $ IEThingWith (addAnns mempty [AddEpAnn AnnOpenP (EpaDelta (SameLine 1) []), AddEpAnn AnnCloseP def] emptyComments) absIE NoIEWildcard [childLIE] +#endif return $ L l it{ideclHiding = Just (hide, L l' $ reverse pre ++ [x] ++ xs)} +#if !MIN_VERSION_ghc(9,2,0) go hide l' pre ((L l'' (IEThingWith _ twIE@(L _ ie) _ lies' _)) : xs) +#else + go hide l' pre ((L l'' (IEThingWith l''' twIE@(L _ ie) _ lies')) : xs) +#endif -- ThingWith ie lies' => ThingWith ie (lies' ++ [child]) | parent == unIEWrappedName ie - , hasSibling <- not $ null lies' = + , hasSibling <- not $ null lies' = do srcChild <- uniqueSrcSpanT - let childRdr = L srcChild $ mkRdrUnqual $ mkVarOcc child - + let childRdr = reLocA $ L srcChild $ mkRdrUnqual $ mkVarOcc child +#if MIN_VERSION_ghc(9,2,0) + childRdr <- pure $ setEntryDP childRdr $ SameLine $ if hasSibling then 1 else 0 +#endif let alreadyImported = showNameWithoutUniques (occName (unLoc childRdr)) `elem` map (showNameWithoutUniques @OccName) (listify (const True) lies') when alreadyImported $ lift (Left $ child <> " already included in " <> parent <> " imports") + let childLIE = reLocA $ L srcChild $ IEName childRdr +#if !MIN_VERSION_ghc(9,2,0) when hasSibling $ addTrailingCommaT (last lies') - let childLIE = L srcChild $ IEName childRdr addSimpleAnnT childRdr (DP (0, if hasSibling then 1 else 0)) [(G AnnVal, dp00)] return $ L l it{ideclHiding = Just (hide, L l' $ reverse pre ++ [L l'' (IEThingWith noExtField twIE NoIEWildcard (lies' ++ [childLIE]) [])] ++ xs)} +#else + let it' = it{ideclHiding = Just (hide, lies)} + lies = L l' $ reverse pre ++ + [L l'' (IEThingWith l''' twIE NoIEWildcard (over _last fixLast lies' ++ [childLIE]))] ++ xs + fixLast = if hasSibling then first addComma else id + return $ if hasSibling + then L l it' + else L l it' +#endif go hide l' pre (x : xs) = go hide l' (x : pre) xs go hide l' pre [] | hasSibling <- not $ null pre = do @@ -318,13 +464,22 @@ extendImportViaParent df parent child (L l it@ImportDecl{..}) srcParent <- uniqueSrcSpanT srcChild <- uniqueSrcSpanT parentRdr <- liftParseAST df parent - let childRdr = L srcChild $ mkRdrUnqual $ mkVarOcc child + let childRdr = reLocA $ L srcChild $ mkRdrUnqual $ mkVarOcc child isParentOperator = hasParen parent +#if !MIN_VERSION_ghc(9,2,0) when hasSibling $ addTrailingCommaT (head pre) - let parentLIE = L srcParent $ (if isParentOperator then IEType else IEName) parentRdr - childLIE = L srcChild $ IEName childRdr - x :: LIE GhcPs = L l'' $ IEThingWith noExtField parentLIE NoIEWildcard [childLIE] [] + let parentLIE = L srcParent (if isParentOperator then IEType parentRdr else IEName parentRdr) + childLIE = reLocA $ L srcChild $ IEName childRdr +#else + let parentLIE = reLocA $ L srcParent $ (if isParentOperator then IEType (epl 0) parentRdr' else IEName parentRdr') + parentRdr' = modifyAnns parentRdr $ \case + it@NameAnn{nann_adornment = NameParens} -> it{nann_open = epl 1} + other -> other + childLIE = reLocA $ L srcChild $ IEName childRdr +#endif +#if !MIN_VERSION_ghc(9,2,0) + x :: LIE GhcPs = reLocA $ L l'' $ IEThingWith noExtField parentLIE NoIEWildcard [childLIE] [] -- Add AnnType for the parent if it's parenthesized (type operator) when isParentOperator $ addSimpleAnnT parentLIE (DP (0, 0)) [(G AnnType, DP (0, 0))] @@ -335,6 +490,10 @@ extendImportViaParent df parent child (L l it@ImportDecl{..}) -- we need change the ann key from `[]` to `:` to keep parens and other anns. unless hasSibling $ transferAnn (L l' $ reverse pre) (L l' [x]) id +#else + x :: LIE GhcPs = reLocA $ L l'' $ IEThingWith listAnn parentLIE NoIEWildcard [childLIE] + listAnn = epAnn srcParent [AddEpAnn AnnOpenP (epl 1), AddEpAnn AnnCloseP (epl 0)] +#endif return $ L l it{ideclHiding = Just (hide, L l' $ reverse pre ++ [x])} extendImportViaParent _ _ _ _ = lift $ Left "Unable to extend the import list via parent" @@ -345,6 +504,7 @@ hasParen :: String -> Bool hasParen ('(' : _) = True hasParen _ = False +#if !MIN_VERSION_ghc(9,2,0) unqalDP :: Int -> Bool -> [(KeywordId, DeltaPos)] unqalDP c paren = ( if paren @@ -352,6 +512,7 @@ unqalDP c paren = else pure ) (G AnnVal, dp00) +#endif ------------------------------------------------------------------------------ @@ -360,28 +521,52 @@ hideSymbol :: String -> LImportDecl GhcPs -> Rewrite hideSymbol symbol lidecl@(L loc ImportDecl{..}) = case ideclHiding of - Nothing -> Rewrite loc $ extendHiding symbol lidecl Nothing - Just (True, hides) -> Rewrite loc $ extendHiding symbol lidecl (Just hides) - Just (False, imports) -> Rewrite loc $ deleteFromImport symbol lidecl imports + Nothing -> Rewrite (locA loc) $ extendHiding symbol lidecl Nothing + Just (True, hides) -> Rewrite (locA loc) $ extendHiding symbol lidecl (Just hides) + Just (False, imports) -> Rewrite (locA loc) $ deleteFromImport symbol lidecl imports hideSymbol _ (L _ (XImportDecl _)) = error "cannot happen" extendHiding :: String -> LImportDecl GhcPs -> +#if !MIN_VERSION_ghc(9,2,0) Maybe (Located [LIE GhcPs]) -> +#else + Maybe (XRec GhcPs [LIE GhcPs]) -> +#endif DynFlags -> TransformT (Either String) (LImportDecl GhcPs) extendHiding symbol (L l idecls) mlies df = do L l' lies <- case mlies of +#if !MIN_VERSION_ghc(9,2,0) Nothing -> flip L [] <$> uniqueSrcSpanT +#else + Nothing -> do + src <- uniqueSrcSpanT + let ann = noAnnSrcSpanDP0 src + ann' = flip (fmap.fmap) ann $ \x -> x + {al_rest = [AddEpAnn AnnHiding (epl 1)] + ,al_open = Just $ AddEpAnn AnnOpenP (epl 1) + ,al_close = Just $ AddEpAnn AnnCloseP (epl 0) + } + return $ L ann' [] +#endif Just pr -> pure pr let hasSibling = not $ null lies src <- uniqueSrcSpanT top <- uniqueSrcSpanT rdr <- liftParseAST df symbol - let lie = L src $ IEName rdr - x = L top $ IEVar noExtField lie +#if MIN_VERSION_ghc(9,2,0) + rdr <- pure $ modifyAnns rdr $ addParens (isOperator $ unLoc rdr) +#endif + let lie = reLocA $ L src $ IEName rdr + x = reLocA $ L top $ IEVar noExtField lie +#if MIN_VERSION_ghc(9,2,0) + x <- pure $ if hasSibling then first addComma x else x + lies <- pure $ over _head (`setEntryDP` SameLine 1) lies +#endif +#if !MIN_VERSION_ghc(9,2,0) singleHide = L l' [x] when (isNothing mlies) $ do addSimpleAnnT @@ -394,13 +579,14 @@ extendHiding symbol (L l idecls) mlies df = do addSimpleAnnT x (DP (0, 0)) [] addSimpleAnnT rdr dp00 $ unqalDP 0 $ isOperator $ unLoc rdr if hasSibling - then when hasSibling $ do + then do addTrailingCommaT x addSimpleAnnT (head lies) (DP (0, 1)) [] unless (null $ tail lies) $ addTrailingCommaT (head lies) -- Why we need this? else forM_ mlies $ \lies0 -> do transferAnn lies0 singleHide id +#endif return $ L l idecls{ideclHiding = Just (True, L l' $ x : lies)} where isOperator = not . all isAlphaNum . occNameString . rdrNameOcc @@ -408,7 +594,11 @@ extendHiding symbol (L l idecls) mlies df = do deleteFromImport :: String -> LImportDecl GhcPs -> +#if !MIN_VERSION_ghc(9,2,0) Located [LIE GhcPs] -> +#else + XRec GhcPs [LIE GhcPs] -> +#endif DynFlags -> TransformT (Either String) (LImportDecl GhcPs) deleteFromImport (T.pack -> symbol) (L l idecl) llies@(L lieLoc lies) _ = do @@ -418,6 +608,7 @@ deleteFromImport (T.pack -> symbol) (L l idecl) llies@(L lieLoc lies) _ = do idecl { ideclHiding = Just (False, edited) } +#if !MIN_VERSION_ghc(9,2,0) -- avoid import A (foo,) whenJust (lastMaybe deletedLies) removeTrailingCommaT when (not (null lies) && null deletedLies) $ do @@ -428,9 +619,13 @@ deleteFromImport (T.pack -> symbol) (L l idecl) llies@(L lieLoc lies) _ = do [ (G AnnOpenP, DP (0, 1)) , (G AnnCloseP, DP (0, 0)) ] +#endif pure lidecl' where deletedLies = +#if MIN_VERSION_ghc(9,2,0) + over _last removeTrailingComma $ +#endif mapMaybe killLie lies killLie :: LIE GhcPs -> Maybe (LIE GhcPs) killLie v@(L _ (IEVar _ (L _ (unqualIEWrapName -> nam)))) @@ -439,7 +634,11 @@ deleteFromImport (T.pack -> symbol) (L l idecl) llies@(L lieLoc lies) _ = do killLie v@(L _ (IEThingAbs _ (L _ (unqualIEWrapName -> nam)))) | nam == symbol = Nothing | otherwise = Just v +#if !MIN_VERSION_ghc(9,2,0) killLie (L lieL (IEThingWith xt ty@(L _ (unqualIEWrapName -> nam)) wild cons flds)) +#else + killLie (L lieL (IEThingWith xt ty@(L _ (unqualIEWrapName -> nam)) wild cons)) +#endif | nam == symbol = Nothing | otherwise = Just $ @@ -449,5 +648,7 @@ deleteFromImport (T.pack -> symbol) (L l idecl) llies@(L lieLoc lies) _ = do ty wild (filter ((/= symbol) . unqualIEWrapName . unLoc) cons) +#if !MIN_VERSION_ghc(9,2,0) (filter ((/= symbol) . T.pack . Util.unpackFS . flLabel . unLoc) flds) +#endif killLie v = Just v diff --git a/ghcide/src/Development/IDE/Plugin/Completions.hs b/ghcide/src/Development/IDE/Plugin/Completions.hs index 0d54ec0f92..f29fc94ace 100644 --- a/ghcide/src/Development/IDE/Plugin/Completions.hs +++ b/ghcide/src/Development/IDE/Plugin/Completions.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} @@ -22,9 +23,7 @@ import Development.IDE.Core.Service import Development.IDE.Core.Shake import Development.IDE.GHC.Compat import Development.IDE.GHC.Error (rangeToSrcSpan) -import Development.IDE.GHC.ExactPrint (Annotated (annsA), - GetAnnotatedParsedSource (GetAnnotatedParsedSource), - astA) +import Development.IDE.GHC.ExactPrint (GetAnnotatedParsedSource (GetAnnotatedParsedSource)) import Development.IDE.GHC.Util (prettyPrint) import Development.IDE.Graph import Development.IDE.Plugin.CodeAction (newImport, @@ -85,7 +84,7 @@ produceCompletions = do _ -> return ([], Nothing) -- Drop any explicit imports in ImportDecl if not hidden -dropListFromImportDecl :: GenLocated SrcSpan (ImportDecl GhcPs) -> GenLocated SrcSpan (ImportDecl GhcPs) +dropListFromImportDecl :: LImportDecl GhcPs -> LImportDecl GhcPs dropListFromImportDecl iDecl = let f d@ImportDecl {ideclHiding} = case ideclHiding of Just (False, _) -> d {ideclHiding=Nothing} @@ -226,24 +225,35 @@ extendImportHandler' ideState ExtendImport {..} case existingImport of Just imp -> do fmap (nfp,) $ liftEither $ - rewriteToWEdit df doc (annsA ps) $ - extendImport (T.unpack <$> thingParent) (T.unpack newThing) imp + rewriteToWEdit df doc +#if !MIN_VERSION_ghc(9,2,0) + (annsA ps) +#endif + $ + extendImport (T.unpack <$> thingParent) (T.unpack newThing) (makeDeltaAst imp) Nothing -> do let n = newImport importName sym importQual False sym = if isNothing importQual then Just it else Nothing it = case thingParent of Nothing -> newThing Just p -> p <> "(" <> newThing <> ")" - t <- liftMaybe $ snd <$> newImportToEdit n (astA ps) (fromMaybe "" contents) + t <- liftMaybe $ snd <$> newImportToEdit + n +#if !MIN_VERSION_ghc(9,2,0) + (astA ps) +#else + ps +#endif + (fromMaybe "" contents) return (nfp, WorkspaceEdit {_changes=Just (fromList [(doc,List [t])]), _documentChanges=Nothing, _changeAnnotations=Nothing}) | otherwise = mzero -isWantedModule :: ModuleName -> Maybe ModuleName -> GenLocated l (ImportDecl pass) -> Bool +isWantedModule :: ModuleName -> Maybe ModuleName -> GenLocated l (ImportDecl GhcPs) -> Bool isWantedModule wantedModule Nothing (L _ it@ImportDecl{ideclName, ideclHiding = Just (False, _)}) = not (isQualifiedImport it) && unLoc ideclName == wantedModule isWantedModule wantedModule (Just qual) (L _ ImportDecl{ideclAs, ideclName, ideclHiding = Just (False, _)}) = - unLoc ideclName == wantedModule && (wantedModule == qual || (unLoc <$> ideclAs) == Just qual) + unLoc ideclName == wantedModule && (wantedModule == qual || (unLoc . reLoc <$> ideclAs) == Just qual) isWantedModule _ _ _ = False liftMaybe :: Monad m => Maybe a -> MaybeT m a diff --git a/ghcide/src/Development/IDE/Plugin/Completions/Logic.hs b/ghcide/src/Development/IDE/Plugin/Completions/Logic.hs index 4032f2bc41..df0cede535 100644 --- a/ghcide/src/Development/IDE/Plugin/Completions/Logic.hs +++ b/ghcide/src/Development/IDE/Plugin/Completions/Logic.hs @@ -35,7 +35,8 @@ import Data.Ord (Down (Down)) import qualified Data.Set as Set import Development.IDE.Core.Compile import Development.IDE.Core.PositionMapping -import Development.IDE.GHC.Compat as GHC hiding (ppr) +import Development.IDE.GHC.Compat hiding (ppr) +import qualified Development.IDE.GHC.Compat as GHC import Development.IDE.GHC.Compat.Util import Development.IDE.GHC.Error import Development.IDE.GHC.Util @@ -46,6 +47,15 @@ import Development.IDE.Spans.LocalBindings import Development.IDE.Types.Exports import Development.IDE.Types.HscEnvEq import Development.IDE.Types.Options + +#if MIN_VERSION_ghc(9,2,0) +import GHC.Plugins (Depth (AllTheWay), + defaultSDocContext, + mkUserStyle, + neverQualify, + renderWithContext, + sdocStyle) +#endif import Ide.PluginUtils (mkLspCommand) import Ide.Types (CommandId (..), PluginId) @@ -79,11 +89,11 @@ data Context = TypeContext -- i.e. where are the value decls and the type decls getCContext :: Position -> ParsedModule -> Maybe Context getCContext pos pm - | Just (L r modName) <- moduleHeader + | Just (L (locA -> r) modName) <- moduleHeader , pos `isInsideSrcSpan` r = Just (ModuleContext (moduleNameString modName)) - | Just (L r _) <- exportList + | Just (L (locA -> r) _) <- exportList , pos `isInsideSrcSpan` r = Just ExportContext @@ -102,23 +112,23 @@ getCContext pos pm imports = hsmodImports $ unLoc $ pm_parsed_source pm go :: LHsDecl GhcPs -> Maybe Context - go (L r SigD {}) + go (L (locA -> r) SigD {}) | pos `isInsideSrcSpan` r = Just TypeContext | otherwise = Nothing - go (L r GHC.ValD {}) + go (L (locA -> r) GHC.ValD {}) | pos `isInsideSrcSpan` r = Just ValueContext | otherwise = Nothing go _ = Nothing goInline :: GHC.LHsType GhcPs -> Maybe Context - goInline (GHC.L r _) + goInline (GHC.L (locA -> r) _) | pos `isInsideSrcSpan` r = Just TypeContext goInline _ = Nothing importGo :: GHC.LImportDecl GhcPs -> Maybe Context - importGo (L r impDecl) + importGo (L (locA -> r) impDecl) | pos `isInsideSrcSpan` r - = importInline importModuleName (ideclHiding impDecl) + = importInline importModuleName (fmap (fmap reLoc) $ ideclHiding impDecl) <|> Just (ImportContext importModuleName) | otherwise = Nothing @@ -254,9 +264,9 @@ mkNameCompItem doc thingParent origName provenance thingType isInfix docs !imp = (TyVarTy _) -> noParensSnippet (LitTy _) -> noParensSnippet (TyConApp _ []) -> noParensSnippet - _ -> snippetText i ("(" <> showGhc t <> ")") + _ -> snippetText i ("(" <> showForSnippet t <> ")") where - noParensSnippet = snippetText i (showGhc t) + noParensSnippet = snippetText i (showForSnippet t) snippetText i t = "${" <> T.pack (show i) <> ":" <> t <> "}" getArgs :: Type -> [Type] getArgs t @@ -277,6 +287,16 @@ mkNameCompItem doc thingParent origName provenance thingType isInfix docs !imp = #endif | otherwise = [] + +showForSnippet :: Outputable a => a -> T.Text +#if MIN_VERSION_ghc(9,2,0) +showForSnippet x = T.pack $ renderWithContext ctxt $ GHC.ppr x -- FIXme + where + ctxt = defaultSDocContext{sdocStyle = mkUserStyle neverQualify AllTheWay} +#else +showForSnippet x = showGhc x +#endif + mkModCompl :: T.Text -> CompletionItem mkModCompl label = CompletionItem label (Just CiModule) Nothing Nothing @@ -331,12 +351,12 @@ cacheDataProducer uri env curMod globalEnv inScopeEnv limports = do curModName = moduleName curMod curModNameText = ppr curModName - importMap = Map.fromList [ (l, imp) | imp@(L (RealSrcSpan l _) _) <- limports ] + importMap = Map.fromList [ (l, imp) | imp@(L (locA -> (RealSrcSpan l _)) _) <- limports ] - iDeclToModName :: ImportDecl name -> ModuleName + iDeclToModName :: ImportDecl GhcPs -> ModuleName iDeclToModName = unLoc . ideclName - asNamespace :: ImportDecl name -> ModuleName + asNamespace :: ImportDecl GhcPs -> ModuleName asNamespace imp = maybe (iDeclToModName imp) GHC.unLoc (ideclAs imp) -- Full canonical names of imported modules importDeclerations = map unLoc limports @@ -382,7 +402,9 @@ cacheDataProducer uri env curMod globalEnv inScopeEnv limports = do let (mbParent, originName) = case par of NoParent -> (Nothing, nameOccName n) ParentIs n' -> (Just . T.pack $ printName n', nameOccName n) +#if !MIN_VERSION_ghc(9,2,0) FldParent n' lbl -> (Just . T.pack $ printName n', maybe (nameOccName n) mkVarOccFS lbl) +#endif tys <- catchSrcErrors (hsc_dflags packageState) "completion" $ do name' <- lookupName packageState m n return ( name' >>= safeTyThingType @@ -431,7 +453,7 @@ localCompletionsForParsedModule uri pm@ParsedModule{pm_parsed_source = L _ HsMod compls = concat [ case decl of SigD _ (TypeSig _ ids typ) -> - [mkComp id CiFunction (Just $ ppr typ) | id <- ids] + [mkComp id CiFunction (Just $ showForSnippet typ) | id <- ids] ValD _ FunBind{fun_id} -> [ mkComp fun_id CiFunction Nothing | not (hasTypeSig fun_id) @@ -440,13 +462,13 @@ localCompletionsForParsedModule uri pm@ParsedModule{pm_parsed_source = L _ HsMod [mkComp id CiVariable Nothing | VarPat _ id <- listify (\(_ :: Pat GhcPs) -> True) pat_lhs] TyClD _ ClassDecl{tcdLName, tcdSigs} -> - mkComp tcdLName CiInterface (Just $ ppr tcdLName) : - [ mkComp id CiFunction (Just $ ppr typ) + mkComp tcdLName CiInterface (Just $ showForSnippet tcdLName) : + [ mkComp id CiFunction (Just $ showForSnippet typ) | L _ (ClassOpSig _ _ ids typ) <- tcdSigs , id <- ids] TyClD _ x -> - let generalCompls = [mkComp id cl (Just $ ppr $ tyClDeclLName x) - | id <- listify (\(_ :: Located(IdP GhcPs)) -> True) x + let generalCompls = [mkComp id cl (Just $ showForSnippet $ tyClDeclLName x) + | id <- listify (\(_ :: LIdP GhcPs) -> True) x , let cl = occNameToComKind Nothing (rdrNameOcc $ unLoc id)] -- here we only have to look at the outermost type recordCompls = findRecordCompl uri pm (Local pos) x @@ -454,11 +476,11 @@ localCompletionsForParsedModule uri pm@ParsedModule{pm_parsed_source = L _ HsMod -- the constructors and snippets will be duplicated here giving the user 2 choices. generalCompls ++ recordCompls ForD _ ForeignImport{fd_name,fd_sig_ty} -> - [mkComp fd_name CiVariable (Just $ ppr fd_sig_ty)] + [mkComp fd_name CiVariable (Just $ showForSnippet fd_sig_ty)] ForD _ ForeignExport{fd_name,fd_sig_ty} -> - [mkComp fd_name CiVariable (Just $ ppr fd_sig_ty)] + [mkComp fd_name CiVariable (Just $ showForSnippet fd_sig_ty)] _ -> [] - | L pos decl <- hsmodDecls, + | L (locA -> pos) decl <- hsmodDecls, let mkComp = mkLocalComp pos ] @@ -469,8 +491,8 @@ localCompletionsForParsedModule uri pm@ParsedModule{pm_parsed_source = L _ HsMod -- to tell local completions and global completions apart -- instead of using the empty string here, we should probably introduce a new field... ensureTypeText = Just $ fromMaybe "" ty - pn = ppr n - doc = SpanDocText (getDocumentation [pm] n) (SpanDocUris Nothing Nothing) + pn = showForSnippet n + doc = SpanDocText (getDocumentation [pm] $ reLoc n) (SpanDocUris Nothing Nothing) findRecordCompl :: Uri -> ParsedModule -> Provenance -> TyClDecl GhcPs -> [CompItem] findRecordCompl uri pmod mn DataDecl {tcdLName, tcdDataDefn} = result @@ -480,15 +502,14 @@ findRecordCompl uri pmod mn DataDecl {tcdLName, tcdDataDefn} = result | ConDeclH98{..} <- unLoc <$> dd_cons tcdDataDefn , Just con_details <- [getFlds con_args] , let field_names = concatMap extract con_details - , let field_labels = showGhc . unLoc <$> field_names + , let field_labels = showGhc <$> field_names , (not . List.null) field_labels ] - doc = SpanDocText (getDocumentation [pmod] tcdLName) (SpanDocUris Nothing Nothing) + doc = SpanDocText (getDocumentation [pmod] $ reLoc tcdLName) (SpanDocUris Nothing Nothing) - getFlds :: HsConDetails arg (Located [LConDeclField GhcPs]) -> Maybe [ConDeclField GhcPs] getFlds conArg = case conArg of RecCon rec -> Just $ unLoc <$> unLoc rec - PrefixCon _ -> Just [] + PrefixCon{} -> Just [] _ -> Nothing extract ConDeclField{..} @@ -602,8 +623,8 @@ getCompletions plId ideOpts CC {allModNamesAsNS, anyQualCompls, unqualCompls, qu where occ = nameOccName name ctyp = occNameToComKind Nothing occ - pn = ppr name - ty = ppr <$> typ + pn = showForSnippet name + ty = showForSnippet <$> typ thisModName = Local $ nameSrcSpan name compls = if T.null prefixModule diff --git a/ghcide/src/Development/IDE/Plugin/TypeLenses.hs b/ghcide/src/Development/IDE/Plugin/TypeLenses.hs index 127afe57d0..4f7084badb 100644 --- a/ghcide/src/Development/IDE/Plugin/TypeLenses.hs +++ b/ghcide/src/Development/IDE/Plugin/TypeLenses.hs @@ -97,6 +97,7 @@ codeLensProvider ideState pId CodeLensParams{_textDocument = TextDocumentIdentif mode <- usePropertyLsp #mode pId properties fmap (Right . List) $ case uriToFilePath' uri of Just (toNormalizedFilePath' -> filePath) -> liftIO $ do + env <- fmap hscEnv <$> runAction "codeLens.GhcSession" ideState (use GhcSession filePath) tmr <- runAction "codeLens.TypeCheck" ideState (use TypeCheck filePath) bindings <- runAction "codeLens.GetBindings" ideState (use GetBindings filePath) gblSigs <- runAction "codeLens.GetGlobalBindingTypeSigs" ideState (use GetGlobalBindingTypeSigs filePath) @@ -123,9 +124,9 @@ codeLensProvider ideState pId CodeLensParams{_textDocument = TextDocumentIdentif case mode of Always -> pure (catMaybes $ generateLensForGlobal <$> gblSigs') - <> generateLensFromDiags (suggestLocalSignature False tmr bindings) -- we still need diagnostics for local bindings + <> generateLensFromDiags (suggestLocalSignature False env tmr bindings) -- we still need diagnostics for local bindings Exported -> pure $ catMaybes $ generateLensForGlobal <$> filter gbExported gblSigs' - Diagnostics -> generateLensFromDiags $ suggestSignature False gblSigs tmr bindings + Diagnostics -> generateLensFromDiags $ suggestSignature False env gblSigs tmr bindings Nothing -> pure [] generateLens :: PluginId -> Range -> T.Text -> WorkspaceEdit -> CodeLens @@ -140,9 +141,9 @@ commandHandler _ideState wedit = do -------------------------------------------------------------------------------- -suggestSignature :: Bool -> Maybe GlobalBindingTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] -suggestSignature isQuickFix mGblSigs mTmr mBindings diag = - suggestGlobalSignature isQuickFix mGblSigs diag <> suggestLocalSignature isQuickFix mTmr mBindings diag +suggestSignature :: Bool -> Maybe HscEnv -> Maybe GlobalBindingTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestSignature isQuickFix env mGblSigs mTmr mBindings diag = + suggestGlobalSignature isQuickFix mGblSigs diag <> suggestLocalSignature isQuickFix env mTmr mBindings diag suggestGlobalSignature :: Bool -> Maybe GlobalBindingTypeSigsResult -> Diagnostic -> [(T.Text, [TextEdit])] suggestGlobalSignature isQuickFix mGblSigs Diagnostic{_message, _range} @@ -156,19 +157,20 @@ suggestGlobalSignature isQuickFix mGblSigs Diagnostic{_message, _range} [(title, [action])] | otherwise = [] -suggestLocalSignature :: Bool -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] -suggestLocalSignature isQuickFix mTmr mBindings Diagnostic{_message, _range = _range@Range{..}} +suggestLocalSignature :: Bool -> Maybe HscEnv -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestLocalSignature isQuickFix mEnv mTmr mBindings Diagnostic{_message, _range = _range@Range{..}} | Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, [identifier]) <- (T.unwords . T.words $ _message) =~~ ("Polymorphic local binding with no type signature: (.*) ::" :: T.Text) , Just bindings <- mBindings + , Just env <- mEnv , localScope <- getFuzzyScope bindings _start _end , -- we can't use srcspan to lookup scoped bindings, because the error message reported by GHC includes the entire binding, instead of simply the name Just (name, ty) <- find (\(x, _) -> printName x == T.unpack identifier) localScope >>= \(name, mTy) -> (name,) <$> mTy , Just TcModuleResult{tmrTypechecked = TcGblEnv{tcg_rdr_env, tcg_sigs}} <- mTmr , -- not a top-level thing, to avoid duplication not $ name `elemNameSet` tcg_sigs - , tyMsg <- printSDocQualifiedUnsafe (mkPrintUnqualifiedDefault tcg_rdr_env) $ pprSigmaType ty + , tyMsg <- printSDocQualifiedUnsafe (mkPrintUnqualifiedDefault env tcg_rdr_env) $ pprSigmaType ty , signature <- T.pack $ printName name <> " :: " <> tyMsg , startCharacter <- _character _start , startOfLine <- Position (_line _start) startCharacter @@ -213,7 +215,7 @@ instance A.FromJSON Mode where -------------------------------------------------------------------------------- showDocRdrEnv :: HscEnv -> GlobalRdrEnv -> SDoc -> String -showDocRdrEnv env rdrEnv = showSDocForUser (hsc_dflags env) (mkPrintUnqualified (hsc_dflags env) rdrEnv) +showDocRdrEnv env rdrEnv = showSDocForUser' env (mkPrintUnqualifiedDefault env rdrEnv) data GetGlobalBindingTypeSigs = GetGlobalBindingTypeSigs deriving (Generic, Show, Eq, Ord, Hashable, NFData) diff --git a/ghcide/src/Development/IDE/Spans/AtPoint.hs b/ghcide/src/Development/IDE/Spans/AtPoint.hs index 4f099e42c2..599872cebe 100644 --- a/ghcide/src/Development/IDE/Spans/AtPoint.hs +++ b/ghcide/src/Development/IDE/Spans/AtPoint.hs @@ -160,7 +160,13 @@ documentHighlight -> MaybeT m [DocumentHighlight] documentHighlight hf rf pos = pure highlights where - ns = concat $ pointCommand hf pos (rights . M.keys . getNodeIds) +#if MIN_VERSION_ghc(9,0,1) + -- We don't want to show document highlights for evidence variables, which are supposed to be invisible + notEvidence = not . any isEvidenceContext . identInfo +#else + notEvidence = const True +#endif + ns = concat $ pointCommand hf pos (rights . M.keys . M.filter notEvidence . getNodeIds) highlights = do n <- ns ref <- fromMaybe [] (M.lookup (Right n) rf) diff --git a/ghcide/src/Development/IDE/Spans/Documentation.hs b/ghcide/src/Development/IDE/Spans/Documentation.hs index 8afe4f72fe..ed993fb7ec 100644 --- a/ghcide/src/Development/IDE/Spans/Documentation.hs +++ b/ghcide/src/Development/IDE/Spans/Documentation.hs @@ -39,7 +39,12 @@ mkDocMap -> TcGblEnv -> IO DocAndKindMap mkDocMap env rm this_mod = - do let (_ , DeclDocMap this_docs, _) = extractDocs this_mod + do +#if MIN_VERSION_ghc(9,2,0) + (_ , DeclDocMap this_docs, _) <- extractDocs this_mod +#else + let (_ , DeclDocMap this_docs, _) = extractDocs this_mod +#endif d <- foldrM getDocs (mkNameEnv $ M.toList $ fmap (`SpanDocString` SpanDocUris Nothing Nothing) this_docs) names k <- foldrM getType (tcg_type_env this_mod) names pure $ DKMap d k @@ -108,7 +113,12 @@ getDocumentation -- may be edge cases where it is very wrong). -- TODO : Build a version of GHC exactprint to extract this information -- more accurately. +-- TODO : Implement this for GHC 9.2 with in-tree annotations +-- (alternatively, just remove it and rely soley on GHC's parsing) getDocumentation sources targetName = fromMaybe [] $ do +#if MIN_VERSION_ghc(9,2,0) + Nothing +#else -- Find the module the target is defined in. targetNameSpan <- realSpan $ getLoc targetName tc <- @@ -170,6 +180,7 @@ docHeaders = mapMaybe (\(L _ x) -> wrk x) then Just $ T.pack s else Nothing _ -> Nothing +#endif -- These are taken from haskell-ide-engine's Haddock plugin diff --git a/ghcide/src/Development/IDE/Spans/Pragmas.hs b/ghcide/src/Development/IDE/Spans/Pragmas.hs index 1ce7eb88bb..c575d9e810 100644 --- a/ghcide/src/Development/IDE/Spans/Pragmas.hs +++ b/ghcide/src/Development/IDE/Spans/Pragmas.hs @@ -122,13 +122,21 @@ updateParserState token range prevParserState ModeInitial -> case token of ITvarsym "#" -> defaultParserState{ isLastTokenHash = True } +#if !MIN_VERSION_ghc(9,2,0) ITlineComment s +#else + ITlineComment s _ +#endif | isDownwardLineHaddock s -> defaultParserState{ mode = ModeHaddock } | otherwise -> defaultParserState { nextPragma = NextPragmaInfo (endLine + 1) Nothing , mode = ModeComment } +#if !MIN_VERSION_ghc(9,2,0) ITblockComment s +#else + ITblockComment s _ +#endif | isPragma s -> defaultParserState { nextPragma = NextPragmaInfo (endLine + 1) Nothing @@ -144,7 +152,11 @@ updateParserState token range prevParserState ModeComment -> case token of ITvarsym "#" -> defaultParserState{ isLastTokenHash = True } +#if !MIN_VERSION_ghc(9,2,0) ITlineComment s +#else + ITlineComment s _ +#endif | hasDeleteStartedOnSameLine startLine prevLineSplitTextEdits , let currLineSplitTextEdits = updateLineSplitTextEdits range s prevLineSplitTextEdits -> defaultParserState{ nextPragma = prevNextPragma{ lineSplitTextEdits = Just currLineSplitTextEdits } } @@ -156,7 +168,11 @@ updateParserState token range prevParserState , mode = ModeHaddock } | otherwise -> defaultParserState { nextPragma = NextPragmaInfo (endLine + 1) Nothing } +#if !MIN_VERSION_ghc(9,2,0) ITblockComment s +#else + ITblockComment s _ +#endif | isPragma s -> defaultParserState { nextPragma = NextPragmaInfo (endLine + 1) Nothing @@ -180,13 +196,21 @@ updateParserState token range prevParserState case token of ITvarsym "#" -> defaultParserState{ isLastTokenHash = True } +#if !MIN_VERSION_ghc(9,2,0) ITlineComment s +#else + ITlineComment s _ +#endif | hasDeleteStartedOnSameLine startLine prevLineSplitTextEdits , let currLineSplitTextEdits = updateLineSplitTextEdits range s prevLineSplitTextEdits -> defaultParserState{ nextPragma = prevNextPragma{ lineSplitTextEdits = Just currLineSplitTextEdits } } | otherwise -> defaultParserState +#if !MIN_VERSION_ghc(9,2,0) ITblockComment s +#else + ITblockComment s _ +#endif | isPragma s -> defaultParserState{ nextPragma = NextPragmaInfo (endLine + 1) Nothing, @@ -200,7 +224,11 @@ updateParserState token range prevParserState ModePragma -> case token of ITvarsym "#" -> defaultParserState{ isLastTokenHash = True } +#if !MIN_VERSION_ghc(9,2,0) ITlineComment s +#else + ITlineComment s _ +#endif | hasDeleteStartedOnSameLine startLine prevLineSplitTextEdits , let currLineSplitTextEdits = updateLineSplitTextEdits range s prevLineSplitTextEdits -> defaultParserState{ nextPragma = prevNextPragma{ lineSplitTextEdits = Just currLineSplitTextEdits } } @@ -210,7 +238,11 @@ updateParserState token range prevParserState defaultParserState{ nextPragma = prevNextPragma{ lineSplitTextEdits = Just currLineSplitTextEdits } } | otherwise -> defaultParserState +#if !MIN_VERSION_ghc(9,2,0) ITblockComment s +#else + ITblockComment s _ +#endif | isPragma s -> defaultParserState{ nextPragma = NextPragmaInfo (endLine + 1) Nothing, lastPragmaLine = endLine } | hasDeleteStartedOnSameLine startLine prevLineSplitTextEdits @@ -390,7 +422,7 @@ mkLexerPState dynFlags stringBuffer = <*> const False finalPState = mkPStatePure (mkLexerParserFlags finalDynFlags) stringBuffer startRealSrcLoc #else - pState = mkPState finalDynFlags stringBuffer startRealSrcLoc + pState = initParserState (initParserOpts finalDynFlags) stringBuffer startRealSrcLoc PState{ options = pStateOptions } = pState finalExtBitsMap = setBit (pExtsBitmap pStateOptions) (fromEnum UsePosPragsBit) finalPStateOptions = pStateOptions{ pExtsBitmap = finalExtBitsMap } diff --git a/ghcide/test/exe/Main.hs b/ghcide/test/exe/Main.hs index 169e9922af..e328133576 100644 --- a/ghcide/test/exe/Main.hs +++ b/ghcide/test/exe/Main.hs @@ -7,6 +7,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE ImplicitParams #-} +{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeOperators #-} @@ -15,8 +16,8 @@ module Main (main) where import Control.Applicative.Combinators -import Control.Concurrent.Extra as Concurrent -import Control.Exception (bracket_, catch) +import Control.Concurrent +import Control.Exception (bracket_, catch, finally) import qualified Control.Lens as Lens import Control.Monad import Control.Monad.IO.Class (MonadIO, liftIO) @@ -81,7 +82,7 @@ import System.Exit (ExitCode (ExitSuccess import System.FilePath import System.IO.Extra hiding (withTempDir) import qualified System.IO.Extra -import System.Info.Extra (isWindows) +import System.Info.Extra (isWindows, isMac) import System.Mem (performGC) import System.Process.Extra (CreateProcess (cwd), createPipe, proc, @@ -1737,7 +1738,8 @@ extendImportTests = testGroup "extend import actions" , "import A (pattern Some)" , "k (Some x) = x" ]) - , testSession "type constructor name same as data constructor name" $ template + , ignoreForGHC92 "Diagnostic message has no suggestions" $ + testSession "type constructor name same as data constructor name" $ template [("ModuleA.hs", T.unlines [ "module ModuleA where" , "newtype Foo = Foo Int" @@ -2526,9 +2528,9 @@ deleteUnusedDefinitionTests = testGroup "delete unused definition action" return (action, actionTitle) addTypeAnnotationsToLiteralsTest :: TestTree -addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals to satisfy contraints" +addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals to satisfy constraints" [ - testSession "add default type to satisfy one contraint" $ + testSession "add default type to satisfy one constraint" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "module A (f) where" @@ -2543,7 +2545,7 @@ addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals t , "f = (1 :: Integer)" ]) - , testSession "add default type to satisfy one contraint in nested expressions" $ + , testSession "add default type to satisfy one constraint in nested expressions" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "module A where" @@ -2561,7 +2563,7 @@ addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals t , " let x = (3 :: Integer)" , " in x" ]) - , testSession "add default type to satisfy one contraint in more nested expressions" $ + , testSession "add default type to satisfy one constraint in more nested expressions" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "module A where" @@ -2579,7 +2581,7 @@ addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals t , " let x = let y = (5 :: Integer) in y" , " in x" ]) - , testSession "add default type to satisfy one contraint with duplicate literals" $ + , testSession "add default type to satisfy one constraint with duplicate literals" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "{-# LANGUAGE OverloadedStrings #-}" @@ -2601,7 +2603,8 @@ addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals t , "" , "f = seq (\"debug\" :: " <> listOfChar <> ") traceShow \"debug\"" ]) - , testSession "add default type to satisfy two contraints" $ + , knownBrokenForGhcVersions [GHC92] "GHC 9.2 only has 'traceShow' in error span" $ + testSession "add default type to satisfy two constraints" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "{-# LANGUAGE OverloadedStrings #-}" @@ -2621,7 +2624,8 @@ addTypeAnnotationsToLiteralsTest = testGroup "add type annotations to literals t , "" , "f a = traceShow (\"debug\" :: " <> listOfChar <> ") a" ]) - , testSession "add default type to satisfy two contraints with duplicate literals" $ + , knownBrokenForGhcVersions [GHC92] "GHC 9.2 only has 'traceShow' in error span" $ + testSession "add default type to satisfy two constraints with duplicate literals" $ testFor (T.unlines [ "{-# OPTIONS_GHC -Wtype-defaults #-}" , "{-# LANGUAGE OverloadedStrings #-}" @@ -3300,7 +3304,7 @@ addSigActionTests = let , "pattern Point{x, y} <- (x, y)\n where Point x y = (x, y)" >:: "pattern Point :: a -> b -> (a, b)" , "pattern MkT1' b = MkT1 42 b" >:: "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a" , "pattern MkT1' b <- MkT1 42 b" >:: "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a" - , "pattern MkT1' b <- MkT1 42 b\n where MkT1' b = T1 42 b" >:: "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a" + , "pattern MkT1' b <- MkT1 42 b\n where MkT1' b = MkT1 42 b" >:: "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a" ] exportUnusedTests :: TestTree @@ -3326,7 +3330,8 @@ exportUnusedTests = testGroup "export unused actions" (R 2 0 2 11) "Export ‘bar’" Nothing - , testSession "type is exported but not the constructor of same name" $ template + , ignoreForGHC92 "Diagnostic message has no suggestions" $ + testSession "type is exported but not the constructor of same name" $ template (T.unlines [ "{-# OPTIONS_GHC -Wunused-top-binds #-}" , "module A (Foo) where" @@ -3818,13 +3823,13 @@ addSigLensesTests = , ("pattern Point{x, y} <- (x, y)\n where Point x y = (x, y)", "pattern Point :: a -> b -> (a, b)") , ("pattern MkT1' b = MkT1 42 b", "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a") , ("pattern MkT1' b <- MkT1 42 b", "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a") - , ("pattern MkT1' b <- MkT1 42 b\n where MkT1' b = T1 42 b", "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a") + , ("pattern MkT1' b <- MkT1 42 b\n where MkT1' b = MkT1 42 b", "pattern MkT1' :: (Eq a, Num a) => Show b => b -> T1 a") , ("qualifiedSigTest= C.realPart", "qualifiedSigTest :: C.Complex a -> a") , ("head = 233", "head :: Integer") , ("rank2Test (k :: forall a . a -> a) = (k 233 :: Int, k \"QAQ\")", "rank2Test :: (forall a. a -> a) -> (Int, " <> listOfChar <> ")") , ("symbolKindTest = Proxy @\"qwq\"", "symbolKindTest :: Proxy \"qwq\"") , ("promotedKindTest = Proxy @Nothing", "promotedKindTest :: Proxy 'Nothing") - , ("typeOperatorTest = Refl", "typeOperatorTest :: a :~: a") + , ("typeOperatorTest = Refl", if ghcVersion >= GHC92 then "typeOperatorTest :: forall {k} {a :: k}. a :~: a" else "typeOperatorTest :: a :~: a") , ("notInScopeTest = mkCharType", "notInScopeTest :: String -> Data.Data.DataType") ] in testGroup @@ -3976,8 +3981,8 @@ findDefinitionAndHoverTests = let spaceL37 = Position 41 24 ; space = [ExpectNoDefinitions, ExpectHoverText [":: Char"]] docL41 = Position 45 1 ; doc = [ExpectHoverText ["Recognizable docs: kpqz"]] ; constr = [ExpectHoverText ["Monad m"]] - eitL40 = Position 44 28 ; kindE = [ExpectHoverText [":: * -> * -> *\n"]] - intL40 = Position 44 34 ; kindI = [ExpectHoverText [":: *\n"]] + eitL40 = Position 44 28 ; kindE = [ExpectHoverText [if ghcVersion >= GHC92 then ":: Type -> Type -> Type\n" else ":: * -> * -> *\n"]] + intL40 = Position 44 34 ; kindI = [ExpectHoverText [if ghcVersion >= GHC92 then ":: Type\n" else ":: *\n"]] tvrL40 = Position 44 37 ; kindV = [ExpectHoverText [":: * -> *\n"]] intL41 = Position 45 20 ; litI = [ExpectHoverText ["7518"]] chrL36 = Position 41 24 ; litC = [ExpectHoverText ["'f'"]] @@ -4043,9 +4048,13 @@ findDefinitionAndHoverTests = let , test no skip cccL17 docLink "Haddock html links" , testM yes yes imported importedSig "Imported symbol" , testM yes yes reexported reexportedSig "Imported symbol (reexported)" - , if ghcVersion == GHC90 && isWindows then + , if | ghcVersion == GHC90 && isWindows -> test no broken thLocL57 thLoc "TH Splice Hover" - else + | ghcVersion == GHC92 && (isWindows || isMac) -> + -- Some GHC 9.2 distributions ship without .hi docs + -- https://gitlab.haskell.org/ghc/ghc/-/issues/20903 + test no broken thLocL57 thLoc "TH Splice Hover" + | otherwise -> test no yes thLocL57 thLoc "TH Splice Hover" ] where yes, broken :: (TestTree -> Maybe TestTree) @@ -4063,6 +4072,7 @@ checkFileCompiles fp diag = pluginSimpleTests :: TestTree pluginSimpleTests = ignoreInWindowsForGHC88And810 $ + ignoreForGHC92 "blocked on ghc-typelits-natnormalise" $ testSessionWithExtraFiles "plugin-knownnat" "simple plugin" $ \dir -> do _ <- openDoc (dir "KnownNat.hs") "haskell" liftIO $ writeFile (dir"hie.yaml") @@ -4077,6 +4087,7 @@ pluginSimpleTests = pluginParsedResultTests :: TestTree pluginParsedResultTests = ignoreInWindowsForGHC88And810 $ + ignoreForGHC92 "No need for this plugin anymore!" $ testSessionWithExtraFiles "plugin-recorddot" "parsedResultAction plugin" $ \dir -> do _ <- openDoc (dir "RecordDot.hs") "haskell" expectNoMoreDiagnostics 2 @@ -4991,7 +5002,7 @@ highlightTests = testGroup "highlight" , DocumentHighlight (R 6 10 6 13) (Just HkRead) , DocumentHighlight (R 7 12 7 15) (Just HkRead) ] - , knownBrokenForGhcVersions [GHC90] "Ghc9 highlights the constructor and not just this field" $ + , knownBrokenForGhcVersions [GHC90, GHC92] "Ghc9 highlights the constructor and not just this field" $ testSessionWait "record" $ do doc <- createDoc "A.hs" "haskell" recsource _ <- waitForDiagnostics @@ -5132,7 +5143,7 @@ outlineTests = testGroup let source = T.unlines ["data A = B {", " x :: Int", " , y :: Int}"] docId <- createDoc "A.hs" "haskell" source symbols <- getDocumentSymbols docId - liftIO $ symbols @=? Left + liftIO $ symbols @?= Left [ docSymbolWithChildren "A" SkStruct (R 0 0 2 13) [ docSymbolWithChildren' "B" SkConstructor (R 0 9 2 13) (R 0 9 0 10) [ docSymbol "x" SkField (R 1 2 1 3) @@ -5225,6 +5236,11 @@ ignoreInWindowsForGHC88And810 ignoreInWindowsBecause "tests are unreliable in windows for ghc 8.8 and 8.10" | otherwise = id +ignoreForGHC92 :: String -> TestTree -> TestTree +ignoreForGHC92 msg + | ghcVersion == GHC92 = ignoreTestBecause msg + | otherwise = id + ignoreInWindowsForGHC88 :: TestTree -> TestTree ignoreInWindowsForGHC88 | ghcVersion == GHC88 = @@ -5388,7 +5404,7 @@ dependentFileTest = testGroup "addDependentFile" expectDiagnostics $ if ghcVersion >= GHC90 -- String vs [Char] causes this change in error message - then [("Foo.hs", [(DsError, (4, 6), "Couldn't match type")])] + then [("Foo.hs", [(DsError, if ghcVersion >= GHC92 then (4,11) else (4, 6), "Couldn't match type")])] else [("Foo.hs", [(DsError, (4, 6), "Couldn't match expected type")])] -- Now modify the dependent file liftIO $ writeFile depFilePath "B" @@ -6238,9 +6254,13 @@ findResolution_us delay_us = withTempFile $ \f -> withTempFile $ \f' -> do if t /= t' then return delay_us else findResolution_us (delay_us * 10) -testIde :: IDE.Arguments -> Session () -> IO () -testIde arguments session = do +testIde :: IDE.Arguments -> Session a -> IO a +testIde = testIde' "." + +testIde' :: FilePath -> IDE.Arguments -> Session a -> IO a +testIde' projDir arguments session = do config <- getConfigFromEnv + cwd <- getCurrentDirectory (hInRead, hInWrite) <- createPipe (hOutRead, hOutWrite) <- createPipe let server = IDE.defaultMain arguments @@ -6248,8 +6268,10 @@ testIde arguments session = do , IDE.argsHandleOut = pure hOutWrite } - withAsync server $ \_ -> - runSessionWithHandles hInWrite hOutRead config lspTestCaps "." session + flip finally (setCurrentDirectory cwd) $ withAsync server $ \_ -> + runSessionWithHandles hInWrite hOutRead config lspTestCaps projDir session + + positionMappingTests :: TestTree positionMappingTests = diff --git a/hls-graph/src/Control/Concurrent/STM/Stats.hs b/hls-graph/src/Control/Concurrent/STM/Stats.hs index 295b5d58f0..a79f287ef9 100644 --- a/hls-graph/src/Control/Concurrent/STM/Stats.hs +++ b/hls-graph/src/Control/Concurrent/STM/Stats.hs @@ -1,7 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} #ifdef STM_STATS -{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE RecordWildCards #-} #endif module Control.Concurrent.STM.Stats ( atomicallyNamed diff --git a/hls-graph/src/Development/IDE/Graph/Internal/Types.hs b/hls-graph/src/Development/IDE/Graph/Internal/Types.hs index 6f75b1a809..9706061971 100644 --- a/hls-graph/src/Development/IDE/Graph/Internal/Types.hs +++ b/hls-graph/src/Development/IDE/Graph/Internal/Types.hs @@ -1,5 +1,6 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} @@ -8,7 +9,6 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE CPP #-} module Development.IDE.Graph.Internal.Types where @@ -18,11 +18,11 @@ import Control.Monad.Catch -- Needed in GHC 8.6.5 import Control.Concurrent.STM.Stats (TVar, atomically) #else -import GHC.Conc (TVar, atomically) +import GHC.Conc (TVar, atomically) #endif #if __GLASGOW_HASKELL__ < 880 -import Prelude hiding (MonadFail) import Control.Monad.Fail +import Prelude hiding (MonadFail) #endif import Control.Monad.IO.Class import Control.Monad.Trans.Reader diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index b525551f8c..b6d25909a8 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -2,6 +2,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} {-# LANGUAGE RecordWildCards #-} module Test.Hls ( module Test.Tasty.HUnit, diff --git a/plugins/default/src/Ide/Plugin/Example.hs b/plugins/default/src/Ide/Plugin/Example.hs index 89bef3441e..6fbbaad67a 100644 --- a/plugins/default/src/Ide/Plugin/Example.hs +++ b/plugins/default/src/Ide/Plugin/Example.hs @@ -27,7 +27,7 @@ import Data.Typeable import Development.IDE as D import Development.IDE.Core.Shake (getDiagnostics, getHiddenDiagnostics) -import Development.IDE.GHC.Compat (ParsedModule (ParsedModule)) +import Development.IDE.GHC.Compat import GHC.Generics import Ide.PluginUtils import Ide.Types diff --git a/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/Literals.hs b/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/Literals.hs index 61a8367e1b..59c4457648 100644 --- a/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/Literals.hs +++ b/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/Literals.hs @@ -82,10 +82,10 @@ fromOverLit OverLit{..} sSpan = case ol_val of fromOverLit _ _ = Nothing fromIntegralLit :: RealSrcSpan -> IntegralLit -> Maybe Literal -fromIntegralLit s (IL txt _ val) = fmap (\txt' -> IntLiteral s txt' val) (fromSourceText txt) +fromIntegralLit s IL{..} = fmap (\txt' -> IntLiteral s txt' il_value) (fromSourceText il_text) fromFractionalLit :: RealSrcSpan -> FractionalLit -> Maybe Literal -fromFractionalLit s (FL txt _ val) = fmap (\txt' -> FracLiteral s txt' val) (fromSourceText txt) +fromFractionalLit s FL{..} = fmap (\txt' -> FracLiteral s txt' fl_value) (fromSourceText fl_text) fromSourceText :: SourceText -> Maybe Text fromSourceText = \case @@ -115,6 +115,6 @@ literalToString = \case overLitToString :: OverLitVal -> String overLitToString = \case - HsIntegral int -> case int of { IL _ _ val -> "IntegralOverLit: " <> show val } - HsFractional frac -> case frac of { FL _ _ val -> "RationalOverLit: " <> show val } + HsIntegral int -> case int of { IL{il_value} -> "IntegralOverLit: " <> show il_value} + HsFractional frac -> case frac of { FL{fl_value} -> "RationalOverLit: " <> show fl_value} HsIsString _ str -> "HIsString: " <> show str diff --git a/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs b/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs index e6b3e3a5b7..7a14519904 100644 --- a/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs +++ b/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs @@ -6,7 +6,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} - +{-# LANGUAGE ViewPatterns #-} module Ide.Plugin.ExplicitImports ( descriptor @@ -42,7 +42,9 @@ importCommandId = "ImportLensCommand" -- | The "main" function of a plugin descriptor :: PluginId -> PluginDescriptor IdeState -descriptor = descriptorForModules (/= moduleName pRELUDE) +descriptor = + -- (almost) no one wants to see an explicit import list for Prelude + descriptorForModules (/= moduleName pRELUDE) descriptorForModules :: (ModuleName -> Bool) @@ -180,7 +182,7 @@ exportedModuleStrings :: ParsedModule -> [String] exportedModuleStrings ParsedModule{pm_parsed_source = L _ HsModule{..}} | Just export <- hsmodExports, exports <- unLoc export - = map show exports + = map prettyPrint exports exportedModuleStrings _ = [] minimalImportsRule :: Rules () @@ -194,7 +196,7 @@ minimalImportsRule = define $ \MinimalImports nfp -> do let importsMap = Map.fromList [ (realSrcSpanStart l, T.pack (prettyPrint i)) - | L (RealSrcSpan l _) i <- fromMaybe [] mbMinImports + | L (locA -> RealSrcSpan l _) i <- fromMaybe [] mbMinImports ] res = [ (i, Map.lookup (realSrcSpanStart l) importsMap) @@ -240,15 +242,14 @@ extractMinimalImports (Just hsc) (Just TcModuleResult {..}) = do notExported _ _ = False extractMinimalImports _ _ = return ([], Nothing) -mkExplicitEdit :: (ModuleName -> Bool) -> PositionMapping -> LImportDecl pass -> T.Text -> Maybe TextEdit -mkExplicitEdit pred posMapping (L src imp) explicit +mkExplicitEdit :: (ModuleName -> Bool) -> PositionMapping -> LImportDecl GhcRn -> T.Text -> Maybe TextEdit +mkExplicitEdit pred posMapping (L (locA -> src) imp) explicit -- Explicit import list case | ImportDecl {ideclHiding = Just (False, _)} <- imp = Nothing | not (isQualifiedImport imp), RealSrcSpan l _ <- src, L _ mn <- ideclName imp, - -- (almost) no one wants to see an explicit import list for Prelude pred mn, Just rng <- toCurrentRange posMapping $ realSrcSpanToRange l = Just $ TextEdit rng explicit diff --git a/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs b/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs index f04e5d474c..c4da71d5cc 100644 --- a/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs +++ b/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs @@ -55,7 +55,7 @@ import Refact.Apply #ifdef HLINT_ON_GHC_LIB import Data.List (nub) -import Development.IDE.GHC.Compat.Core (BufSpan, +import Development.IDE.GHC.Compat (BufSpan, DynFlags, extensionFlags, ms_hspp_opts, @@ -79,7 +79,7 @@ import System.IO (IOMode (Wri withFile) import System.IO.Temp #else -import Development.IDE.GHC.Compat.Core hiding +import Development.IDE.GHC.Compat hiding (setEnv) import Language.Haskell.GHC.ExactPrint.Delta (deltaOptions) import Language.Haskell.GHC.ExactPrint.Parsers (postParseTransform) @@ -109,7 +109,7 @@ import GHC.Generics (Associativi Generic) import Text.Regex.TDFA.Text () -import Development.IDE.GHC.Compat.Core (WarningFlag (Opt_WarnUnrecognisedPragmas), +import Development.IDE.GHC.Compat (WarningFlag (Opt_WarnUnrecognisedPragmas), wopt) import Development.IDE.Spans.Pragmas (LineSplitTextEdits (LineSplitTextEdits), NextPragmaInfo (NextPragmaInfo), diff --git a/plugins/hls-pragmas-plugin/test/testdata/hie.yaml b/plugins/hls-pragmas-plugin/test/testdata/hie.yaml index 1a9f518b52..7b4d912951 100644 --- a/plugins/hls-pragmas-plugin/test/testdata/hie.yaml +++ b/plugins/hls-pragmas-plugin/test/testdata/hie.yaml @@ -1,6 +1,7 @@ cradle: direct: arguments: + - "-XHaskell2010" - "NeedsPragmas" - "TypeApplications" - "NamedFieldPuns" diff --git a/plugins/hls-qualify-imported-names-plugin/src/Ide/Plugin/QualifyImportedNames.hs b/plugins/hls-qualify-imported-names-plugin/src/Ide/Plugin/QualifyImportedNames.hs index 5c5a570156..fd2fe979c7 100644 --- a/plugins/hls-qualify-imported-names-plugin/src/Ide/Plugin/QualifyImportedNames.hs +++ b/plugins/hls-qualify-imported-names-plugin/src/Ide/Plugin/QualifyImportedNames.hs @@ -1,6 +1,7 @@ {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-} @@ -28,25 +29,27 @@ import Development.IDE.Core.RuleTypes (GetFileContents (GetFileCont import Development.IDE.Core.Service (runAction) import Development.IDE.Core.Shake (IdeState, use) import Development.IDE.GHC.Compat (ContextInfo (Use), + GenLocated (..), GhcPs, + GlobalRdrElt, GlobalRdrEnv, + HsModule (hsmodImports), Identifier, IdentifierDetails (IdentifierDetails, identInfo), - RefMap, Span) -import Development.IDE.GHC.Compat.Core (GenLocated (L), GhcPs, - GlobalRdrElt (GRE, gre_imp, gre_name), - GlobalRdrEnv, - HsModule (hsmodImports), ImpDeclSpec (ImpDeclSpec, is_as, is_dloc, is_qual), ImportSpec (ImpSpec), LImportDecl, ModuleName, Name, NameEnv, OccName, - ParsedModule (ParsedModule, pm_parsed_source), + ParsedModule, RefMap, Span, SrcSpan, TcGblEnv (tcg_rdr_env), emptyUFM, globalRdrEnvElts, + gre_imp, gre_name, lookupNameEnv, moduleNameString, nameOccName, occNameString, - plusUFM_C, srcSpanEndCol, + pattern GRE, + pattern ParsedModule, + plusUFM_C, pm_parsed_source, + srcSpanEndCol, srcSpanEndLine, srcSpanStartCol, srcSpanStartLine, unitUFM) diff --git a/plugins/hls-rename-plugin/src/Ide/Plugin/Rename.hs b/plugins/hls-rename-plugin/src/Ide/Plugin/Rename.hs index 54470fc0d8..5ffc7cfde7 100644 --- a/plugins/hls-rename-plugin/src/Ide/Plugin/Rename.hs +++ b/plugins/hls-rename-plugin/src/Ide/Plugin/Rename.hs @@ -67,15 +67,19 @@ getSrcEdits :: getSrcEdits state updateMod uri = do ccs <- lift getClientCapabilities nfp <- safeUriToNfp uri - ParsedModule{pm_parsed_source = ps, pm_annotations = apiAnns} <- + ~ParsedModule{pm_parsed_source = ps, pm_annotations = apiAnns} <- handleMaybeM "Error: could not get parsed source" $ liftIO $ runAction "Rename.GetParsedModuleWithComments" state (use GetParsedModuleWithComments nfp) - +#if !MIN_VERSION_ghc(9,2,1) let anns = relativiseApiAnns ps apiAnns src = T.pack $ exactPrint ps anns res = T.pack $ exactPrint (updateMod <$> ps) anns +#else + let src = T.pack $ exactPrint ps + res = T.pack $ exactPrint (updateMod <$> ps) +#endif pure $ diffText ccs (uri, src) res IncludeDeletions diff --git a/plugins/hls-splice-plugin/src/Ide/Plugin/Splice.hs b/plugins/hls-splice-plugin/src/Ide/Plugin/Splice.hs index 4e51e59b69..14ce391783 100644 --- a/plugins/hls-splice-plugin/src/Ide/Plugin/Splice.hs +++ b/plugins/hls-splice-plugin/src/Ide/Plugin/Splice.hs @@ -15,6 +15,8 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} module Ide.Plugin.Splice ( descriptor, @@ -134,7 +136,7 @@ expandTHSplice _eStyle ideState params@ExpandSpliceParams {..} = do graftSpliceWith :: forall ast. - HasSplice ast => + HasSplice AnnListItem ast => Maybe (SrcSpan, Located (ast GhcPs)) -> Maybe (Either String WorkspaceEdit) graftSpliceWith expandeds = @@ -273,27 +275,27 @@ findSubSpansDesc srcSpan = ) data SpliceClass where - OneToOneAST :: HasSplice ast => Proxy# ast -> SpliceClass + OneToOneAST :: HasSplice AnnListItem ast => Proxy# ast -> SpliceClass IsHsDecl :: SpliceClass -class (Outputable (ast GhcRn), ASTElement (ast GhcPs)) => HasSplice ast where +class (Outputable (ast GhcRn), ASTElement l (ast GhcPs)) => HasSplice l ast where type SpliceOf ast :: Kinds.Type -> Kinds.Type type SpliceOf ast = HsSplice matchSplice :: Proxy# ast -> ast GhcPs -> Maybe (SpliceOf ast GhcPs) expandSplice :: Proxy# ast -> SpliceOf ast GhcPs -> RnM (Either (ast GhcPs) (ast GhcRn), FreeVars) -instance HasSplice HsExpr where +instance HasSplice AnnListItem HsExpr where matchSplice _ (HsSpliceE _ spl) = Just spl matchSplice _ _ = Nothing expandSplice _ = fmap (first Right) . rnSpliceExpr -instance HasSplice Pat where +instance HasSplice AnnListItem Pat where matchSplice _ (SplicePat _ spl) = Just spl matchSplice _ _ = Nothing expandSplice _ = rnSplicePat -instance HasSplice HsType where +instance HasSplice AnnListItem HsType where matchSplice _ (HsSpliceTy _ spl) = Just spl matchSplice _ _ = Nothing expandSplice _ = fmap (first Right) . rnSpliceType @@ -366,8 +368,8 @@ manualCalcEdit clientCapabilities reportEditor ran ps hscEnv typechkd srcSpan _e -- | FIXME: Is thereAny "clever" way to do this exploiting TTG? unRenamedE :: - forall ast m. - (Fail.MonadFail m, HasSplice ast) => + forall ast m l. + (Fail.MonadFail m, HasSplice l ast) => DynFlags -> ast GhcRn -> TransformT m (Located (ast GhcPs)) @@ -375,7 +377,7 @@ unRenamedE dflags expr = do uniq <- show <$> uniqueSrcSpanT (anns, expr') <- either (fail . show) pure $ - parseAST @(ast GhcPs) dflags uniq $ + parseAST @_ @(ast GhcPs) dflags uniq $ showSDoc dflags $ ppr expr let _anns' = setPrecedingLines expr' 0 1 anns pure expr' diff --git a/plugins/hls-tactics-plugin/src/Wingman/GHC.hs b/plugins/hls-tactics-plugin/src/Wingman/GHC.hs index bd48252dec..944cab82d5 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/GHC.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/GHC.hs @@ -190,9 +190,9 @@ pattern AMatch ctx pats body <- pattern SingleLet :: IdP GhcPs -> [Pat GhcPs] -> HsExpr GhcPs -> HsExpr GhcPs -> HsExpr GhcPs pattern SingleLet bind pats val expr <- HsLet _ - (L _ (HsValBinds _ + (HsValBinds _ (ValBinds _ (bagToList -> - [L _ (FunBind _ (L _ bind) (MG _ (L _ [L _ (AMatch _ pats val)]) _) _ _)]) _))) + [(L _ (FunBind _ (L _ bind) (MG _ (L _ [L _ (AMatch _ pats val)]) _) _ _))]) _)) (L _ expr) diff --git a/stack-9.2.1.yaml b/stack-9.2.1.yaml new file mode 100644 index 0000000000..690e8a1a03 --- /dev/null +++ b/stack-9.2.1.yaml @@ -0,0 +1,121 @@ +resolver: nightly-2021-12-22 +compiler: ghc-9.2.1 + +packages: +- . +- ./hie-compat +- ./hls-graph +- ./ghcide/ +- ./hls-plugin-api +- ./hls-test-utils +- ./shake-bench +- ./plugins/hls-call-hierarchy-plugin +- ./plugins/hls-class-plugin +# - ./plugins/hls-haddock-comments-plugin +# - ./plugins/hls-eval-plugin +- ./plugins/hls-explicit-imports-plugin +- ./plugins/hls-qualify-imported-names-plugin +- ./plugins/hls-refine-imports-plugin +# - ./plugins/hls-hlint-plugin +# - ./plugins/hls-rename-plugin +# - ./plugins/hls-retrie-plugin +# - ./plugins/hls-splice-plugin +# - ./plugins/hls-tactics-plugin +# - ./plugins/hls-brittany-plugin +# - ./plugins/hls-stylish-haskell-plugin +# - ./plugins/hls-floskell-plugin +# - ./plugins/hls-fourmolu-plugin +- ./plugins/hls-pragmas-plugin +- ./plugins/hls-module-name-plugin +# - ./plugins/hls-ormolu-plugin +# - ./plugins/hls-alternate-number-format-plugin + +extra-deps: + +# ghc-9.2 specific +# boot packages +- Cabal-3.6.2.0 +- directory-1.3.7.0 +- ghc-boot-9.2.1 +- process-1.6.13.2 +- time-1.12.1 + + +- bytestring-encoding-0.1.1.0 +- dependent-map-0.4.0.0 +- dependent-sum-0.7.1.0 +- extra-1.7.9 # for ghcide, https://github.com/haskell/haskell-language-server/pull/2131 +- hspec-2.7.10 # for hls-test-utils +- hspec-core-2.7.10 # for hls-test-utils +- some-1.0.2 # for dependent-sum, https://github.com/obsidiansystems/dependent-sum/issues/66 +- dependent-sum-template-0.1.1.1 +- floskell-0.10.6 +- heapsize-0.3.0.1 +- hiedb-0.4.1.0 +- implicit-hie-0.1.2.6 +- implicit-hie-cradle-0.3.0.5 +- monad-dijkstra-0.1.1.3 +- retrie-1.1.0.0 +- lsp-1.2.0.1 +- lsp-types-1.3.0.1 +- lsp-test-0.14.0.1 + +# shake-bench dependencies +- Chart-1.9.3 +- Chart-diagrams-1.9.3 +- SVGFonts-1.7.0.1 # for Chart-diagrams, https://github.com/timbod7/haskell-chart/issues/232 +- diagrams-postscript-1.5 +- statestack-0.3 +- operational-0.2.4.1 + +# currently needed for ghcide>extra, etc. +allow-newer: true + +ghc-options: + "$everything": -haddock + +configure-options: + ghcide: + - --disable-library-for-ghci + haskell-language-server: + - --disable-library-for-ghci + heapsize: + - --disable-library-for-ghci + +flags: + haskell-language-server: + pedantic: true + + ignore-plugins-ghc-bounds: true + alternateNumberFormat: false + brittany: false + callhierarchy: false + class: false + eval: false + floskell: false + fourmolu: false + haddockComments: false + hlint: false + importLens: false + moduleName: false + ormolu: false + qualifyImportedNames: false + refineImports: false + retrie: false + splice: false + stylishhaskell: false + tactic: false + importLens: false + + retrie: + BuildExecutable: false + # Stack doesn't support automatic flags. + # hls-hlint-plugin: + # hlint33: true + hyphenation: + embed: true + +nix: + packages: [ icu libcxx zlib ] + +concurrent-tests: false diff --git a/test/functional/FunctionalCodeAction.hs b/test/functional/FunctionalCodeAction.hs index 3d160931b7..9c0beaeb7a 100644 --- a/test/functional/FunctionalCodeAction.hs +++ b/test/functional/FunctionalCodeAction.hs @@ -344,20 +344,22 @@ unusedTermTests = testGroup "unused term code actions" [ liftIO $ do let cas = map fromAction res kinds = map (^. L.kind) cas - nub kinds @?= [Just CodeActionRefactorInline, Just CodeActionRefactorExtract, Just CodeActionQuickFix] + assertBool "Test precondition failed" $ Just CodeActionQuickFix `elem` kinds -- Verify that that when we set the only parameter, we only get actions -- of the right kind. ResponseMessage _ _ (Right (List res)) <- request STextDocumentCodeAction params liftIO $ do let cas = map fromAction res kinds = map (^. L.kind) cas - nub kinds @?= nub [Just CodeActionRefactorInline, Just CodeActionRefactorExtract] + assertBool "Quick fixes should have been filtered out" + $ Just CodeActionQuickFix `notElem` kinds ] expectFailIfGhc9 :: String -> TestTree -> TestTree expectFailIfGhc9 reason = case ghcVersion of GHC90 -> expectFailBecause reason + GHC92 -> expectFailBecause reason _ -> id disableWingman :: Session () diff --git a/test/functional/Main.hs b/test/functional/Main.hs index 93072b52ac..9cf61e05d7 100644 --- a/test/functional/Main.hs +++ b/test/functional/Main.hs @@ -27,7 +27,7 @@ main = defaultTestRunner , ignoreInEnv [HostOS Windows, GhcVer GHC90] "Tests gets stuck in ci" $ Deferred.tests , Definition.tests , Diagnostic.tests - , ignoreInEnv [HostOS Windows, GhcVer GHC90] "Tests gets stuck in ci" $ Format.tests + , ignoreInEnv [HostOS Windows, GhcVer GHC90, GhcVer GHC92] "Tests gets stuck in ci" $ Format.tests , FunctionalBadProject.tests , FunctionalCodeAction.tests , HieBios.tests diff --git a/test/testdata/hie.yaml b/test/testdata/hie.yaml index 71812fbd6d..a8703fdd69 100644 --- a/test/testdata/hie.yaml +++ b/test/testdata/hie.yaml @@ -1,6 +1,7 @@ cradle: direct: arguments: + - "-Wmissing-signatures" - "CodeActionImport" - "CodeActionOnly" - "CodeActionRename"