Skip to content

Commit c2f54a2

Browse files
authored
Add "Refine hole" code action (#1463)
* Implement "use constructor" code action * Haddock * Make use ctor actions configurable * Undo more stupid formatting * Use loose parsing for config * Only show unifiable ctors * Don't use guard in IO Missing features were accidentally blocking all code actions * Push data con matching into tacticsGetDataCons * Implement a refine tactic for Reed * Implement a refine tactic for Reed
1 parent b0390ac commit c2f54a2

File tree

15 files changed

+85
-2
lines changed

15 files changed

+85
-2
lines changed

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ mkWorkspaceEdits
144144
-> Either ResponseError (Maybe WorkspaceEdit)
145145
mkWorkspaceEdits span dflags ccs uri pm rtr = do
146146
for_ (rtr_other_solns rtr) $ traceMX "other solution"
147+
traceMX "solution" $ rtr_extract rtr
147148
let g = graftHole (RealSrcSpan span) rtr
148149
response = transform dflags ccs uri g pm
149150
in case response of

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic/FeatureSet.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import qualified Data.Text as T
2121
------------------------------------------------------------------------------
2222
-- | All the available features. A 'FeatureSet' describes the ones currently
2323
-- available to the user.
24-
data Feature = FeatureUseDataCon
24+
data Feature
25+
= FeatureUseDataCon
26+
| FeatureRefineHole
2527
deriving (Eq, Ord, Show, Read, Enum, Bounded)
2628

2729

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic/GHC.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ tacticsThetaTy (tcSplitSigmaTy -> (_, theta, _)) = theta
8484
------------------------------------------------------------------------------
8585
-- | Get the data cons of a type, if it has any.
8686
tacticsGetDataCons :: Type -> Maybe ([DataCon], [Type])
87-
tacticsGetDataCons ty =
87+
tacticsGetDataCons ty | Just _ <- algebraicTyCon ty =
8888
splitTyConApp_maybe ty <&> \(tc, apps) ->
8989
( filter (not . dataConCannotMatch apps) $ tyConDataCons tc
9090
, apps
9191
)
92+
tacticsGetDataCons _ = Nothing
9293

9394
------------------------------------------------------------------------------
9495
-- | Instantiate all of the quantified type variables in a type with fresh

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic/LanguageServer/TacticProviders.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ commandTactic Homomorphism = useNameFromHypothesis homo
5151
commandTactic DestructLambdaCase = const destructLambdaCase
5252
commandTactic HomomorphismLambdaCase = const homoLambdaCase
5353
commandTactic UseDataCon = userSplit
54+
commandTactic Refine = const refine
5455

5556

5657
------------------------------------------------------------------------------
@@ -89,6 +90,9 @@ commandProvider UseDataCon =
8990
. occNameString
9091
. occName
9192
$ dataConName dcon
93+
commandProvider Refine =
94+
requireFeature FeatureRefineHole $
95+
provide Refine ""
9296

9397

9498
------------------------------------------------------------------------------

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic/Tactics.hs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ splitAuto = requireConcreteHole $ tracing "split(auto)" $ do
207207
splitDataCon dc
208208

209209

210+
------------------------------------------------------------------------------
211+
-- | Like 'split', but only works if there is a single matching data
212+
-- constructor for the goal.
213+
splitSingle :: TacticsM ()
214+
splitSingle = tracing "splitSingle" $ do
215+
jdg <- goal
216+
let g = jGoal jdg
217+
case tacticsGetDataCons $ unCType g of
218+
Just ([dc], _) -> do
219+
splitDataCon dc
220+
_ -> throwError $ GoalMismatch "splitSingle" g
221+
222+
210223
------------------------------------------------------------------------------
211224
-- | Allow the given tactic to proceed if and only if it introduces holes that
212225
-- have a different goal than current goal.
@@ -268,6 +281,17 @@ localTactic t f = do
268281
runStateT (unTacticT t) $ f jdg
269282

270283

284+
refine :: TacticsM ()
285+
refine = go 3
286+
where
287+
go 0 = pure ()
288+
go n = do
289+
let try_that_doesnt_suck t = commit t $ pure ()
290+
try_that_doesnt_suck intros
291+
try_that_doesnt_suck splitSingle
292+
go $ n - 1
293+
294+
271295
auto' :: Int -> TacticsM ()
272296
auto' 0 = throwError NoProgress
273297
auto' n = do

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic/TestTypes.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ data TacticCommand
2020
| DestructLambdaCase
2121
| HomomorphismLambdaCase
2222
| UseDataCon
23+
| Refine
2324
deriving (Eq, Ord, Show, Enum, Bounded)
2425

2526
-- | Generate a title for the command.
@@ -31,6 +32,7 @@ tacticTitle Homomorphism var = "Homomorphic case split on " <> var
3132
tacticTitle DestructLambdaCase _ = "Lambda case split"
3233
tacticTitle HomomorphismLambdaCase _ = "Homomorphic lambda case split"
3334
tacticTitle UseDataCon dcon = "Use constructor " <> dcon
35+
tacticTitle Refine _ = "Refine hole"
3436

3537

3638
------------------------------------------------------------------------------

plugins/hls-tactics-plugin/test/GoldenSpec.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ spec = do
105105
useTest "Left" "UseConLeft.hs" 2 8
106106
useTest "Right" "UseConRight.hs" 2 8
107107

108+
-- test via:
109+
-- stack test hls-tactics-plugin --test-arguments '--match "Golden/refine/"'
110+
describe "refine" $ do
111+
let refineTest = mkGoldenTest allFeatures Refine ""
112+
describe "golden" $ do
113+
refineTest "RefineIntro.hs" 2 8
114+
refineTest "RefineCon.hs" 2 8
115+
refineTest "RefineReader.hs" 4 8
116+
refineTest "RefineGADT.hs" 8 8
117+
118+
108119
describe "golden tests" $ do
109120
let autoTest = mkGoldenTest allFeatures Auto ""
110121

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test :: ((), (b, c), d)
2+
test = _
3+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test :: ((), (b, c), d)
2+
test = ((), (_, _), _)
3+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{-# LANGUAGE GADTs #-}
2+
3+
data GADT a where
4+
One :: (b -> Int) -> GADT Int
5+
Two :: GADT Bool
6+
7+
test :: z -> GADT Int
8+
test = _
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{-# LANGUAGE GADTs #-}
2+
3+
data GADT a where
4+
One :: (b -> Int) -> GADT Int
5+
Two :: GADT Bool
6+
7+
test :: z -> GADT Int
8+
test z = One (\ b -> _)
9+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test :: a -> Either a b
2+
test = _
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test :: a -> Either a b
2+
test a = _
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
newtype Reader r a = Reader (r -> a)
2+
3+
test :: b -> Reader r a
4+
test = _
5+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
newtype Reader r a = Reader (r -> a)
2+
3+
test :: b -> Reader r a
4+
test b = Reader (\ r -> _)
5+

0 commit comments

Comments
 (0)