Skip to content

Commit 58f01b7

Browse files
committed
Make adding missing constraints work when 'forall' is present (fixes #1164)
1 parent bf642c0 commit 58f01b7

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

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

Lines changed: 7 additions & 6 deletions
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
807-
(L contextSrcSpan _ , _) ->
808-
if isGoodSrcSpan contextSrcSpan
809-
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
806+
srcSpanToRange $ case splitLHsForAllTy locatedType of
807+
(_{-ignore `forall` if present-}, typeBody) -> case splitLHsQualTy typeBody of
808+
(L contextSrcSpan _ , _) ->
809+
if isGoodSrcSpan contextSrcSpan
810+
then contextSrcSpan -- The type signature has explicit context
811+
else -- No explicit context, return SrcSpanqq at the start of type body (the part of type which follows the optional `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

ghcide/test/exe/Main.hs

Lines changed: 31 additions & 1 deletion
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
@@ -1982,7 +2004,7 @@ addFunctionConstraintTests = let
19822004
check actionTitle originalCode expectedCode = testSession (T.unpack actionTitle) $ do
19832005
doc <- createDoc "Testing.hs" "haskell" originalCode
19842006
_ <- waitForDiagnostics
1985-
actionsOrCommands <- getCodeActions doc (Range (Position 6 0) (Position 6 maxBound))
2007+
actionsOrCommands <- getCodeActions doc (Range (Position 0 0) (Position 6 maxBound))
19862008
chosenAction <- liftIO $ pickActionWithTitle actionTitle actionsOrCommands
19872009
executeCodeAction chosenAction
19882010
modifiedCode <- documentContents doc
@@ -1993,6 +2015,10 @@ addFunctionConstraintTests = let
19932015
"Add `Eq a` to the context of the type signature for `eq`"
19942016
(missingConstraintSourceCode "")
19952017
(missingConstraintSourceCode "Eq a => ")
2018+
, check
2019+
"Add `Eq a` to the context of the type signature for `eq`"
2020+
(missingConstraintWithForAllSourceCode "")
2021+
(missingConstraintWithForAllSourceCode "Eq a => ")
19962022
, check
19972023
"Add `Eq b` to the context of the type signature for `eq`"
19982024
(incompleteConstraintSourceCode "Eq a")
@@ -2001,6 +2027,10 @@ addFunctionConstraintTests = let
20012027
"Add `Eq c` to the context of the type signature for `eq`"
20022028
(incompleteConstraintSourceCode2 "(Eq a, Eq b)")
20032029
(incompleteConstraintSourceCode2 "(Eq a, Eq b, Eq c)")
2030+
, check
2031+
"Add `Eq b` to the context of the type signature for `eq`"
2032+
(incompleteConstraintWithForAllSourceCode "Eq a")
2033+
(incompleteConstraintWithForAllSourceCode "(Eq a, Eq b)")
20042034
, check
20052035
"Add `Eq b` to the context of the type signature for `eq`"
20062036
(incompleteConstraintSourceCodeWithExtraCharsInContext "( Eq a )")

0 commit comments

Comments
 (0)