Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit ff9a5b2

Browse files
fendormpickering
authored andcommitted
Do not traverse into Generated bindings when creating TypeMap (#1372)
In a module with a lot of derived type classes, such as `Cabal.LicenseId` generating the hover map was taking upwards of 2gb of memory. In future, we might still want information about these derived bindings so instead we might choose not to traverse into `Type` nodes or work out why the traversal was actually taking so long.
1 parent c49cfa0 commit ff9a5b2

File tree

3 files changed

+71
-35
lines changed

3 files changed

+71
-35
lines changed

hie-plugin-api/Haskell/Ide/Engine/Compat.hs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,25 @@ pattern FunBindType t <-
134134
GHC.FunBind (GHC.L _ (Var.varType -> t)) _ _ _ _
135135
#endif
136136

137+
pattern FunBindGen :: Type.Type -> GHC.MatchGroup GhcTc (GHC.LHsExpr GhcTc) -> GHC.HsBindLR GhcTc GhcTc
138+
pattern FunBindGen t fmatches <-
139+
#if MIN_VERSION_ghc(8, 6, 0)
140+
GHC.FunBind _ (GHC.L _ (Var.varType -> t)) fmatches _ _
141+
#elif MIN_VERSION_ghc(8, 4, 0)
142+
GHC.FunBind (GHC.L _ (Var.varType -> t)) fmatches _ _ _
143+
#else
144+
GHC.FunBind (GHC.L _ (Var.varType -> t)) fmatches _ _ _
145+
#endif
146+
147+
pattern AbsBinds :: GHC.LHsBinds GhcTc -> GHC.HsBindLR GhcTc GhcTc
148+
pattern AbsBinds bs <-
149+
#if MIN_VERSION_ghc(8, 6, 0)
150+
GHC.AbsBinds _ _ _ _ _ bs _
151+
#elif MIN_VERSION_ghc(8, 4, 0)
152+
GHC.AbsBinds _ _ _ _ bs _
153+
#else
154+
GHC.AbsBinds _ _ _ _ bs
155+
#endif
137156

138157
#if MIN_VERSION_ghc(8, 6, 0)
139158
matchGroupType :: GHC.MatchGroupTc -> GHC.Type

hie-plugin-api/Haskell/Ide/Engine/TypeMap.hs

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@ module Haskell.Ide.Engine.TypeMap where
99
import qualified Data.IntervalMap.FingerTree as IM
1010

1111
import qualified GHC
12-
import GHC ( TypecheckedModule )
12+
import GHC ( TypecheckedModule, GhcMonad )
13+
import Bag
14+
import BasicTypes
1315

1416
import Data.Data as Data
1517
import Control.Monad.IO.Class
18+
import Control.Applicative
1619
import Data.Maybe
1720
import qualified TcHsSyn
1821
import qualified CoreUtils
1922
import qualified Type
2023
import qualified Desugar
21-
import Haskell.Ide.Engine.Compat
24+
import qualified Haskell.Ide.Engine.Compat as Compat
2225

2326
import Haskell.Ide.Engine.ArtifactMap
2427

@@ -27,44 +30,57 @@ import Haskell.Ide.Engine.ArtifactMap
2730
genTypeMap :: GHC.GhcMonad m => TypecheckedModule -> m TypeMap
2831
genTypeMap tm = do
2932
let typecheckedSource = GHC.tm_typechecked_source tm
30-
hs_env <- GHC.getSession
31-
liftIO $ types hs_env typecheckedSource
33+
everythingInTypecheckedSourceM typecheckedSource
3234

3335

3436
everythingInTypecheckedSourceM
35-
:: Data x => (forall a . Data a => a -> IO TypeMap) -> x -> IO TypeMap
36-
everythingInTypecheckedSourceM = everythingButTypeM @GHC.Id
37-
37+
:: GhcMonad m => GHC.TypecheckedSource -> m TypeMap
38+
everythingInTypecheckedSourceM xs = bs
39+
where
40+
bs = foldBag (liftA2 IM.union) processBind (return IM.empty) xs
41+
42+
processBind :: GhcMonad m => GHC.LHsBindLR Compat.GhcTc Compat.GhcTc -> m TypeMap
43+
processBind x@(GHC.L (GHC.RealSrcSpan spn) b) =
44+
case b of
45+
Compat.FunBindGen t fmatches ->
46+
case GHC.mg_origin fmatches of
47+
Generated -> return IM.empty
48+
FromSource -> do
49+
im <- types fmatches
50+
return $ IM.singleton (rspToInt spn) t `IM.union` im
51+
Compat.AbsBinds bs -> everythingInTypecheckedSourceM bs
52+
_ -> types x
53+
processBind _ = return IM.empty
3854

3955
-- | Obtain details map for types.
40-
types :: GHC.HscEnv -> GHC.TypecheckedSource -> IO TypeMap
41-
types hs_env = everythingInTypecheckedSourceM (ty `combineM` fun `combineM` funBind)
56+
types :: forall m a . (GhcMonad m, Data a) => a -> m TypeMap
57+
types = everythingButTypeM @GHC.Id (ty `combineM` fun `combineM` funBind)
4258
where
43-
ty :: forall a . Data a => a -> IO TypeMap
59+
ty :: forall a' . (GhcMonad m, Data a') => a' -> m TypeMap
4460
ty term = case cast term of
4561
(Just lhsExprGhc@(GHC.L (GHC.RealSrcSpan spn) _)) ->
46-
getType hs_env lhsExprGhc >>= \case
62+
getType lhsExprGhc >>= \case
4763
Nothing -> return IM.empty
4864
Just (_, typ) -> return (IM.singleton (rspToInt spn) typ)
4965
_ -> return IM.empty
5066

