Skip to content

Commit a19d125

Browse files
authored
Try a homomorphic destruct before a standard destruct (#1582)
* Try a homomorphic destruct before a standard destruct * Add zip test * Remove a debug trace * Split out the attemptWhen combinator
1 parent 2dc00d0 commit a19d125

File tree

7 files changed

+50
-9
lines changed

7 files changed

+50
-9
lines changed

plugins/hls-tactics-plugin/src/Wingman/CodeGen.hs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ConLike
1313
import Control.Lens ((%~), (<>~), (&))
1414
import Control.Monad.Except
1515
import Control.Monad.State
16+
import Data.Bool (bool)
1617
import Data.Generics.Labels ()
1718
import Data.List
1819
import Data.Maybe (mapMaybe)
@@ -183,18 +184,19 @@ destructLambdaCase' f jdg = do
183184
------------------------------------------------------------------------------
184185
-- | Construct a data con with subgoals for each field.
185186
buildDataCon
186-
:: Judgement
187+
:: Bool -- Should we blacklist destruct?
188+
-> Judgement
187189
-> ConLike -- ^ The data con to build
188190
-> [Type] -- ^ Type arguments for the data con
189191
-> RuleM (Synthesized (LHsExpr GhcPs))
190-
buildDataCon jdg dc tyapps = do
192+
buildDataCon should_blacklist jdg dc tyapps = do
191193
let args = conLikeInstOrigArgTys' dc tyapps
192194
ext
193195
<- fmap unzipTrace
194196
$ traverse ( \(arg, n) ->
195197
newSubgoal
196198
. filterSameTypeFromOtherPositions dc n
197-
. blacklistingDestruct
199+
. bool id blacklistingDestruct should_blacklist
198200
. flip withNewGoal jdg
199201
$ CType arg
200202
) $ zip args [0..]

plugins/hls-tactics-plugin/src/Wingman/Machinery.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ runTactic ctx jdg t =
8787
RunTacticResults
8888
{ rtr_trace = syn_trace syn
8989
, rtr_extract = simplify $ syn_val syn
90-
, rtr_other_solns = reverse . fmap fst $ take 5 sorted
90+
, rtr_other_solns = reverse . fmap fst $ sorted
9191
, rtr_jdg = jdg
9292
, rtr_ctx = ctx
9393
}
@@ -223,6 +223,16 @@ unify goal inst = do
223223
Nothing -> throwError (UnificationError inst goal)
224224

225225

226+
------------------------------------------------------------------------------
227+
-- | Prefer the first tactic to the second, if the bool is true. Otherwise, just run the second tactic.
228+
--
229+
-- This is useful when you have a clever pruning solution that isn't always
230+
-- applicable.
231+
attemptWhen :: TacticsM a -> TacticsM a -> Bool -> TacticsM a
232+
attemptWhen _ t2 False = t2
233+
attemptWhen t1 t2 True = commit t1 t2
234+
235+
226236
------------------------------------------------------------------------------
227237
-- | Get the class methods of a 'PredType', correctly dealing with
228238
-- instantiation of quantified class types.

plugins/hls-tactics-plugin/src/Wingman/Plugin.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ mkWorkspaceEdits
139139
-> Either UserFacingMessage WorkspaceEdit
140140
mkWorkspaceEdits span dflags ccs uri pm rtr = do
141141
for_ (rtr_other_solns rtr) $ \soln -> do
142-
traceMX "other solution" soln
142+
traceMX "other solution" $ syn_val soln
143143
traceMX "with score" $ scoreSolution soln (rtr_jdg rtr) []
144144
traceMX "solution" $ rtr_extract rtr
145145
let g = graftHole (RealSrcSpan span) rtr

plugins/hls-tactics-plugin/src/Wingman/Tactics.hs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ intros = rule $ \jdg -> do
108108
destructAuto :: HyInfo CType -> TacticsM ()
109109
destructAuto hi = requireConcreteHole $ tracing "destruct(auto)" $ do
110110
jdg <- goal
111-
let subtactic = rule $ destruct' (const subgoal) hi
111+
let subtactic = destructOrHomoAuto hi
112112
case isPatternMatch $ hi_provenance hi of
113113
True ->
114114
pruning subtactic $ \jdgs ->
@@ -121,6 +121,25 @@ destructAuto hi = requireConcreteHole $ tracing "destruct(auto)" $ do
121121
False -> subtactic
122122

123123

124+
------------------------------------------------------------------------------
125+
-- | When running auto, in order to prune the auto search tree, we try
126+
-- a homomorphic destruct whenever possible. If that produces any results, we
127+
-- can probably just prune the other side.
128+
destructOrHomoAuto :: HyInfo CType -> TacticsM ()
129+
destructOrHomoAuto hi = tracing "destructOrHomoAuto" $ do
130+
jdg <- goal
131+
let g = unCType $ jGoal jdg
132+
ty = unCType $ hi_type hi
133+
134+
attemptWhen
135+
(rule $ destruct' (\dc jdg ->
136+
buildDataCon False jdg dc $ snd $ splitAppTys g) hi)
137+
(rule $ destruct' (const subgoal) hi)
138+
$ case (splitTyConApp_maybe g, splitTyConApp_maybe ty) of
139+
(Just (gtc, _), Just (tytc, _)) -> gtc == tytc
140+
_ -> False
141+
142+
124143
------------------------------------------------------------------------------
125144
-- | Case split, and leave holes in the matches.
126145
destruct :: HyInfo CType -> TacticsM ()
@@ -132,7 +151,7 @@ destruct hi = requireConcreteHole $ tracing "destruct(user)" $
132151
-- | Case split, using the same data constructor in the matches.
133152
homo :: HyInfo CType -> TacticsM ()
134153
homo = requireConcreteHole . tracing "homo" . rule . destruct' (\dc jdg ->
135-
buildDataCon jdg dc $ snd $ splitAppTys $ unCType $ jGoal jdg)
154+
buildDataCon False jdg dc $ snd $ splitAppTys $ unCType $ jGoal jdg)
136155

