From 04c2df837b10d176dbe5c945adaf038abefa7f76 Mon Sep 17 00:00:00 2001 From: Sandy Maguire Date: Tue, 16 Mar 2021 22:30:09 -0700 Subject: [PATCH 1/2] Use a canonical ordering when destructing terms --- .../src/Wingman/Judgements.hs | 40 +++++++++++++++---- .../hls-tactics-plugin/src/Wingman/Tactics.hs | 4 +- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs b/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs index ed1122d4ae..ee1ad2c298 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs @@ -16,6 +16,7 @@ import Development.IDE.Spans.LocalBindings import OccName import SrcLoc import Type +import Wingman.GHC (algebraicTyCon) import Wingman.Types @@ -149,7 +150,10 @@ findPositionVal :: Judgement' a -> OccName -> Int -> Maybe OccName findPositionVal jdg defn pos = listToMaybe $ do -- It's important to inspect the entire hypothesis here, as we need to trace -- ancstry through potentially disallowed terms in the hypothesis. - (name, hi) <- M.toList $ M.map (overProvenance expandDisallowed) $ hyByName $ jEntireHypothesis jdg + (name, hi) <- M.toList + $ M.map (overProvenance expandDisallowed) + $ hyByName + $ jEntireHypothesis jdg case hi_provenance hi of TopLevelArgPrv defn' pos' _ | defn == defn' @@ -238,12 +242,13 @@ patternHypothesis scrutinee dc jdg = introduceHypothesis $ \_ pos -> PatternMatchPrv $ PatVal - scrutinee - (maybe mempty - (\scrut -> S.singleton scrut <> getAncestry jdg scrut) - scrutinee) - (Uniquely dc) - pos + scrutinee + (maybe + mempty + (\scrut -> S.singleton scrut <> getAncestry jdg scrut) + scrutinee) + (Uniquely dc) + pos ------------------------------------------------------------------------------ @@ -285,6 +290,21 @@ jLocalHypothesis . jHypothesis +------------------------------------------------------------------------------ +-- | Given a judgment, return the hypotheses that are acceptable to destruct. +-- +-- We use the ordering of the hypothesis for this purpose. Since new bindings +-- are always inserted at the beginning, we can impose a canonical ordering on +-- which order to try destructs by what order they are introduced --- stopping +-- at the first one we've already destructed. +jAcceptableDestructTargets :: Judgement' CType -> [HyInfo CType] +jAcceptableDestructTargets + = filter (isJust . algebraicTyCon . unCType . hi_type) + . takeWhile (not . isAlreadyDestructed . hi_provenance) + . unHypothesis + . jEntireHypothesis + + ------------------------------------------------------------------------------ -- | If we're in a top hole, the name of the defining function. isTopHole :: Context -> Judgement' a -> Maybe OccName @@ -391,6 +411,12 @@ isDisallowed :: Provenance -> Bool isDisallowed DisallowedPrv{} = True isDisallowed _ = False +------------------------------------------------------------------------------ +-- | Has this term already been disallowed? +isAlreadyDestructed :: Provenance -> Bool +isAlreadyDestructed (DisallowedPrv AlreadyDestructed _) = True +isAlreadyDestructed _ = False + ------------------------------------------------------------------------------ -- | Eliminates 'DisallowedPrv' provenances. diff --git a/plugins/hls-tactics-plugin/src/Wingman/Tactics.hs b/plugins/hls-tactics-plugin/src/Wingman/Tactics.hs index 858b24aa59..2b63d6ee77 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/Tactics.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/Tactics.hs @@ -339,9 +339,7 @@ overFunctions = overAlgebraicTerms :: (HyInfo CType -> TacticsM ()) -> TacticsM () overAlgebraicTerms = - attemptOn $ filter (isJust . algebraicTyCon . unCType . hi_type) - . unHypothesis - . jHypothesis + attemptOn jAcceptableDestructTargets allNames :: Judgement -> Set OccName From 4f24c60055b86b6843dfe6a1284f29c6b0676edd Mon Sep 17 00:00:00 2001 From: Sandy Maguire Date: Wed, 17 Mar 2021 09:27:56 -0700 Subject: [PATCH 2/2] Fix introducing hypotheses in the wrong order --- plugins/hls-tactics-plugin/src/Wingman/Judgements.hs | 5 ++++- plugins/hls-tactics-plugin/src/Wingman/Types.hs | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs b/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs index ee1ad2c298..92c1f7fdd9 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/Judgements.hs @@ -62,7 +62,10 @@ withNewGoal t = field @"_jGoal" .~ t introduce :: Hypothesis a -> Judgement' a -> Judgement' a -introduce hy = field @"_jHypothesis" <>~ hy +-- NOTE(sandy): It's important that we put the new hypothesis terms first, +-- since 'jAcceptableDestructTargets' will never destruct a pattern that occurs +-- after a previously-destructed term. +introduce hy = field @"_jHypothesis" %~ mappend hy ------------------------------------------------------------------------------ diff --git a/plugins/hls-tactics-plugin/src/Wingman/Types.hs b/plugins/hls-tactics-plugin/src/Wingman/Types.hs index 2f28f8d3d0..71e58ef68f 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/Types.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/Types.hs @@ -261,6 +261,10 @@ instance Uniquable a => Ord (Uniquely a) where compare = nonDetCmpUnique `on` getUnique . getViaUnique +-- NOTE(sandy): The usage of list here is mostly for convenience, but if it's +-- ever changed, make sure to correspondingly update +-- 'jAcceptableDestructTargets' so that it correctly identifies newly +-- introduced terms. newtype Hypothesis a = Hypothesis { unHypothesis :: [HyInfo a] }