1
- {-# LANGUAGE LambdaCase #-}
2
- {-# LANGUAGE ScopedTypeVariables #-}
1
+ {-# LANGUAGE DerivingStrategies #-}
2
+ {-# LANGUAGE GeneralizedNewtypeDeriving #-}
3
+ {-# LANGUAGE LambdaCase #-}
4
+ {-# LANGUAGE ScopedTypeVariables #-}
3
5
4
6
module Ide.LocalBindings
5
- ( Bindings ( .. )
6
- , bindings
7
+ ( Bindings
8
+ , getLocalScope
7
9
, mostSpecificSpan
8
10
, holify
11
+ , bindings
9
12
) where
10
13
11
- import Bag
12
- import Control.Lens
13
- import Control.Monad
14
- import Data.Data.Lens
15
14
import Data.Function
16
15
import Data.Generics
16
+ import Data.IntervalMap.FingerTree (IntervalMap , Interval (.. ))
17
+ import qualified Data.IntervalMap.FingerTree as IM
17
18
import Data.List
18
- import Data.Map (Map )
19
19
import qualified Data.Map as M
20
20
import Data.Maybe
21
21
import Data.Ord
22
22
import Data.Set (Set )
23
23
import qualified Data.Set as S
24
- import Development.IDE.GHC.Compat (TypecheckedModule (.. ), GhcTc , noExt , RefMap , identType )
25
- import HsBinds
24
+ import Development.IDE.GHC.Compat (GhcTc , RefMap , identType , noExt )
26
25
import HsExpr
27
26
import Id
28
27
import OccName
29
28
import SrcLoc
30
29
30
+ ------------------------------------------------------------------------------
31
+ -- | Turn a 'RealSrcSpan' into an 'Interval'.
32
+ realSrcSpanToInterval :: RealSrcSpan -> Interval RealSrcLoc
33
+ realSrcSpanToInterval rss =
34
+ Interval
35
+ (realSrcSpanStart rss)
36
+ (realSrcSpanEnd rss)
37
+
31
38
32
39
------------------------------------------------------------------------------
33
- -- | WIP function for getting 'bindings' from HIE, rather than stupidly
34
- -- traversing the entire AST.
35
- _bindigsHIE :: RefMap -> SrcSpan -> Set Id
36
- _bindigsHIE _ (UnhelpfulSpan _) = mempty
37
- _bindigsHIE refmap (RealSrcSpan span ) = S. fromList $ do
40
+ -- | Compute which identifiers are in scpoe at every point in the AST. Use
41
+ -- 'getLocalScope' to find the results.
42
+ bindings :: RefMap -> Bindings
43
+ bindings refmap = Bindings $ foldr (uncurry IM. insert) mempty $ do
38
44
(ident, refs) <- M. toList refmap
39
- Right _name <- pure ident
45
+ Right name <- pure ident
40
46
(ref_span, ident_details) <- refs
41
- Just _ty <- pure $ identType ident_details
42
- guard $ ref_span `containsSpan` span
43
- mempty
44
-
45
-
47
+ Just ty <- pure $ identType ident_details
48
+ pure ( realSrcSpanToInterval ref_span
49
+ , S. singleton $ mkVanillaGlobal name ty
50
+ )
46
51
47
52
------------------------------------------------------------------------------
48
53
-- | The available bindings at every point in a Haskell tree.
49
- data Bindings = Bindings
50
- { bGlobalBinds :: Set Id
51
- , bLocalBinds :: Map SrcSpan (Set Id )
52
- } deriving (Eq , Ord )
53
-
54
- instance Semigroup Bindings where
55
- Bindings g1 l1 <> Bindings g2 l2 = Bindings (g1 <> g2) (l1 <> l2)
56
-
57
- instance Monoid Bindings where
58
- mempty = Bindings mempty mempty
59
-
60
-
61
- ------------------------------------------------------------------------------
62
- -- | Determine what bindings are in scope at every point in a program.
63
- --
64
- -- **WARNING:** This doesn't find bindings inside of TH splices or arrow syntax
65
- -- --- and possibly other obscure pieces of the AST.
66
- bindings :: TypecheckedModule -> Bindings
67
- bindings = uncurry Bindings . bindsBindings mempty . tm_typechecked_source
54
+ newtype Bindings = Bindings
55
+ { getBindings :: IntervalMap RealSrcLoc (Set Id )
56
+ } deriving newtype (Eq , Ord , Semigroup , Monoid )
68
57
69
58
70
59
------------------------------------------------------------------------------
71
- -- | Helper function for implementing 'binding'.
72
- --
73
- -- **WARNING:** This doesn't yet work over TH splices or arrow syntax --- and
74
- -- possibly other obscure pieces of the AST.
75
- dataBindings :: Data a => S. Set Id -> a -> M. Map SrcSpan (S. Set Id )
76
- dataBindings in_scope = foldMapOf biplate $ cool collect
77
- where
78
- cool
79
- :: (HsExpr GhcTc -> M. Map SrcSpan (S. Set Id ))
80
- -> LHsExpr GhcTc -> M. Map SrcSpan (S. Set Id )
81
- cool f (L src expr) = M. union (f expr) (M. singleton src in_scope)
82
-
83
- collect :: HsExpr GhcTc -> M. Map SrcSpan (S. Set Id )
84
- collect (HsLam _ matches) = matchGroupBindings in_scope matches
85
- collect (HsLamCase _ matches) = matchGroupBindings in_scope matches
86
- collect (HsCase _ scrutinee matches) =
87
- M. union (dataBindings in_scope scrutinee) $ matchGroupBindings in_scope matches
88
- collect (HsLet _ (L _ binds) expr) =
89
- let (new, res) = localBindsBindings in_scope binds
90
- in_scope' = S. union new in_scope
91
- in M. union (dataBindings in_scope' expr) res
92
- collect (HsVar _ _) = mempty
93
- collect (HsUnboundVar _ _) = mempty
94
- collect (HsConLikeOut _ _) = mempty
95
- collect (HsRecFld _ _) = mempty
96
- collect (HsOverLabel _ _ _) = mempty
97
- collect (HsIPVar _ _) = mempty
98
- collect (HsOverLit _ _) = mempty
99
- collect (HsLit _ _) = mempty
100
- collect (HsApp _ a b) = M. union (dataBindings in_scope a) (dataBindings in_scope b)
101
- collect (HsAppType _ _ a) = dataBindings in_scope a
102
- collect (OpApp _ a b c) =
103
- mconcat
104
- [ dataBindings in_scope a
105
- , dataBindings in_scope b
106
- , dataBindings in_scope c
107
- ]
108
- collect (NegApp _ a _) = dataBindings in_scope a
109
- collect (HsPar _ a) = dataBindings in_scope a
110
- collect (SectionL _ a b) =
111
- mconcat
112
- [ dataBindings in_scope a
113
- , dataBindings in_scope b
114
- ]
115
- collect (SectionR _ a b) =
116
- mconcat
117
- [ dataBindings in_scope a
118
- , dataBindings in_scope b
119
- ]
120
- collect (ExplicitTuple _ a _) = dataBindings in_scope a
121
- collect (ExplicitSum _ _ _ a) = dataBindings in_scope a
122
- collect (HsIf _ _ a b c) =
123
- mconcat
124
- [ dataBindings in_scope a
125
- , dataBindings in_scope b
126
- , dataBindings in_scope c
127
- ]
128
- collect (HsMultiIf _ a) = dataBindings in_scope a
129
- collect (HsDo _ _ a) = dataBindings in_scope a
130
- collect (ExplicitList _ _ a) = dataBindings in_scope a
131
- collect (RecordCon _ _ a) = dataBindings in_scope a
132
- collect (RecordUpd _ _ a) = dataBindings in_scope a
133
- collect (ExprWithTySig _ _ a) = dataBindings in_scope a
134
- collect (ArithSeq _ _ a) = dataBindings in_scope a
135
- collect (HsSCC _ _ _ a) = dataBindings in_scope a
136
- collect (HsBracket _ a) = dataBindings in_scope a
137
- collect (HsStatic _ a) = dataBindings in_scope a
138
- -- TODO(sandy): This doesn't do arrow syntax
139
- collect _ = mempty
140
-
141
-
142
- ------------------------------------------------------------------------------
143
- -- | Map the binds from a match group into over their containing spans.
144
- matchGroupBindings :: S. Set Id -> MatchGroup GhcTc (LHsExpr GhcTc ) -> M. Map SrcSpan (S. Set Id )
145
- matchGroupBindings _ (XMatchGroup _) = M. empty
146
- matchGroupBindings in_scope (MG _ (L _ alts) _) = M. fromList $ do
147
- L _ (Match _ _ pats body) <- alts
148
- let bound = S. filter isId $ everything S. union (mkQ S. empty S. singleton) pats
149
- M. toList $ dataBindings (S. union bound in_scope) body
150
-
151
-
152
- ------------------------------------------------------------------------------
153
- -- | Map the binds from a local binds into over their containing spans.
154
- localBindsBindings :: S. Set Id -> HsLocalBindsLR GhcTc GhcTc -> (S. Set Id , M. Map SrcSpan (S. Set Id ))
155
- localBindsBindings in_scope (HsValBinds _ (ValBinds _ binds _sigs)) = bindsBindings in_scope binds
156
- localBindsBindings in_scope (HsValBinds _ (XValBindsLR (NValBinds groups _sigs))) =
157
- flip foldMap groups $ bindsBindings in_scope . snd
158
- localBindsBindings _ _ = (mempty , mempty )
159
-
160
-
161
- ------------------------------------------------------------------------------
162
- -- | Map the binds from a hsbindlr into over their containing spans.
163
- bindsBindings :: S. Set Id -> Bag (LHsBindLR GhcTc GhcTc ) -> (S. Set Id , M. Map SrcSpan (S. Set Id ))
164
- bindsBindings in_scope binds =
165
- flip foldMap (fmap unLoc $ bagToList binds) $ \ case
166
- FunBind _ (L _ name) matches _ _ ->
167
- (S. singleton name, matchGroupBindings (S. insert name in_scope) matches)
168
- PatBind _ pat rhs _ ->
169
- let bound = S. filter isId $ everything S. union (mkQ S. empty S. singleton) pat
170
- in (bound, dataBindings (S. union bound in_scope) rhs)
171
- AbsBinds _ _ _ _ _ binds' _ -> bindsBindings in_scope binds'
172
- VarBind _ name c _ -> (S. singleton name, dataBindings in_scope c)
173
- PatSynBind _ _ -> mempty
174
- XHsBindsLR _ -> mempty
60
+ -- | Given a 'Bindings' get every identifier in scope at the given
61
+ -- 'RealSrcSpan',
62
+ getLocalScope :: Bindings -> RealSrcSpan -> Set Id
63
+ getLocalScope bs rss
64
+ = foldMap snd
65
+ $ IM. dominators (realSrcSpanToInterval rss)
66
+ $ getBindings bs
175
67
176
68
177
69
------------------------------------------------------------------------------
@@ -196,19 +88,18 @@ mostSpecificSpan span z
196
88
_ -> [] )
197
89
$ z
198
90
91
+
199
92
------------------------------------------------------------------------------
200
93
-- | Convert an HsVar back into an HsUnboundVar if it isn't actually in scope.
201
94
-- TODO(sandy): this will throw away the type >:(
202
95
holify :: Bindings -> LHsExpr GhcTc -> LHsExpr GhcTc
203
- holify ( Bindings _ local) v@ (L span (HsVar _ (L _ var))) =
96
+ holify bs v@ (L s @ ( RealSrcSpan span ) (HsVar _ (L _ var))) =
204
97
let occ = occName var
205
- in case M. lookup span local of
206
- Nothing -> v
207
- Just binds ->
208
- -- Make sure the binding is not in scope and that it begins with an
209
- -- underscore
210
- case not (S. member var binds) && take 1 (occNameString occ) == " _" of
211
- True -> L span $ HsUnboundVar noExt $ TrueExprHole occ
212
- False -> v
98
+ binds = getLocalScope bs span
99
+ in -- Make sure the binding is not in scope and that it begins with an
100
+ -- underscore
101
+ case not (S. member var binds) && take 1 (occNameString occ) == " _" of
102
+ True -> L s $ HsUnboundVar noExt $ TrueExprHole occ
103
+ False -> v
213
104
holify _ v = v
214
105
0 commit comments