137156

138157
------------------------------------------------------------------------------
@@ -147,7 +166,7 @@ homoLambdaCase :: TacticsM ()
147166
homoLambdaCase =
148167
tracing "homoLambdaCase" $
149168
rule $ destructLambdaCase' $ \dc jdg ->
150-
buildDataCon jdg dc
169+
buildDataCon False jdg dc
151170
. snd
152171
. splitAppTys
153172
. unCType
@@ -242,7 +261,7 @@ splitConLike dc =
242261
let g = jGoal jdg
243262
case splitTyConApp_maybe $ unCType g of
244263
Just (_, apps) -> do
245-
buildDataCon (unwhitelistingSplit jdg) dc apps
264+
buildDataCon True (unwhitelistingSplit jdg) dc apps
246265
Nothing -> throwError $ GoalMismatch "splitDataCon" g
247266

248267
------------------------------------------------------------------------------

plugins/hls-tactics-plugin/test/CodeAction/AutoSpec.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ spec = do
4949
autoTest 9 12 "AutoEndo.hs"
5050
autoTest 2 16 "AutoEmptyString.hs"
5151
autoTest 7 35 "AutoPatSynUse.hs"
52+
autoTest 2 28 "AutoZip.hs"
5253

5354
failing "flaky in CI" $
5455
autoTest 2 11 "GoldenApplicativeThen.hs"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]
2+
zip_it_up_and_zip_it_out = _
3+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]
2+
zip_it_up_and_zip_it_out _ [] = []
3+
zip_it_up_and_zip_it_out [] (_ : _) = []
4+
zip_it_up_and_zip_it_out (a : l_a5) (b : l_b3)
5+
= (a, b) : zip_it_up_and_zip_it_out l_a5 l_b3
6+

0 commit comments

Comments
 (0)