Skip to content

Commit 10a0edb

Browse files
Wingman: Let-bindings in metatactics (#2160)
* Add metatactic for let-bindings * Add test for simple let bindings * Label hole numbers in the documentation * Sort imports Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent c91d30a commit 10a0edb

File tree

7 files changed

+89
-0
lines changed

7 files changed

+89
-0
lines changed

Diff for: plugins/hls-tactics-plugin/COMMANDS.md

+26
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,32 @@ running `intros x y z w` will produce:
382382
\x y z -> (_ :: d)
383383
```
384384

385+
## let
386+
387+
arguments: varadic binding.
388+
deterministic.
389+
390+
> Create let-bindings for each binder given to this tactic.
391+
392+
393+
### Example
394+
395+
Given:
396+
397+
```haskell
398+
_ :: x
399+
```
400+
401+
running `let a b c` will produce:
402+
403+
```haskell
404+
let a = _1 :: a
405+
b = _2 :: b
406+
c = _3 :: c
407+
in (_4 :: x)
408+
409+
```
410+
385411
## nested
386412

387413
arguments: single reference.

Diff for: plugins/hls-tactics-plugin/src/Wingman/CodeGen.hs

+21
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Control.Lens ((%~), (<>~), (&))
1515
import Control.Monad.Except
1616
import Control.Monad.Reader (ask)
1717
import Control.Monad.State
18+
import Data.Bifunctor (second)
1819
import Data.Bool (bool)
1920
import Data.Functor ((<&>))
2021
import Data.Generics.Labels ()
@@ -315,3 +316,23 @@ letForEach rename solve (unHypothesis -> hy) jdg = do
315316
g <- fmap (fmap unLoc) $ newSubgoal $ introduce ctx (userHypothesis hy') jdg
316317
pure $ fmap noLoc $ let' <$> matches <*> g
317318

319+
320+
------------------------------------------------------------------------------
321+
-- | Let-bind the given occname judgement pairs.
322+
nonrecLet
323+
:: [(OccName, Judgement)]
324+
-> Judgement
325+
-> RuleM (Synthesized (LHsExpr GhcPs))
326+
nonrecLet occjdgs jdg = do
327+
occexts <- traverse newSubgoal $ fmap snd occjdgs
328+
ctx <- ask
329+
ext <- newSubgoal
330+
$ introduce ctx (userHypothesis $ fmap (second jGoal) occjdgs)
331+
$ jdg
332+
pure $ fmap noLoc $
333+
let'
334+
<$> traverse
335+
(\(occ, ext) -> valBind (occNameToStr occ) <$> fmap unLoc ext)
336+
(zip (fmap fst occjdgs) occexts)
337+
<*> fmap unLoc ext
338+

Diff for: plugins/hls-tactics-plugin/src/Wingman/Metaprogramming/Parser.hs

+16
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,22 @@ commands =
348348
"(_ :: a -> a -> a -> a) a1 a2 a3"
349349
]
350350

351+
, command "let" Deterministic (Bind Many)
352+
"Create let-bindings for each binder given to this tactic."
353+
(pure . letBind)
354+
[ Example
355+
Nothing
356+
["a", "b", "c"]
357+
[ ]
358+
(Just "x")
359+
$ T.pack $ unlines
360+
[ "let a = _1 :: a"
361+
, " b = _2 :: b"
362+
, " c = _3 :: c"
363+
, " in (_4 :: x)"
364+
]
365+
]
366+
351367
, command "try" Nondeterministic Tactic
352368
"Simultaneously run and do not run a tactic. Subsequent tactics will bind on both states."
353369
(pure . R.try)

Diff for: plugins/hls-tactics-plugin/src/Wingman/Tactics.hs

+15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE TupleSections #-}
23

34
module Wingman.Tactics
45
( module Wingman.Tactics
@@ -23,6 +24,7 @@ import qualified Data.Map as M
2324
import Data.Maybe
2425
import Data.Set (Set)
2526
import qualified Data.Set as S
27+
import Data.Traversable (for)
2628
import DataCon
2729
import Development.IDE.GHC.Compat
2830
import GHC.Exts
@@ -579,6 +581,19 @@ cata hi = do
579581
$ Hypothesis unifiable_diff
580582

581583

584+
letBind :: [OccName] -> TacticsM ()
585+
letBind occs = do
586+
jdg <- goal
587+
occ_tys <- for occs
588+
$ \occ
589+
-> fmap (occ, )
590+
$ fmap (<$ jdg)
591+
$ fmap CType
592+
$ freshTyvars
593+
$ mkInvForAllTys [alphaTyVar] alphaTy
594+
rule $ nonrecLet occ_tys
595+
596+
582597
------------------------------------------------------------------------------
583598
-- | Deeply nest an unsaturated function onto itself
584599
nested :: OccName -> TacticsM ()

Diff for: plugins/hls-tactics-plugin/test/CodeAction/RunMetaprogramSpec.hs

+2
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,7 @@ spec = do
3939
metaTest 4 28 "MetaUseSymbol"
4040
metaTest 7 53 "MetaDeepOf"
4141
metaTest 2 34 "MetaWithArg"
42+
metaTest 2 18 "MetaLetSimple"
43+
4244
metaTest 2 12 "IntrosTooMany"
4345

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
test :: Int
2+
test
3+
= let
4+
a = _w0
5+
b = _w1
6+
c = _w2
7+
in _w3
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test :: Int
2+
test = [wingman| let a b c |]

0 commit comments

Comments
 (0)