Skip to content

Commit 720923d

Browse files
wz1000fendor
authored andcommitted
Jump to instance definition and explain typeclass evidence
1 parent 9f4d673 commit 720923d

File tree

2 files changed

+80
-14
lines changed

2 files changed

+80
-14
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ getDefinition :: NormalizedFilePath -> Position -> IdeAction (Maybe [(Location,
9898
getDefinition file pos = runMaybeT $ do
9999
ide@ShakeExtras{ withHieDb, hiedbWriter } <- ask
100100
opts <- liftIO $ getIdeOptionsIO ide
101-
(HAR _ hf _ _ _, mapping) <- useWithStaleFastMT GetHieAst file
101+
(hf, mapping) <- useWithStaleFastMT GetHieAst file
102102
(ImportMap imports, _) <- useWithStaleFastMT GetImportMap file
103103
!pos' <- MaybeT (pure $ fromCurrentPosition mapping pos)
104104
locationsWithIdentifier <- AtPoint.gotoDefinition withHieDb (lookupMod hiedbWriter) opts imports hf pos'

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

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ import qualified Data.Text as T
5252

5353
import qualified Data.Array as A
5454
import Data.Either
55-
import Data.List (isSuffixOf)
5655
import Data.List.Extra (dropEnd1, nubOrd)
5756

57+
import Data.List (isSuffixOf, sortOn)
58+
import Data.Tree
59+
import qualified Data.Tree as T
5860
import Data.Version (showVersion)
5961
import Development.IDE.Types.Shake (WithHieDb)
62+
import qualified GHC.Utils.Outputable as O
6063
import HieDb hiding (pointCommand,
6164
withHieDb)
6265
import System.Directory (doesFileExist)
@@ -198,7 +201,7 @@ gotoDefinition
198201
-> LookupModule m
199202
-> IdeOptions
200203
-> M.Map ModuleName NormalizedFilePath
201-
-> HieASTs a
204+
-> HieAstResult
202205
-> Position
203206
-> MaybeT m [(Location, Identifier)]
204207
gotoDefinition withHieDb getHieFile ideOpts imports srcSpans pos
@@ -212,7 +215,7 @@ atPoint
212215
-> HscEnv
213216
-> Position
214217
-> IO (Maybe (Maybe Range, [T.Text]))
215-
atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env pos =
218+
atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (DKMap dm km) env pos =
216219
listToMaybe <$> sequence (pointCommand hf pos hoverInfo)
217220
where
218221
-- Hover info for values/data
@@ -236,7 +239,7 @@ atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env
236239
info = nodeInfoH kind ast
237240

238241
names :: [(Identifier, IdentifierDetails hietype)]
239-
names = M.assocs $ nodeIdentifiers info
242+
names = sortOn (any isEvidenceUse . identInfo . snd) $ M.assocs $ nodeIdentifiers info
240243

241244
-- Check for evidence bindings
242245
isInternal :: (Identifier, IdentifierDetails a) -> Bool
@@ -248,11 +251,14 @@ atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env
248251
filteredNames = filter (not . isInternal) names
249252

250253
prettyName :: (Either ModuleName Name, IdentifierDetails hietype) -> IO T.Text
251-
prettyName (Right n, dets) = pure $ T.unlines $
252-
wrapHaskell (printOutputable n <> maybe "" (" :: " <>) ((prettyType <$> identType dets) <|> maybeKind))
253-
: maybeToList (pretty (definedAt n) (prettyPackageName n))
254-
++ catMaybes [ T.unlines . spanDocToMarkdown <$> lookupNameEnv dm n
255-
]
254+
prettyName (Right n, dets)
255+
| any isEvidenceUse (identInfo dets) =
256+
pure $ maybe "" (printOutputable . renderEvidenceTree) (getEvidenceTree rf n) <> "\n"
257+
| otherwise = pure $ T.unlines $
258+
wrapHaskell (printOutputable n <> maybe "" (" :: " <>) ((prettyType <$> identType dets) <|> maybeKind))
259+
: maybeToList (pretty (definedAt n) (prettyPackageName n))
260+
++ catMaybes [ T.unlines . spanDocToMarkdown <$> lookupNameEnv dm n
261+
]
256262
where maybeKind = fmap printOutputable $ safeTyThingType =<< lookupNameEnv km n
257263
pretty Nothing Nothing = Nothing
258264
pretty (Just define) Nothing = Just $ define <> "\n"
@@ -298,6 +304,12 @@ atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env
298304
prettyType t = case kind of
299305
HieFresh -> printOutputable t
300306
HieFromDisk full_file -> printOutputable $ hieTypeToIface $ recoverFullType t (hie_types full_file)
307+
-- prettyType = printOutputable . expandType
308+
309+
expandType :: a -> SDoc
310+
expandType t = case kind of
311+
HieFresh -> ppr t
312+
HieFromDisk full_file -> ppr $ hieTypeToIface $ recoverFullType t (hie_types full_file)
301313

302314
definedAt :: Name -> Maybe T.Text
303315
definedAt name =
@@ -307,6 +319,40 @@ atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env
307319
UnhelpfulLoc {} | isInternalName name || isSystemName name -> Nothing
308320
_ -> Just $ "*Defined " <> printOutputable (pprNameDefnLoc name) <> "*"
309321

322+
-- We want to render the root constraint even if it is a let,
323+
-- but we don't want to render any subsequent lets
324+
renderEvidenceTree :: Tree (EvidenceInfo a) -> SDoc
325+
-- However, if the root constraint is simply an indirection (via let) to a single other constraint,
326+
-- we can still skip rendering it
327+
renderEvidenceTree (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_)}) [x])
328+
= renderEvidenceTree x
329+
renderEvidenceTree (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_), ..}) xs)
330+
= hang (text "- Evidence of constraint `" O.<> expandType evidenceType O.<> "`") 2 $
331+
vcat $ text "depending on:" : map renderEvidenceTree' xs
332+
renderEvidenceTree x = renderEvidenceTree' x
333+
334+
-- renderEvidenceTree' skips let bound evidence variables and prints the children directly
335+
renderEvidenceTree' (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_)}) xs)
336+
= vcat (map renderEvidenceTree' xs)
337+
renderEvidenceTree' (T.Node (EvidenceInfo{..}) xs)
338+
= hang (text "- Evidence of constraint `" O.<> expandType evidenceType O.<> "`") 2 $
339+
vcat $ map (text . T.unpack) (maybeToList $ definedAt evidenceVar)
340+
++ [printDets evidenceSpan evidenceDetails (null xs)]
341+
++ map renderEvidenceTree' xs
342+
343+
printDets :: RealSrcSpan -> Maybe (EvVarSource, Scope, Maybe Span) -> Bool -> SDoc
344+
printDets _ Nothing True = text ""
345+
printDets _ Nothing False = text "constructed using:"
346+
printDets ospn (Just (src,_,mspn)) _ = pprSrc
347+
$$ text "at" <+> ppr spn
348+
where
349+
-- Use the bind span if we have one, else use the occurence span
350+
spn = fromMaybe ospn mspn
351+
pprSrc = case src of
352+
-- Users don't know what HsWrappers are
353+
EvWrapperBind -> "bound by type signature or pattern"
354+
_ -> ppr src
355+
310356
-- | Find 'Location's of type definition at a specific point and return them along with their 'Identifier's.
311357
typeLocationsAtPoint
312358
:: forall m
@@ -323,7 +369,7 @@ typeLocationsAtPoint withHieDb lookupModule _ideOptions pos (HAR _ ast _ _ hieKi
323369
let arr = hie_types hf
324370
ts = concat $ pointCommand ast pos getts
325371
unfold = map (arr A.!)
326-
getts x = nodeType ni ++ (mapMaybe identType $ M.elems $ nodeIdentifiers ni)
372+
getts x = nodeType ni ++ mapMaybe identType (M.elems $ nodeIdentifiers ni)
327373
where ni = nodeInfo' x
328374
getTypes' ts' = flip concatMap (unfold ts') $ \case
329375
HTyVarTy n -> [n]
@@ -337,7 +383,7 @@ typeLocationsAtPoint withHieDb lookupModule _ideOptions pos (HAR _ ast _ _ hieKi
337383
in fmap nubOrd $ concatMapM (\n -> fmap (maybe [] (fmap (,Right n))) (nameToLocation withHieDb lookupModule n)) (getTypes' ts)
338384
HieFresh ->
339385
let ts = concat $ pointCommand ast pos getts
340-
getts x = nodeType ni ++ (mapMaybe identType $ M.elems $ nodeIdentifiers ni)
386+
getts x = nodeType ni ++ mapMaybe identType (M.elems $ nodeIdentifiers ni)
341387
where ni = nodeInfo x
342388
in fmap nubOrd $ concatMapM (\n -> fmap (maybe [] (fmap (,Right n))) (nameToLocation withHieDb lookupModule n)) (getTypes ts)
343389

@@ -352,28 +398,48 @@ namesInType (LitTy _) = []
352398
namesInType _ = []
353399

354400
getTypes :: [Type] -> [Name]
355-
getTypes ts = concatMap namesInType ts
401+
getTypes = concatMap namesInType
356402

357403
-- | Find 'Location's of definition at a specific point and return them along with their 'Identifier's.
358404
locationsAtPoint
359-
:: forall m a
405+
:: forall m
360406
. MonadIO m
361407
=> WithHieDb
362408
-> LookupModule m
363409
-> IdeOptions
364410
-> M.Map ModuleName NormalizedFilePath
365411
-> Position
412+
<<<<<<< HEAD
366413
-> HieASTs a
367414
-> m [(Location, Identifier)]
368415
locationsAtPoint withHieDb lookupModule _ideOptions imports pos ast =
416+
||||||| parent of 86ebcf859 (Jump to instance definition and explain typeclass evidence)
417+
-> HieASTs a
418+
-> m [Location]
419+
locationsAtPoint withHieDb lookupModule _ideOptions imports pos ast =
420+
=======
421+
-> HieAstResult
422+
-> m [Location]
423+
locationsAtPoint withHieDb lookupModule _ideOptions imports pos (HAR _ ast _rm _ _) =
424+
>>>>>>> 86ebcf859 (Jump to instance definition and explain typeclass evidence)
369425
let ns = concat $ pointCommand ast pos (M.keys . getNodeIds)
426+
evTrees = mapMaybe (either (const Nothing) $ getEvidenceTree _rm) ns
427+
evNs = concatMap (map (Right . evidenceVar) . T.flatten) evTrees
370428
zeroPos = Position 0 0
371429
zeroRange = Range zeroPos zeroPos
430+
<<<<<<< HEAD
372431
modToLocation m = fmap (\fs -> pure (Location (fromNormalizedUri $ filePathToUri' fs) zeroRange)) $ M.lookup m imports
373432
in fmap (nubOrd . concat) $ mapMaybeM
374433
(either (\m -> pure ((fmap $ fmap (,Left m)) (modToLocation m)))
375434
(\n -> fmap (fmap $ fmap (,Right n)) (nameToLocation withHieDb lookupModule n)))
376435
ns
436+
||||||| parent of 86ebcf859 (Jump to instance definition and explain typeclass evidence)
437+
modToLocation m = fmap (\fs -> pure $ Location (fromNormalizedUri $ filePathToUri' fs) zeroRange) $ M.lookup m imports
438+
in fmap (nubOrd . concat) $ mapMaybeM (either (pure . modToLocation) $ nameToLocation withHieDb lookupModule) ns
439+
=======
440+
modToLocation m = (\fs -> pure $ Location (fromNormalizedUri $ filePathToUri' fs) zeroRange) <$> M.lookup m imports
441+
in nubOrd . concat <$> mapMaybeM (either (pure . modToLocation) $ nameToLocation withHieDb lookupModule) (ns ++ evNs)
442+
>>>>>>> 86ebcf859 (Jump to instance definition and explain typeclass evidence)
377443

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

0 commit comments

Comments
 (0)