1
- {-# LANGUAGE GADTs #-}
2
- {-# LANGUAGE LambdaCase #-}
3
- {-# LANGUAGE NumDecimals #-}
4
- {-# LANGUAGE OverloadedStrings #-}
5
- {-# LANGUAGE TypeApplications #-}
1
+ {-# LANGUAGE FlexibleContexts #-}
2
+ {-# LANGUAGE GADTs #-}
3
+ {-# LANGUAGE LambdaCase #-}
4
+ {-# LANGUAGE NumDecimals #-}
5
+ {-# LANGUAGE OverloadedStrings #-}
6
+ {-# LANGUAGE ScopedTypeVariables #-}
7
+ {-# LANGUAGE TypeApplications #-}
6
8
7
9
-- | A plugin that uses tactics to synthesize code
8
10
module Ide.Plugin.Tactic
@@ -37,8 +39,8 @@ import Development.IDE.Core.Shake (useWithStale, IdeState (..))
37
39
import Development.IDE.GHC.Compat
38
40
import Development.IDE.GHC.Error (realSrcSpanToRange )
39
41
import Development.IDE.GHC.ExactPrint
40
- import Development.IDE.Spans.LocalBindings (getDefiningBindings )
41
- import Development.Shake (Action )
42
+ import Development.IDE.Spans.LocalBindings (Bindings , getDefiningBindings )
43
+ import Development.Shake (RuleResult , Action )
42
44
import qualified FastString
43
45
import Ide.Plugin.Tactic.CaseSplit
44
46
import Ide.Plugin.Tactic.Context
@@ -58,6 +60,7 @@ import Prelude hiding (span)
58
60
import SrcLoc (containsSpan )
59
61
import System.Timeout
60
62
import TcRnTypes (tcg_binds )
63
+ import Development.Shake.Classes
61
64
62
65
63
66
descriptor :: PluginId -> PluginDescriptor IdeState
@@ -86,6 +89,18 @@ tcCommandName = T.pack . show
86
89
runIde :: IdeState -> Action a -> IO a
87
90
runIde state = runAction " tactic" state
88
91
92
+ runStaleIde
93
+ :: forall a r
94
+ . ( r ~ RuleResult a
95
+ , Eq a , Hashable a , Binary a , Show a , Typeable a , NFData a
96
+ , Show r , Typeable r , NFData r
97
+ )
98
+ => IdeState
99
+ -> NormalizedFilePath
100
+ -> a
101
+ -> MaybeT IO (r , PositionMapping )
102
+ runStaleIde state nfp a = MaybeT $ runIde state $ useWithStale a nfp
103
+
89
104
90
105
codeActionProvider :: PluginMethodHandler IdeState TextDocumentCodeAction
91
106
codeActionProvider state plId (CodeActionParams _ _ (TextDocumentIdentifier uri) range _ctx)
@@ -114,29 +129,54 @@ judgementForHole
114
129
-> Range
115
130
-> MaybeT IO (Range , Judgement , Context , DynFlags )
116
131
judgementForHole state nfp range = do
117
- (asts, amapping) <- MaybeT $ runIde state $ useWithStale GetHieAst nfp
118
- range' <- liftMaybe $ fromCurrentRange amapping range
132
+ (asts, amapping) <- runStaleIde state nfp GetHieAst
133
+ case asts of
134
+ HAR _ _ _ _ (HieFromDisk _) -> fail " Need a fresh hie file"
135
+ HAR _ hf _ _ HieFresh -> do
136
+ (binds, _) <- runStaleIde state nfp GetBindings
137
+ (tcmod, _) <- runStaleIde state nfp TypeCheck
138
+ (rss, g) <- liftMaybe $ getSpanAndTypeAtHole amapping range hf
139
+ resulting_range <- liftMaybe $ toCurrentRange amapping $ realSrcSpanToRange rss
140
+ let (jdg, ctx) = mkJudgementAndContext g binds rss tcmod
141
+ dflags <- getIdeDynflags state nfp
142
+ pure (resulting_range, jdg, ctx, dflags)
119
143
120
- (binds, _) <- MaybeT $ runIde state $ useWithStale GetBindings nfp
121
144
145
+ getIdeDynflags
146
+ :: IdeState
147
+ -> NormalizedFilePath
148
+ -> MaybeT IO DynFlags
149
+ getIdeDynflags state nfp = do
122
150
-- Ok to use the stale 'ModIface', since all we need is its 'DynFlags'
123
151
-- which don't change very often.
124
- ((modsum,_), _) <- MaybeT $ runIde state $ useWithStale GetModSummaryWithoutTimestamps nfp
125
- let dflags = ms_hspp_opts modsum
152
+ ((modsum,_), _) <- runStaleIde state nfp GetModSummaryWithoutTimestamps
153
+ pure $ ms_hspp_opts modsum
126
154
127
- case asts of
128
- (HAR _ hf _ _ kind) -> do
129
- (rss, g) <- liftMaybe $ join $ listToMaybe $ M. elems $ flip M. mapWithKey (getAsts hf) $ \ fs ast ->
130
- case selectSmallestContaining (rangeToRealSrcSpan (FastString. unpackFS fs) range') ast of
131
- Nothing -> Nothing
132
- Just ast' -> do
133
- let info = nodeInfo ast'
134
- ty <- listToMaybe $ nodeType info
135
- guard $ (" HsUnboundVar" ," HsExpr" ) `S.member` nodeAnnotations info
136
- pure (nodeSpan ast', ty)
137
155
138
- resulting_range <- liftMaybe $ toCurrentRange amapping $ realSrcSpanToRange rss
139
- (tcmod, _) <- MaybeT $ runIde state $ useWithStale TypeCheck nfp
156
+ getSpanAndTypeAtHole
157
+ :: PositionMapping
158
+ -> Range
159
+ -> HieASTs b
160
+ -> Maybe (Span , b )
161
+ getSpanAndTypeAtHole amapping range hf = do
162
+ range' <- fromCurrentRange amapping range
163
+ join $ listToMaybe $ M. elems $ flip M. mapWithKey (getAsts hf) $ \ fs ast ->
164
+ case selectSmallestContaining (rangeToRealSrcSpan (FastString. unpackFS fs) range') ast of
165
+ Nothing -> Nothing
166
+ Just ast' -> do
167
+ let info = nodeInfo ast'
168
+ ty <- listToMaybe $ nodeType info
169
+ guard $ (" HsUnboundVar" ," HsExpr" ) `S.member` nodeAnnotations info
170
+ pure (nodeSpan ast', ty)
171
+
172
+
173
+ mkJudgementAndContext
174
+ :: Type
175
+ -> Bindings
176
+ -> RealSrcSpan
177
+ -> TcModuleResult
178
+ -> (Judgement , Context )
179
+ mkJudgementAndContext g binds rss tcmod = do
140
180
let tcg = tmrTypechecked tcmod
141
181
tcs = tcg_binds tcg
142
182
ctx = mkContext
@@ -147,18 +187,12 @@ judgementForHole state nfp range = do
147
187
local_hy = spliceProvenance top_provs
148
188
$ hypothesisFromBindings rss binds
149
189
cls_hy = contextMethodHypothesis ctx
150
- case kind of
151
- HieFromDisk _hf' ->
152
- fail " Need a fresh hie file"
153
- HieFresh ->
154
- pure ( resulting_range
155
- , mkFirstJudgement
156
- (local_hy <> cls_hy)
157
- (isRhsHole rss tcs)
158
- g
159
- , ctx
160
- , dflags
161
- )
190
+ in ( mkFirstJudgement
191
+ (local_hy <> cls_hy)
192
+ (isRhsHole rss tcs)
193
+ g
194
+ , ctx
195
+ )
162
196
163
197
spliceProvenance
164
198
:: Map OccName Provenance
@@ -195,6 +229,7 @@ tacticCmd tac state (TacticParams uri range var_name)
195
229
tacticCmd _ _ _ =
196
230
pure $ Left $ mkErr InvalidRequest " Bad URI"
197
231
232
+
198
233
mkErr :: ErrorCode -> T. Text -> ResponseError
199
234
mkErr code err = ResponseError code err Nothing
200
235
@@ -278,6 +313,7 @@ mergeFunBindMatches _ _ _ = Left "mergeFunBindMatches: called on something that
278
313
noteT :: String -> TransformT (Either String ) a
279
314
noteT = lift . Left
280
315
316
+
281
317
------------------------------------------------------------------------------
282
318
-- | Helper function to route 'mergeFunBindMatches' into the right place in an
283
319
-- AST --- correctly dealing with inserting into instance declarations.
0 commit comments