Skip to content

Commit 54be003

Browse files
jhrcekmergify[bot]
andauthored
Make adding missing constraint work in presence of 'forall' (fixes #1164) (#1177)
* Make adding missing constraints work when 'forall' is present (fixes #1164) * Improve comment * Revert range change * Don't use code action descr. as test name * GHC 8.10+ doesn't have splitLHsForAllTy Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent d7e1619 commit 54be003

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

Diff for: ghcide/src/Development/IDE/GHC/Compat.hs

+10-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ module Development.IDE.GHC.Compat(
5858
applyPluginsParsedResultAction,
5959
module Compat.HieTypes,
6060
module Compat.HieUtils,
61-
61+
dropForAll
6262
) where
6363

6464
#if MIN_GHC_API_VERSION(8,10,0)
@@ -283,3 +283,12 @@ pattern ExposePackage s a mr <- DynFlags.ExposePackage s a _ mr
283283
#else
284284
pattern ExposePackage s a mr = DynFlags.ExposePackage s a mr
285285
#endif
286+
287+
-- | Take AST representation of type signature and drop `forall` part from it (if any), returning just type's body
288+
dropForAll :: LHsType pass -> LHsType pass
289+
#if MIN_GHC_API_VERSION(8,10,0)
290+
dropForAll = snd . GHC.splitLHsForAllTyInvis
291+
#else
292+
dropForAll = snd . GHC.splitLHsForAllTy
293+
#endif
294+

Diff for: ghcide/src/Development/IDE/Plugin/CodeAction.hs

+4-3
Original file line numberDiff line numberDiff line change
@@ -803,12 +803,13 @@ suggestFunctionConstraint ParsedModule{pm_parsed_source = L _ HsModule{hsmodDecl
803803
| L _ (SigD _ (TypeSig _ identifiers (HsWC _ (HsIB _ locatedType)))) <- hsmodDecls
804804
, any (`isSameName` T.unpack typeSignatureName) $ fmap unLoc identifiers
805805
]
806-
srcSpanToRange $ case splitLHsQualTy locatedType of
806+
let typeBody = dropForAll locatedType
807+
srcSpanToRange $ case splitLHsQualTy typeBody of
807808
(L contextSrcSpan _ , _) ->
808809
if isGoodSrcSpan contextSrcSpan
809810
then contextSrcSpan -- The type signature has explicit context
810-
else -- No explicit context, return SrcSpan at the start of type sig where we can write context
811-
let start = srcSpanStart $ getLoc locatedType in mkSrcSpan start start
811+
else -- No explicit context, return SrcSpan at the start of type (after a potential `forall`)
812+
let start = srcSpanStart $ getLoc typeBody in mkSrcSpan start start
812813

813814
isSameName :: IdP GhcPs -> String -> Bool
814815
isSameName x name = showSDocUnsafe (ppr x) == name

Diff for: ghcide/test/exe/Main.hs

+39-2
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,28 @@ addFunctionConstraintTests = let
19341934
, "eq x y = x == y"
19351935
]
19361936

1937+
missingConstraintWithForAllSourceCode :: T.Text -> T.Text
1938+
missingConstraintWithForAllSourceCode constraint =
1939+
T.unlines
1940+
[ "{-# LANGUAGE ExplicitForAll #-}"
1941+
, "module Testing where"
1942+
, ""
1943+
, "eq :: forall a. " <> constraint <> "a -> a -> Bool"
1944+
, "eq x y = x == y"
1945+
]
1946+
1947+
incompleteConstraintWithForAllSourceCode :: T.Text -> T.Text
1948+
incompleteConstraintWithForAllSourceCode constraint =
1949+
T.unlines
1950+
[ "{-# LANGUAGE ExplicitForAll #-}"
1951+
, "module Testing where"
1952+
, ""
1953+
, "data Pair a b = Pair a b"
1954+
, ""
1955+
, "eq :: " <> constraint <> " => Pair a b -> Pair a b -> Bool"
1956+
, "eq (Pair x y) (Pair x' y') = x == x' && y == y'"
1957+
]
1958+
19371959
incompleteConstraintSourceCode :: T.Text -> T.Text
19381960
incompleteConstraintSourceCode constraint =
19391961
T.unlines
@@ -1978,8 +2000,8 @@ addFunctionConstraintTests = let
19782000
, "eq (Pair x y) (Pair x' y') = x == x' && y == y'"
19792001
]
19802002

1981-
check :: T.Text -> T.Text -> T.Text -> TestTree
1982-
check actionTitle originalCode expectedCode = testSession (T.unpack actionTitle) $ do
2003+
check :: String -> T.Text -> T.Text -> T.Text -> TestTree
2004+
check testName actionTitle originalCode expectedCode = testSession testName $ do
19832005
doc <- createDoc "Testing.hs" "haskell" originalCode
19842006
_ <- waitForDiagnostics
19852007
actionsOrCommands <- getCodeActions doc (Range (Position 6 0) (Position 6 maxBound))
@@ -1990,22 +2012,37 @@ addFunctionConstraintTests = let
19902012

19912013
in testGroup "add function constraint"
19922014
[ check
2015+
"no preexisting constraint"
19932016
"Add `Eq a` to the context of the type signature for `eq`"
19942017
(missingConstraintSourceCode "")
19952018
(missingConstraintSourceCode "Eq a => ")
19962019
, check
2020+
"no preexisting constraint, with forall"
2021+
"Add `Eq a` to the context of the type signature for `eq`"
2022+
(missingConstraintWithForAllSourceCode "")
2023+
(missingConstraintWithForAllSourceCode "Eq a => ")
2024+
, check
2025+
"preexisting constraint, no parenthesis"
19972026
"Add `Eq b` to the context of the type signature for `eq`"
19982027
(incompleteConstraintSourceCode "Eq a")
19992028
(incompleteConstraintSourceCode "(Eq a, Eq b)")
20002029
, check
2030+
"preexisting constraints in parenthesis"
20012031
"Add `Eq c` to the context of the type signature for `eq`"
20022032
(incompleteConstraintSourceCode2 "(Eq a, Eq b)")
20032033
(incompleteConstraintSourceCode2 "(Eq a, Eq b, Eq c)")
2034+
, check
2035+
"preexisting constraints with forall"
2036+
"Add `Eq b` to the context of the type signature for `eq`"
2037+
(incompleteConstraintWithForAllSourceCode "Eq a")
2038+
(incompleteConstraintWithForAllSourceCode "(Eq a, Eq b)")
20042039
, check
2040+
"preexisting constraint, with extra spaces in context"
20052041
"Add `Eq b` to the context of the type signature for `eq`"
20062042
(incompleteConstraintSourceCodeWithExtraCharsInContext "( Eq a )")
20072043
(incompleteConstraintSourceCodeWithExtraCharsInContext "(Eq a, Eq b)")
20082044
, check
2045+
"preexisting constraint, with newlines in type signature"
20092046
"Add `Eq b` to the context of the type signature for `eq`"
20102047
(incompleteConstraintSourceCodeWithNewlinesInTypeSignature "(Eq a)")
20112048
(incompleteConstraintSourceCodeWithNewlinesInTypeSignature "(Eq a, Eq b)")

0 commit comments

Comments
 (0)