51-
fun :: forall a . Data a => a -> IO TypeMap
67+
fun :: forall a' . (GhcMonad m, Data a') => a' -> m TypeMap
5268
fun term = case cast term of
5369
(Just (GHC.L (GHC.RealSrcSpan spn) hsPatType)) ->
5470
return (IM.singleton (rspToInt spn) (TcHsSyn.hsPatType hsPatType))
5571
_ -> return IM.empty
5672

57-
funBind :: forall a . Data a => a -> IO TypeMap
73+
funBind :: forall a' . (GhcMonad m, Data a') => a' -> m TypeMap
5874
funBind term = case cast term of
59-
(Just (GHC.L (GHC.RealSrcSpan spn) (FunBindType t))) ->
75+
(Just (GHC.L (GHC.RealSrcSpan spn) (Compat.FunBindType t))) ->
6076
return (IM.singleton (rspToInt spn) t)
6177
_ -> return IM.empty
6278

6379
-- | Combine two queries into one using alternative combinator.
6480
combineM
65-
:: (forall a . Data a => a -> IO TypeMap)
66-
-> (forall a . Data a => a -> IO TypeMap)
67-
-> (forall a . Data a => a -> IO TypeMap)
81+
:: (forall a . (Monad m, Data a) => a -> m TypeMap)
82+
-> (forall a . (Monad m, Data a) => a -> m TypeMap)
83+
-> (forall a . (Monad m, Data a) => a -> m TypeMap)
6884
combineM f g x = do
6985
a <- f x
7086
b <- g x
@@ -73,10 +89,10 @@ combineM f g x = do
7389
-- | Variation of "everything" that does not recurse into children of type t
7490
-- requires AllowAmbiguousTypes
7591
everythingButTypeM
76-
:: forall t
92+
:: forall t m
7793
. (Typeable t)
78-
=> (forall a . Data a => a -> IO TypeMap)
79-
-> (forall a . Data a => a -> IO TypeMap)
94+
=> (forall a . (Monad m, Data a) => a -> m TypeMap)
95+
-> (forall a . (Monad m, Data a) => a -> m TypeMap)
8096
everythingButTypeM f = everythingButM $ (,) <$> f <*> isType @t
8197

