Skip to content

Commit b5b8449

Browse files
Wingman: Fix fundeps (#2611)
* Fix fundeps * One unifier to rule them all * Fix imports Co-authored-by: Pepe Iborra <[email protected]>
1 parent b5c6dd0 commit b5b8449

File tree

6 files changed

+77
-10
lines changed

6 files changed

+77
-10
lines changed

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

+12-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Wingman.GHC where
66
import Control.Monad.State
77
import Control.Monad.Trans.Maybe (MaybeT(..))
88
import Data.Bool (bool)
9+
import Data.Coerce (coerce)
910
import Data.Function (on)
1011
import Data.Functor ((<&>))
1112
import Data.List (isPrefixOf)
@@ -359,12 +360,17 @@ expandTyFam ctx = snd . normaliseType (ctxFamInstEnvs ctx) Nominal
359360
-- | Like 'tcUnifyTy', but takes a list of skolems to prevent unification of.
360361
tryUnifyUnivarsButNotSkolems :: Set TyVar -> CType -> CType -> Maybe TCvSubst
361362
tryUnifyUnivarsButNotSkolems skolems goal inst =
362-
case tcUnifyTysFG
363-
(bool BindMe Skolem . flip S.member skolems)
364-
[unCType inst]
365-
[unCType goal] of
366-
Unifiable subst -> pure subst
367-
_ -> Nothing
363+
tryUnifyUnivarsButNotSkolemsMany skolems $ coerce [(goal, inst)]
364+
365+
------------------------------------------------------------------------------
366+
-- | Like 'tryUnifyUnivarsButNotSkolems', but takes a list
367+
-- of pairs of types to unify.
368+
tryUnifyUnivarsButNotSkolemsMany :: Set TyVar -> [(Type, Type)] -> Maybe TCvSubst
369+
tryUnifyUnivarsButNotSkolemsMany skolems (unzip -> (goal, inst)) =
370+
tcUnifyTys
371+
(bool BindMe Skolem . flip S.member skolems)
372+
inst
373+
goal
368374

369375

370376
updateSubst :: TCvSubst -> TacticState -> TacticState

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

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
{-# LANGUAGE TupleSections #-}
2-
{-# LANGUAGE RankNTypes #-}
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE RankNTypes #-}
3+
{-# LANGUAGE TupleSections #-}
34

45
module Wingman.Machinery where
56

@@ -30,11 +31,19 @@ import Refinery.Tactic
3031
import Refinery.Tactic.Internal
3132
import System.Timeout (timeout)
3233
import Wingman.Context (getInstance)
33-
import Wingman.GHC (tryUnifyUnivarsButNotSkolems, updateSubst, tacticsGetDataCons, freshTyvars)
34+
import Wingman.GHC (tryUnifyUnivarsButNotSkolems, updateSubst, tacticsGetDataCons, freshTyvars, tryUnifyUnivarsButNotSkolemsMany)
3435
import Wingman.Judgements
3536
import Wingman.Simplify (simplify)
3637
import Wingman.Types
3738

39+
#if __GLASGOW_HASKELL__ < 900
40+
import FunDeps (fd_eqs, improveFromInstEnv)
41+
import Pair (unPair)
42+
#else
43+
import GHC.Tc.Instance.FunDeps (fd_eqs, improveFromInstEnv)
44+
import GHC.Data.Pair (unPair)
45+
#endif
46+
3847

3948
substCTy :: TCvSubst -> CType -> CType
4049
substCTy subst = coerce . substTy subst . coerce
@@ -245,6 +254,23 @@ unify goal inst = do
245254
modify $ updateSubst subst
246255
Nothing -> cut
247256

257+
------------------------------------------------------------------------------
258+
-- | Get a substition out of a theta's fundeps
259+
learnFromFundeps
260+
:: ThetaType
261+
-> RuleM ()
262+
learnFromFundeps theta = do
263+
inst_envs <- asks ctxInstEnvs
264+
skolems <- gets ts_skolems
265+
subst <- gets ts_unifier
266+
let theta' = substTheta subst theta
267+
fundeps = foldMap (foldMap fd_eqs . improveFromInstEnv inst_envs (\_ _ -> ())) theta'
268+
case tryUnifyUnivarsButNotSkolemsMany skolems $ fmap unPair fundeps of
269+
Just subst ->
270+
modify $ updateSubst subst
271+
Nothing -> cut
272+
273+
248274
cut :: RuleT jdg ext err s m a
249275
cut = RuleT Empty
250276

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,12 @@ apply (Unsaturated n) hi = tracing ("apply' " <> show (hi_name hi)) $ do
280280
ty = unCType $ hi_type hi
281281
func = hi_name hi
282282
ty' <- freshTyvars ty
283-
let (_, _, all_args, ret) = tacticsSplitFunTy ty'
283+
let (_, theta, all_args, ret) = tacticsSplitFunTy ty'
284284
saturated_args = dropEnd n all_args
285285
unsaturated_args = takeEnd n all_args
286286
rule $ \jdg -> do
287287
unify g (CType $ mkVisFunTys unsaturated_args ret)
288+
learnFromFundeps theta
288289
ext
289290
<- fmap unzipTrace
290291
$ traverse ( newSubgoal

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

+2
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@ spec = do
4343
metaTest 5 9 "MetaIdiom"
4444
metaTest 7 9 "MetaIdiomRecord"
4545

46+
metaTest 14 10 "MetaFundeps"
47+
4648
metaTest 2 12 "IntrosTooMany"
4749

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{-# LANGUAGE FunctionalDependencies #-}
2+
{-# LANGUAGE MultiParamTypeClasses #-}
3+
4+
class Blah a b | a -> b, b -> a
5+
instance Blah Int Bool
6+
7+
foo :: Int
8+
foo = 10
9+
10+
bar :: Blah a b => a -> b
11+
bar = undefined
12+
13+
qux :: Bool
14+
qux = bar foo
15+
16+
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{-# LANGUAGE FunctionalDependencies #-}
2+
{-# LANGUAGE MultiParamTypeClasses #-}
3+
4+
class Blah a b | a -> b, b -> a
5+
instance Blah Int Bool
6+
7+
foo :: Int
8+
foo = 10
9+
10+
bar :: Blah a b => a -> b
11+
bar = undefined
12+
13+
qux :: Bool
14+
qux = [wingman| use bar, use foo |]
15+
16+

0 commit comments

Comments
 (0)