Skip to content

Commit cd9467d

Browse files
committed
Jump to instance definition and explain typeclass evidence
1 parent b970e25 commit cd9467d

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

ghcide/src/Development/IDE/Core/Actions.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ getDefinition :: NormalizedFilePath -> Position -> IdeAction (Maybe [Location])
8888
getDefinition file pos = runMaybeT $ do
8989
ide <- ask
9090
opts <- liftIO $ getIdeOptionsIO ide
91-
(HAR _ hf _ _ _, mapping) <- useE GetHieAst file
91+
(hf, mapping) <- useE GetHieAst file
9292
(ImportMap imports, _) <- useE GetImportMap file
9393
!pos' <- MaybeT (pure $ fromCurrentPosition mapping pos)
9494
hiedb <- lift $ asks hiedb

ghcide/src/Development/IDE/Spans/AtPoint.hs

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,20 @@ import qualified Data.Text as T
5353

5454
import qualified Data.Array as A
5555
import Data.Either
56-
import Data.List (isSuffixOf)
5756
import Data.List.Extra (dropEnd1, nubOrd)
5857

5958
import HieDb hiding (pointCommand)
6059
import System.Directory (doesFileExist)
6160

61+
#if MIN_VERSION_ghc(9,0,1)
62+
import qualified Outputable as O
63+
import Data.Tree
64+
import qualified Data.Tree as T
65+
import Data.List (isSuffixOf, sortOn)
66+
#else
67+
import Data.List (isSuffixOf)
68+
#endif
69+
6270
-- | Gives a Uri for the module, given the .hie file location and the the module info
6371
-- The Bool denotes if it is a boot module
6472
type LookupModule m = FilePath -> ModuleName -> Unit -> Bool -> MaybeT m Uri
@@ -155,7 +163,13 @@ documentHighlight
155163
-> MaybeT m [DocumentHighlight]
156164
documentHighlight hf rf pos = pure highlights
157165
where
158-
ns = concat $ pointCommand hf pos (rights . M.keys . getNodeIds)
166+
#if MIN_VERSION_ghc(9,0,1)
167+
-- We don't want to show document highlights for evidence variables, which is invisible
168+
notEvidence = not . any isEvidenceContext . identInfo
169+
#else
170+
notEvidence = const True
171+
#endif
172+
ns = concat $ pointCommand hf pos (rights . M.keys . M.filter notEvidence . getNodeIds)
159173
highlights = do
160174
n <- ns
161175
ref <- fromMaybe [] (M.lookup (Right n) rf)
@@ -185,7 +199,7 @@ gotoDefinition
185199
-> LookupModule m
186200
-> IdeOptions
187201
-> M.Map ModuleName NormalizedFilePath
188-
-> HieASTs a
202+
-> HieAstResult
189203
-> Position
190204
-> MaybeT m [Location]
191205
gotoDefinition hiedb getHieFile ideOpts imports srcSpans pos
@@ -198,7 +212,7 @@ atPoint
198212
-> DocAndKindMap
199213
-> Position
200214
-> Maybe (Maybe Range, [T.Text])
201-
atPoint IdeOptions{} (HAR _ hf _ _ kind) (DKMap dm km) pos = listToMaybe $ pointCommand hf pos hoverInfo
215+
atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) _rf _ kind) (DKMap dm km) pos = listToMaybe $ pointCommand hf pos hoverInfo
202216
where
203217
-- Hover info for values/data
204218
hoverInfo ast = (Just range, prettyNames ++ pTypes)
@@ -211,12 +225,21 @@ atPoint IdeOptions{} (HAR _ hf _ _ kind) (DKMap dm km) pos = listToMaybe $ point
211225

212226
wrapHaskell x = "\n```haskell\n"<>x<>"\n```\n"
213227
info = nodeInfoH kind ast
214-
names = M.assocs $ nodeIdentifiers info
228+
names =
229+
#if MIN_VERSION_ghc(9,0,1)
230+
sortOn (any isEvidenceUse . identInfo . snd) $
231+
#endif
232+
M.assocs $ nodeIdentifiers info
215233
types = nodeType info
216234

