Skip to content

Commit 8d44068

Browse files
Don't suggest import an unnecessary data constructor. (#1984)
Usually, when the type constructor is used but the data constructor isn't, we only suggest importing the type constructor. When the data constructor and type constructor share the same name we get mixed up and suggest importing both. The solution is to do a better job filtering out the data cons when we know we are looking for a type con. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent e48e02a commit 8d44068

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

ghcide/src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,10 @@ suggestExtendImport exportsMap (L _ HsModule {hsmodImports}) Diagnostic{_range=_
804804
= mod_srcspan >>= uncurry (suggestions hsmodImports binding)
805805
| otherwise = []
806806
where
807+
canUseDatacon = case extractNotInScopeName _message of
808+
Just NotInScopeTypeConstructorOrClass{} -> False
809+
_ -> True
810+
807811
suggestions decls binding mod srcspan
808812
| range <- case [ x | (x,"") <- readSrcSpan (T.unpack srcspan)] of
809813
[s] -> let x = realSrcSpanToRange s
@@ -823,7 +827,7 @@ suggestExtendImport exportsMap (L _ HsModule {hsmodImports}) Diagnostic{_range=_
823827
-- Only for the situation that data constructor name is same as type constructor name,
824828
-- let ident with parent be in front of the one without.
825829
, sortedMatch <- sortBy (\ident1 ident2 -> parent ident2 `compare` parent ident1) (Set.toList match)
826-
, idents <- filter (\ident -> moduleNameText ident == mod) sortedMatch
830+
, idents <- filter (\ident -> moduleNameText ident == mod && (canUseDatacon || not (isDatacon ident))) sortedMatch
827831
, (not . null) idents -- Ensure fallback while `idents` is empty
828832
, ident <- head idents
829833
= Just ident
@@ -1318,8 +1322,9 @@ hideImplicitPreludeSymbol :: T.Text -> NewImport
13181322
hideImplicitPreludeSymbol symbol = newUnqualImport "Prelude" symbol True
13191323

13201324
canUseIdent :: NotInScope -> IdentInfo -> Bool
1321-
canUseIdent NotInScopeDataConstructor{} = isDatacon
1322-
canUseIdent _ = const True
1325+
canUseIdent NotInScopeDataConstructor{} = isDatacon
1326+
canUseIdent NotInScopeTypeConstructorOrClass{} = not . isDatacon
1327+
canUseIdent _ = const True
13231328

13241329
data NotInScope
13251330
= NotInScopeDataConstructor T.Text

ghcide/test/exe/Main.hs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ codeActionTests = testGroup "code actions"
730730
, typeWildCardActionTests
731731
, removeImportTests
732732
, extendImportTests
733-
, suggesImportClassMethodTests
733+
, suggestImportClassMethodTests
734734
, suggestImportTests
735735
, suggestHideShadowTests
736736
, suggestImportDisambiguationTests
@@ -1436,6 +1436,25 @@ extendImportTests = testGroup "extend import actions"
14361436
, "f :: Foo"
14371437
, "f = Foo 1"
14381438
])
1439+
, testSession "type constructor name same as data constructor name, data constructor extraneous" $ template
1440+
[("ModuleA.hs", T.unlines
1441+
[ "module ModuleA where"
1442+
, "data Foo = Foo"
1443+
])]
1444+
("ModuleB.hs", T.unlines
1445+
[ "module ModuleB where"
1446+
, "import ModuleA()"
1447+
, "f :: Foo"
1448+
, "f = undefined"
1449+
])
1450+
(Range (Position 2 4) (Position 2 6))
1451+
["Add Foo to the import list of ModuleA"]
1452+
(T.unlines
1453+
[ "module ModuleB where"
1454+
, "import ModuleA(Foo)"
1455+
, "f :: Foo"
1456+
, "f = undefined"
1457+
])
14391458
]
14401459
where
14411460
codeActionTitle CodeAction{_title=x} = x
@@ -1486,8 +1505,8 @@ extendImportTestsRegEx = testGroup "regex parsing"
14861505
template message expected = do
14871506
liftIO $ matchRegExMultipleImports message @=? expected
14881507

1489-
suggesImportClassMethodTests :: TestTree
1490-
suggesImportClassMethodTests =
1508+
suggestImportClassMethodTests :: TestTree
1509+
suggestImportClassMethodTests =
14911510
testGroup
14921511
"suggest import class methods"
14931512
[ testGroup
@@ -1566,6 +1585,8 @@ suggestImportTests = testGroup "suggest import actions"
15661585
, test False [] "f = quickCheck" [] "import Test.QuickCheck (quickCheck)"
15671586
-- don't omit the parent data type of a constructor
15681587
, test False [] "f ExitSuccess = ()" [] "import System.Exit (ExitSuccess)"
1588+
-- don't suggest data constructor when we only need the type
1589+
, test False [] "f :: Bar" [] "import Bar (Bar(Bar))"
15691590
]
15701591
, testGroup "want suggestion"
15711592
[ wantWait [] "f = foo" [] "import Foo (foo)"

0 commit comments

Comments
 (0)