Skip to content

Commit ef4e33b

Browse files
author
izuzu
committed
Demonstrate that listify is lazy
In `findAliasUseAtPos`, `listify` only produces `RdrName` elements until it finds one whose alias is at the cursor. This element is consumed through pattern matching; `listify` then stops traversing and produces no more elements. See the new test cases in `Main.hs`.
1 parent 9df3d3b commit ef4e33b

4 files changed

Lines changed: 69 additions & 8 deletions

File tree

plugins/hls-rename-plugin/src/Ide/Plugin/Rename/ImportAlias.hs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{-# LANGUAGE DataKinds #-}
22
{-# LANGUAGE OverloadedStrings #-}
3-
{-# OPTIONS_GHC -Wall -Werror #-}
3+
{-# OPTIONS_GHC -Wall #-}
44

55
{-| Logic for renaming qualified import aliases.
66
@@ -47,6 +47,7 @@ import Data.Generics
4747
import qualified Data.Map as M
4848
import Data.Maybe
4949
import qualified Data.Text as T
50+
import Debug.Trace (trace, traceShowWith)
5051
import Development.IDE (realSrcSpanToCodePointRange)
5152
import Development.IDE.Core.FileStore (getVersionedTextDoc)
5253
import Development.IDE.Core.PluginUtils
@@ -55,6 +56,7 @@ import Development.IDE.Core.Service hiding (Log)
5556
import Development.IDE.Core.Shake hiding (Log)
5657
import Development.IDE.GHC.Compat hiding (importDecl)
5758
import GHC.Data.FastString (lengthFS)
59+
import GHC.Utils.Outputable (showPprUnsafe)
5860
import Ide.Plugin.Error
5961
import qualified Language.LSP.Protocol.Lens as L
6062
import Language.LSP.Protocol.Message
@@ -193,8 +195,7 @@ findAliasUseAtPos ::
193195
Maybe (VFS.CodePointRange, [ImportAlias])
194196
findAliasUseAtPos pos exports imports hsDecls =
195197
let qualifiersAtPos = do
196-
locatedRdrName :: XRec GhcPs RdrName <-
197-
listify (const True) exports ++ listify (const True) hsDecls
198+
locatedRdrName <- locateRdrNames exports hsDecls True
198199
Qual qualifier _ <- [unLoc locatedRdrName]
199200
RealSrcSpan qualifiedNameSpan _ <- [getLoc locatedRdrName]
200201
let qualifiedNameRange = realSrcSpanToCodePointRange qualifiedNameSpan
@@ -204,7 +205,7 @@ findAliasUseAtPos pos exports imports hsDecls =
204205
qualifierRange = qualifiedNameRange
205206
& VFS.end .~ (qualifierStart & VFS.character +~ qualifierLength)
206207
guard (rangeContainsPositionInclusive qualifierRange pos)
207-
[(qualifierRange, qualifier)]
208+
traceShowWith (\x -> "findAliasUseAtPos/qualifierAtPos: " <> show x) [(qualifierRange, qualifier)]
208209
in case qualifiersAtPos of
209210
[] -> Nothing
210211
(rangeAtPos, qualifierAtPos) : _ -> Just $ (,) rangeAtPos $ do
@@ -229,8 +230,7 @@ aliasUseSiteRanges ::
229230
aliasUseSiteRanges importAlias exports hsDecls = nubOrd $ do
230231
let ImportAlias{aliasName} = importAlias
231232
aliasLength = fromIntegral (moduleNameLength aliasName)
232-
locatedRdrName :: XRec GhcPs RdrName <-
233-
listify (const True) exports ++ listify (const True) hsDecls
233+
locatedRdrName <- locateRdrNames exports hsDecls False
234234
Qual qualifier _ <- [unLoc locatedRdrName]
235235
guard (qualifier == aliasName)
236236
RealSrcSpan qualifiedNameSpan _ <- [getLoc locatedRdrName]
@@ -275,8 +275,7 @@ aliasUseSiteRangesDisambiguated tcModule importAlias exports hsDecls = nubOrd $
275275
let rdrEnv = tcg_rdr_env (tmrTypechecked tcModule)
276276
ImportAlias{aliasModuleName, aliasName} = importAlias
277277
aliasLength = fromIntegral (moduleNameLength aliasName)
278-
locatedRdrName :: XRec GhcPs RdrName <-
279-
listify (const True) exports ++ listify (const True) hsDecls
278+
locatedRdrName <- locateRdrNames exports hsDecls False
280279
rdrName@(Qual qualifier name) <- [unLoc locatedRdrName]
281280
guard (qualifier == aliasName)
282281
nameGREElement <- pickGREs rdrName $ lookupGlobalRdrEnv rdrEnv name
@@ -306,6 +305,24 @@ ambiguousAliasErrorMessage _ = ""
306305
---------------------------------------------------------------------------------------------------
307306
-- Utility functions
308307

308+
instance Show RdrName where
309+
show (Unqual name) = show name
310+
show (Qual moduleName name) = show moduleName ++ "." ++ show name
311+
show (Orig mod name) = "Orig: " <> show mod <> "." <> show name
312+
show (Exact name) = "Exact: " <> showPprUnsafe name
313+
314+
-- | Locate 'RdrName' identifiers in the given export list and declarations.
315+
locateRdrNames ::
316+
Maybe (XRec GhcPs [LIE GhcPs]) ->
317+
[LHsDecl GhcPs] ->
318+
Bool ->
319+
[XRec GhcPs RdrName]
320+
locateRdrNames exports hsDecls traceEveryProducedName =
321+
listify const_True exports ++ listify const_True hsDecls
322+
where const_True = if traceEveryProducedName
323+
then \x -> trace ("listify: " <> show (unLoc x) <> " at " <> show (getLoc x)) True
324+
else const True
325+
309326
-- | Check whether a 'CodePointRange' contains a 'CodePointPosition' (inclusive
310327
-- start, inclusive end).
311328
-- NOTE: The use of inclusive end allows the user to place the cursor at the end

plugins/hls-rename-plugin/test/Main.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,24 @@ renameTests = testGroup "Identifier"
130130
rename doc (Position 3 31) "Maybe"
131131
, goldenWithRename "Import alias at use site (shared by unrelated imports)" "ImportAliasShared" $ \doc ->
132132
rename doc (Position 6 6) "Maybe"
133+
134+
-- REVIEW: `listify (const True) exports` produces 2 elements. The 2nd one,
135+
-- `M.isJust`, has its alias at the cursor. The `qualifiersAtPos` pattern
136+
-- match consumes it, and then doesn't consume any more elements. `listify
137+
-- exports` then stops, and `listify hsDecls` is not evaluated at all.
138+
-- The console shows 2 `listify:` traces.
139+
, goldenWithRename "Import alias in export list (proving 'listify' is lazy)" "ImportAliasLazyListify" $ \doc ->
140+
rename doc (Position 0 39) "Maybe"
141+
142+
-- REVIEW: `listify (const True) exports ++ listify (const True) hsDecls`
143+
-- produces elements until it produces one whose alias is at the cursor.
144+
-- This element is then consumed in the pattern match. `listify` then stops
145+
-- producing.
146+
-- The console shows traces for all `RdrName`s except for the `M.fromMaybe`
147+
-- on the last line.
148+
, goldenWithRename "Import alias in definition (proving 'listify' is lazy)" "ImportAliasLazyListify" $ \doc ->
149+
rename doc (Position 9 6) "Maybe"
150+
133151
, goldenWithRename "Import alias declaration (with re-exports)" "ImportAliasReexport" $ \doc -> do
134152
rename doc (Position 1 18) "Reexport"
135153
, testCase "Import alias at use site (ambiguous due to re-exports)" $ runRenameSession "" $ do
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module ImportAliasShared (Maybe.fromMaybe, Maybe.isJust, Maybe.maybe, M.mapM) where
2+
3+
import qualified Control.Monad as M
4+
import qualified Data.Maybe as Maybe
5+
6+
bar :: Maybe a -> Bool
7+
bar = Maybe.isJust
8+
9+
baz :: b -> (a -> b) -> Maybe a -> b
10+
baz = Maybe.maybe
11+
12+
buzz :: a -> Maybe a -> a
13+
buzz = Maybe.fromMaybe
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module ImportAliasShared (M.fromMaybe, M.isJust, M.maybe, M.mapM) where
2+
3+
import qualified Control.Monad as M
4+
import qualified Data.Maybe as M
5+
6+
bar :: Maybe a -> Bool
7+
bar = M.isJust
8+
9+
baz :: b -> (a -> b) -> Maybe a -> b
10+
baz = M.maybe
11+
12+
buzz :: a -> Maybe a -> a
13+
buzz = M.fromMaybe

0 commit comments

Comments
 (0)