8298
-- | Returns true if a == t.
@@ -87,8 +103,8 @@ isType _ = isJust $ eqT @a @b
87103
-- | Variation of "everything" with an added stop condition
88104
-- Just like 'everything', this is stolen from SYB package.
89105
everythingButM
90-
:: (forall a . Data a => a -> (IO TypeMap, Bool))
91-
-> (forall a . Data a => a -> IO TypeMap)
106+
:: forall m . (forall a . (Monad m, Data a) => a -> (m TypeMap, Bool))
107+
-> (forall a . (Monad m, Data a) => a -> m TypeMap)
92108
everythingButM f x = do
93109
let (v, stop) = f x
94110
if stop
@@ -111,27 +127,28 @@ everythingButM f x = do
111127
--
112128
-- See #16233<https://gitlab.haskell.org/ghc/ghc/issues/16233>
113129
getType
114-
:: GHC.HscEnv -> GHC.LHsExpr GhcTc -> IO (Maybe (GHC.SrcSpan, Type.Type))
115-
getType hs_env e@(GHC.L spn e') =
130+
:: GhcMonad m => GHC.LHsExpr Compat.GhcTc -> m (Maybe (GHC.SrcSpan, Type.Type))
131+
getType e@(GHC.L spn e') =
116132
-- Some expression forms have their type immediately available
117133
let
118134
tyOpt = case e' of
119-
HsOverLitType t -> Just t
120-
HsLitType t -> Just t
121-
HsLamType t -> Just t
122-
HsLamCaseType t -> Just t
123-
HsCaseType t -> Just t
124-
ExplicitListType t -> Just t
125-
ExplicitSumType t -> Just t
126-
HsMultiIfType t -> Just t
135+
Compat.HsOverLitType t -> Just t
136+
Compat.HsLitType t -> Just t
137+
Compat.HsLamType t -> Just t
138+
Compat.HsLamCaseType t -> Just t
139+
Compat.HsCaseType t -> Just t
140+
Compat.ExplicitListType t -> Just t
141+
Compat.ExplicitSumType t -> Just t
142+
Compat.HsMultiIfType t -> Just t
127143

128144
_ -> Nothing
129145
in case tyOpt of
130146
Just t -> return $ Just (spn ,t)
131147
Nothing
132148
| skipDesugaring e' -> pure Nothing
133149
| otherwise -> do
134-
(_, mbe) <- Desugar.deSugarExpr hs_env e
150+
hsc_env <- GHC.getSession
151+
(_, mbe) <- liftIO $ Desugar.deSugarExpr hsc_env e
135152
let res = (spn, ) . CoreUtils.exprType <$> mbe
136153
pure res
137154
where

test/unit/GhcModPluginSpec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,9 +486,9 @@ ghcmodSpec =
486486
, (Range (toPos (33, 15)) (toPos (33, 19)), "Int -> Test -> ShowS")
487487
, (Range (toPos (33, 15)) (toPos (33, 19)), "Test -> String")
488488
, (Range (toPos (33, 15)) (toPos (33, 19)), "[Test] -> ShowS")
489-
, (Range (toPos (33, 15)) (toPos (33, 19)), "Int -> Test -> ShowS")
490489
#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0)))
491490
#else
491+
, (Range (toPos (33, 15)) (toPos (33, 19)), "Int -> Test -> ShowS")
492492
, (Range (toPos (33, 15)) (toPos (33, 19)), "[Test] -> ShowS")
493493
#endif
494494
]
@@ -505,10 +505,10 @@ ghcmodSpec =
505505
[ (Range (toPos (33, 21)) (toPos (33, 23)), "(Test -> Test -> Bool) -> (Test -> Test -> Bool) -> Eq Test")
506506
, (Range (toPos (33, 21)) (toPos (33, 23)), "Test -> Test -> Bool")
507507
, (Range (toPos (33, 21)) (toPos (33, 23)), "Test -> Test -> Bool")
508-
, (Range (toPos (33, 21)) (toPos (33, 23)), "Test -> Test -> Bool")
509508
#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0)))
510509
#else
511510
, (Range (toPos (33, 21)) (toPos (33, 23)), "Test -> Test -> Bool")
511+
, (Range (toPos (33, 21)) (toPos (33, 23)), "Test -> Test -> Bool")
512512
#endif
513513
]
514514
testCommand testPlugins act "ghcmod" "type" arg res

0 commit comments

Comments
 (0)