Skip to content

Wingman: Add "New Unification Variable" helper #2164

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 9 commits into from
Sep 10, 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
9 changes: 8 additions & 1 deletion plugins/hls-tactics-plugin/src/Wingman/Machinery.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ import Refinery.Tactic.Internal
import System.Timeout (timeout)
import TcType
import Type (tyCoVarsOfTypeWellScoped)
import TysPrim (alphaTyVar, alphaTy)
import Wingman.Context (getInstance)
import Wingman.GHC (tryUnifyUnivarsButNotSkolems, updateSubst, tacticsGetDataCons)
import Wingman.GHC (tryUnifyUnivarsButNotSkolems, updateSubst, tacticsGetDataCons, freshTyvars)
import Wingman.Judgements
import Wingman.Simplify (simplify)
import Wingman.Types
Expand Down Expand Up @@ -229,6 +230,12 @@ newtype Reward a = Reward a
deriving (Eq, Ord, Show) via a


------------------------------------------------------------------------------
-- | Generate a unique unification variable.
newUnivar :: MonadState TacticState m => m Type
newUnivar = do
freshTyvars $
mkInvForAllTys [alphaTyVar] alphaTy


------------------------------------------------------------------------------
Expand Down
14 changes: 6 additions & 8 deletions plugins/hls-tactics-plugin/src/Wingman/Tactics.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import Refinery.Tactic
import Refinery.Tactic.Internal
import TcType
import Type hiding (Var)
import TysPrim (betaTy, alphaTy, betaTyVar, alphaTyVar)
import Wingman.CodeGen
import Wingman.GHC
import Wingman.Judgements
Expand Down Expand Up @@ -543,10 +542,10 @@ applyByType ty = tracing ("applyByType " <> show ty) $ do
-- | Make an n-ary function call of the form
-- @(_ :: forall a b. a -> a -> b) _ _@.
nary :: Int -> TacticsM ()
nary n =
applyByType $
mkInvForAllTys [alphaTyVar, betaTyVar] $
mkFunTys' (replicate n alphaTy) betaTy
nary n = do
a <- newUnivar
b <- newUnivar
applyByType $ mkFunTys' (replicate n a) b


self :: TacticsM ()
Expand Down Expand Up @@ -589,8 +588,7 @@ letBind occs = do
-> fmap (occ, )
$ fmap (<$ jdg)
$ fmap CType
$ freshTyvars
$ mkInvForAllTys [alphaTyVar] alphaTy
$ newUnivar
rule $ nonrecLet occ_tys


Expand Down Expand Up @@ -630,7 +628,7 @@ collapse = do
with_arg :: TacticsM ()
with_arg = rule $ \jdg -> do
let g = jGoal jdg
fresh_ty <- freshTyvars $ mkInvForAllTys [alphaTyVar] alphaTy
fresh_ty <- newUnivar
a <- newSubgoal $ withNewGoal (CType fresh_ty) jdg
f <- newSubgoal $ withNewGoal (coerce mkFunTys' [fresh_ty] g) jdg
pure $ fmap noLoc $ (@@) <$> fmap unLoc f <*> fmap unLoc a
Expand Down
7 changes: 4 additions & 3 deletions plugins/hls-tactics-plugin/test/AutoTupleSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

module AutoTupleSpec where

import Control.Monad (replicateM)
import Control.Monad.State (evalState)
import Data.Either (isRight)
import OccName (mkVarOcc)
import System.IO.Unsafe
import Test.Hspec
import Test.QuickCheck
import Type (mkTyVarTy)
import TysPrim (alphaTyVars)
import TysWiredIn (mkBoxedTupleTy)
import Wingman.Judgements (mkFirstJudgement)
import Wingman.Machinery
Expand All @@ -24,7 +24,8 @@ spec = describe "auto for tuple" $ do
property $ do
-- Pick some number of variables
n <- choose (1, 7)
let vars = fmap mkTyVarTy $ take n alphaTyVars
let vars = flip evalState defaultTacticState
$ replicateM n newUnivar
-- Pick a random ordering
in_vars <- shuffle vars
-- Randomly associate them into tuple types
Expand Down
38 changes: 27 additions & 11 deletions plugins/hls-tactics-plugin/test/UnificationSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
module UnificationSpec where

import Control.Arrow
import Control.Monad (replicateM, join)
import Control.Monad.State (evalState)
import Data.Bool (bool)
import Data.Functor ((<&>))
import Data.Maybe (mapMaybe)
Expand All @@ -13,10 +15,9 @@ import Data.Tuple (swap)
import TcType (substTy, tcGetTyVar_maybe)
import Test.Hspec
import Test.QuickCheck
import Type (mkTyVarTy)
import TysPrim (alphaTyVars)
import TysWiredIn (mkBoxedTupleTy)
import Wingman.GHC
import Wingman.Machinery (newUnivar)
import Wingman.Types


Expand All @@ -25,8 +26,11 @@ spec = describe "unification" $ do
it "should be able to unify univars with skolems on either side of the equality" $ do
property $ do
-- Pick some number of unification vars and skolem
n <- choose (1, 1)
let (skolems, take n -> univars) = splitAt n $ fmap mkTyVarTy alphaTyVars
n <- choose (1, 20)
let (skolems, take n -> univars)
= splitAt n
$ flip evalState defaultTacticState
$ replicateM (n * 2) newUnivar
-- Randomly pair them
skolem_uni_pairs <-
for (zip skolems univars) randomSwap
Expand All @@ -42,13 +46,25 @@ spec = describe "unification" $ do
(CType lhs)
(CType rhs) of
Just subst ->
-- For each pair, running the unification over the univar should
-- result in the skolem
conjoin $ zip univars skolems <&> \(uni, skolem) ->
let substd = substTy subst uni
in counterexample (show substd) $
counterexample (show skolem) $
CType substd === CType skolem
conjoin $ join $
[ -- For each pair, running the unification over the univar should
-- result in the skolem
zip univars skolems <&> \(uni, skolem) ->
let substd = substTy subst uni
in counterexample (show substd) $
counterexample (show skolem) $
CType substd === CType skolem

-- And also, no two univars should equal to one another
-- before or after substitution.
, zip univars (tail univars) <&> \(uni1, uni2) ->
let uni1_sub = substTy subst uni1
uni2_sub = substTy subst uni2
in counterexample (show uni1) $
counterexample (show uni2) $
CType uni1 =/= CType uni2 .&&.
CType uni1_sub =/= CType uni2_sub
]
Nothing -> True === False


Expand Down