Skip to content

Try a homomorphic destruct before a standard destruct #1582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions plugins/hls-tactics-plugin/src/Wingman/CodeGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ConLike
import Control.Lens ((%~), (<>~), (&))
import Control.Monad.Except
import Control.Monad.State
import Data.Bool (bool)
import Data.Generics.Labels ()
import Data.List
import Data.Maybe (mapMaybe)
Expand Down Expand Up @@ -183,18 +184,19 @@ destructLambdaCase' f jdg = do
------------------------------------------------------------------------------
-- | Construct a data con with subgoals for each field.
buildDataCon
:: Judgement
:: Bool -- Should we blacklist destruct?
-> Judgement
-> ConLike -- ^ The data con to build
-> [Type] -- ^ Type arguments for the data con
-> RuleM (Synthesized (LHsExpr GhcPs))
buildDataCon jdg dc tyapps = do
buildDataCon should_blacklist jdg dc tyapps = do
let args = conLikeInstOrigArgTys' dc tyapps
ext
<- fmap unzipTrace
$ traverse ( \(arg, n) ->
newSubgoal
. filterSameTypeFromOtherPositions dc n
. blacklistingDestruct
. bool id blacklistingDestruct should_blacklist
. flip withNewGoal jdg
$ CType arg
) $ zip args [0..]
Expand Down
12 changes: 11 additions & 1 deletion plugins/hls-tactics-plugin/src/Wingman/Machinery.hs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ runTactic ctx jdg t =
RunTacticResults
{ rtr_trace = syn_trace syn
, rtr_extract = simplify $ syn_val syn
, rtr_other_solns = reverse . fmap fst $ take 5 sorted
, rtr_other_solns = reverse . fmap fst $ sorted
, rtr_jdg = jdg
, rtr_ctx = ctx
}
Expand Down Expand Up @@ -223,6 +223,16 @@ unify goal inst = do
Nothing -> throwError (UnificationError inst goal)


------------------------------------------------------------------------------
-- | Prefer the first tactic to the second, if the bool is true. Otherwise, just run the second tactic.
--
-- This is useful when you have a clever pruning solution that isn't always
-- applicable.
attemptWhen :: TacticsM a -> TacticsM a -> Bool -> TacticsM a
attemptWhen _ t2 False = t2
attemptWhen t1 t2 True = commit t1 t2


------------------------------------------------------------------------------
-- | Get the class methods of a 'PredType', correctly dealing with
-- instantiation of quantified class types.
Expand Down
2 changes: 1 addition & 1 deletion plugins/hls-tactics-plugin/src/Wingman/Plugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ mkWorkspaceEdits
-> Either UserFacingMessage WorkspaceEdit
mkWorkspaceEdits span dflags ccs uri pm rtr = do
for_ (rtr_other_solns rtr) $ \soln -> do
traceMX "other solution" soln
traceMX "other solution" $ syn_val soln
traceMX "with score" $ scoreSolution soln (rtr_jdg rtr) []
traceMX "solution" $ rtr_extract rtr
let g = graftHole (RealSrcSpan span) rtr
Expand Down
27 changes: 23 additions & 4 deletions plugins/hls-tactics-plugin/src/Wingman/Tactics.hs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ intros = rule $ \jdg -> do
destructAuto :: HyInfo CType -> TacticsM ()
destructAuto hi = requireConcreteHole $ tracing "destruct(auto)" $ do
jdg <- goal
let subtactic = rule $ destruct' (const subgoal) hi
let subtactic = destructOrHomoAuto hi
case isPatternMatch $ hi_provenance hi of
True ->
pruning subtactic $ \jdgs ->
Expand All @@ -121,6 +121,25 @@ destructAuto hi = requireConcreteHole $ tracing "destruct(auto)" $ do
False -> subtactic


------------------------------------------------------------------------------
-- | When running auto, in order to prune the auto search tree, we try
-- a homomorphic destruct whenever possible. If that produces any results, we
-- can probably just prune the other side.
destructOrHomoAuto :: HyInfo CType -> TacticsM ()
destructOrHomoAuto hi = tracing "destructOrHomoAuto" $ do
jdg <- goal
let g = unCType $ jGoal jdg
ty = unCType $ hi_type hi

attemptWhen
(rule $ destruct' (\dc jdg ->
buildDataCon False jdg dc $ snd $ splitAppTys g) hi)
(rule $ destruct' (const subgoal) hi)
$ case (splitTyConApp_maybe g, splitTyConApp_maybe ty) of
(Just (gtc, _), Just (tytc, _)) -> gtc == tytc
_ -> False


------------------------------------------------------------------------------
-- | Case split, and leave holes in the matches.
destruct :: HyInfo CType -> TacticsM ()
Expand All @@ -132,7 +151,7 @@ destruct hi = requireConcreteHole $ tracing "destruct(user)" $
-- | Case split, using the same data constructor in the matches.
homo :: HyInfo CType -> TacticsM ()
homo = requireConcreteHole . tracing "homo" . rule . destruct' (\dc jdg ->
buildDataCon jdg dc $ snd $ splitAppTys $ unCType $ jGoal jdg)
buildDataCon False jdg dc $ snd $ splitAppTys $ unCType $ jGoal jdg)


------------------------------------------------------------------------------
Expand All @@ -147,7 +166,7 @@ homoLambdaCase :: TacticsM ()
homoLambdaCase =
tracing "homoLambdaCase" $
rule $ destructLambdaCase' $ \dc jdg ->
buildDataCon jdg dc
buildDataCon False jdg dc
. snd
. splitAppTys
. unCType
Expand Down Expand Up @@ -242,7 +261,7 @@ splitConLike dc =
let g = jGoal jdg
case splitTyConApp_maybe $ unCType g of
Just (_, apps) -> do
buildDataCon (unwhitelistingSplit jdg) dc apps
buildDataCon True (unwhitelistingSplit jdg) dc apps
Nothing -> throwError $ GoalMismatch "splitDataCon" g

------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions plugins/hls-tactics-plugin/test/CodeAction/AutoSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ spec = do
autoTest 9 12 "AutoEndo.hs"
autoTest 2 16 "AutoEmptyString.hs"
autoTest 7 35 "AutoPatSynUse.hs"
autoTest 2 28 "AutoZip.hs"

failing "flaky in CI" $
autoTest 2 11 "GoldenApplicativeThen.hs"
Expand Down
3 changes: 3 additions & 0 deletions plugins/hls-tactics-plugin/test/golden/AutoZip.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]
zip_it_up_and_zip_it_out = _

6 changes: 6 additions & 0 deletions plugins/hls-tactics-plugin/test/golden/AutoZip.hs.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]
zip_it_up_and_zip_it_out _ [] = []
zip_it_up_and_zip_it_out [] (_ : _) = []
zip_it_up_and_zip_it_out (a : l_a5) (b : l_b3)
= (a, b) : zip_it_up_and_zip_it_out l_a5 l_b3