217235
prettyNames :: [T.Text]
218236
prettyNames = map prettyName names
219-
prettyName (Right n, dets) = T.unlines $
237+
prettyName (Right n, dets)
238+
#if MIN_VERSION_ghc(9,0,1)
239+
| any isEvidenceUse (identInfo dets) = maybe "" (showSD . renderEvidenceTree) (getEvidenceTree _rf n) <> "\n"
240+
| otherwise
241+
#endif
242+
= T.unlines $
220243
wrapHaskell (showNameWithoutUniques n <> maybe "" (" :: " <>) ((prettyType <$> identType dets) <|> maybeKind))
221244
: definedAt n
222245
++ catMaybes [ T.unlines . spanDocToMarkdown <$> lookupNameEnv dm n
@@ -225,9 +248,12 @@ atPoint IdeOptions{} (HAR _ hf _ _ kind) (DKMap dm km) pos = listToMaybe $ point
225248
prettyName (Left m,_) = showGhc m
226249

227250
prettyTypes = map (("_ :: "<>) . prettyType) types
228-
prettyType t = case kind of
229-
HieFresh -> showGhc t
230-
HieFromDisk full_file -> showGhc $ hieTypeToIface $ recoverFullType t (hie_types full_file)
251+
prettyType = showSD . expandType
252+
253+
expandType :: a -> SDoc
254+
expandType t = case kind of
255+
HieFresh -> ppr t
256+
HieFromDisk full_file -> ppr $ hieTypeToIface $ recoverFullType t (hie_types full_file)
231257

232258
definedAt name =
233259
-- do not show "at <no location info>" and similar messages
@@ -236,6 +262,43 @@ atPoint IdeOptions{} (HAR _ hf _ _ kind) (DKMap dm km) pos = listToMaybe $ point
236262
UnhelpfulLoc {} | isInternalName name || isSystemName name -> []
237263
_ -> ["*Defined " <> T.pack (showSDocUnsafe $ pprNameDefnLoc name) <> "*"]
238264

265+
#if MIN_VERSION_ghc(9,0,1)
266+
-- We want to render the root constraint even if it is a let,
267+
-- but we don't want to render any subsequent lets
268+
renderEvidenceTree :: Tree (EvidenceInfo a) -> SDoc
269+
-- However, if the root constraint is simply an indirection (via let) to a single other constraint,
270+
-- we can still skip rendering it
271+
renderEvidenceTree (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_)}) [x])
272+
= renderEvidenceTree x
273+
renderEvidenceTree (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_), ..}) xs)
274+
= hang (text "- Evidence of constraint `" O.<> expandType evidenceType O.<> "`") 2 $
275+
vcat $ text "depending on:" : map renderEvidenceTree' xs
276+
renderEvidenceTree x = renderEvidenceTree' x
277+
278+
-- renderEvidenceTree' skips let bound evidence variables and prints the children directly
279+
renderEvidenceTree' (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_)}) xs)
280+
= vcat (map renderEvidenceTree' xs)
281+
renderEvidenceTree' (T.Node (EvidenceInfo{..}) xs)
282+
= hang (text "- Evidence of constraint `" O.<> expandType evidenceType O.<> "`") 2 $
283+
vcat $ map (text . T.unpack) (definedAt evidenceVar)
284+
++ [printDets evidenceSpan evidenceDetails (null xs)]
285+
++ map renderEvidenceTree' xs
286+
287+
printDets :: RealSrcSpan -> Maybe (EvVarSource, Scope, Maybe Span) -> Bool -> SDoc
288+
printDets _ Nothing True = text ""
289+
printDets _ Nothing False = text "constructed using:"
290+
printDets ospn (Just (src,_,mspn)) _ = pprSrc
291+
$$ text "at" <+> ppr spn
292+
where
293+
-- Use the bind span if we have one, else use the occurence span
294+
spn = fromMaybe ospn mspn
295+
pprSrc = case src of
296+
-- Users don't know what HsWrappers are
297+
EvWrapperBind -> "bound by type signature or pattern"
298+
_ -> ppr src
299+
#endif
300+
301+
239302
typeLocationsAtPoint
240303
:: forall m
241304
. MonadIO m
@@ -251,7 +314,7 @@ typeLocationsAtPoint hiedb lookupModule _ideOptions pos (HAR _ ast _ _ hieKind)
251314
let arr = hie_types hf
252315
ts = concat $ pointCommand ast pos getts
253316
unfold = map (arr A.!)
254-
getts x = nodeType ni ++ (mapMaybe identType $ M.elems $ nodeIdentifiers ni)
317+
getts x = nodeType ni ++ mapMaybe identType (M.elems $ nodeIdentifiers ni)
255318
where ni = nodeInfo' x
256319
getTypes ts = flip concatMap (unfold ts) $ \case
257320
HTyVarTy n -> [n]
@@ -270,12 +333,12 @@ typeLocationsAtPoint hiedb lookupModule _ideOptions pos (HAR _ ast _ _ hieKind)
270333
HQualTy a b -> getTypes [a,b]
271334
HCastTy a -> getTypes [a]
272335
_ -> []
273-
in fmap nubOrd $ concatMapM (fmap (fromMaybe []) . nameToLocation hiedb lookupModule) (getTypes ts)
336+
in nubOrd <$> concatMapM (fmap (fromMaybe []) . nameToLocation hiedb lookupModule) (getTypes ts)
274337
HieFresh ->
275338
let ts = concat $ pointCommand ast pos getts
276-
getts x = nodeType ni ++ (mapMaybe identType $ M.elems $ nodeIdentifiers ni)
339+
getts x = nodeType ni ++ mapMaybe identType (M.elems $ nodeIdentifiers ni)
277340
where ni = nodeInfo x
278-
in fmap nubOrd $ concatMapM (fmap (fromMaybe []) . nameToLocation hiedb lookupModule) (getTypes ts)
341+
in nubOrd <$> concatMapM (fmap (fromMaybe []) . nameToLocation hiedb lookupModule) (getTypes ts)
279342

280343
namesInType :: Type -> [Name]
281344
namesInType (TyVarTy n) = [Var.varName n]
@@ -288,24 +351,30 @@ namesInType (LitTy _) = []
288351
namesInType _ = []
289352

290353
getTypes :: [Type] -> [Name]
291-
getTypes ts = concatMap namesInType ts
354+
getTypes = concatMap namesInType
292355

293356
locationsAtPoint
294-
:: forall m a
357+
:: forall m
295358
. MonadIO m
296359
=> HieDb
297360
-> LookupModule m
298361
-> IdeOptions
299362
-> M.Map ModuleName NormalizedFilePath
300363
-> Position
301-
-> HieASTs a
364+
-> HieAstResult
302365
-> m [Location]
303-
locationsAtPoint hiedb lookupModule _ideOptions imports pos ast =
366+
locationsAtPoint hiedb lookupModule _ideOptions imports pos (HAR _ ast _rm _ _) =
304367
let ns = concat $ pointCommand ast pos (M.keys . getNodeIds)
368+
#if MIN_VERSION_ghc(9,0,1)
369+
evTrees = mapMaybe (either (const Nothing) $ getEvidenceTree _rm) ns
370+
evNs = concatMap (map (Right . evidenceVar) . T.flatten) evTrees
371+
#else
372+
evNs = []
373+
#endif
305374
zeroPos = Position 0 0
306375
zeroRange = Range zeroPos zeroPos
307-
modToLocation m = fmap (\fs -> pure $ Location (fromNormalizedUri $ filePathToUri' fs) zeroRange) $ M.lookup m imports
308-
in fmap (nubOrd . concat) $ mapMaybeM (either (pure . modToLocation) $ nameToLocation hiedb lookupModule) ns
376+
modToLocation m = (\fs -> pure $ Location (fromNormalizedUri $ filePathToUri' fs) zeroRange) <$> M.lookup m imports
377+
in nubOrd . concat <$> mapMaybeM (either (pure . modToLocation) $ nameToLocation hiedb lookupModule) (ns ++ evNs)
309378

310379
-- | Given a 'Name' attempt to find the location where it is defined.
311380
nameToLocation :: MonadIO m => HieDb -> LookupModule m -> Name -> m (Maybe [Location])

ghcide/src/Development/IDE/Spans/Common.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
module Development.IDE.Spans.Common (
66
showGhc
77
, showNameWithoutUniques
8+
, showSD
89
, unqualIEWrapName
910
, safeTyThingId
1011
, safeTyThingType

0 commit comments

Comments
 (0)