remove empty dir
[ghc-hetmet.git] / ghc / compiler / types / Unify.lhs
index 42ea928..f60c7be 100644 (file)
@@ -1,10 +1,13 @@
 \begin{code}
 module Unify ( 
        -- Matching and unification
-       matchTys, matchTyX, matchTysX,
-       unifyTys, unifyTysX,
+       tcMatchTys, tcMatchTyX, ruleMatchTyX, tcMatchPreds, MatchEnv(..), 
 
-       tcRefineTys, tcMatchTys, tcMatchPreds, coreRefineTys,
+       tcUnifyTys, 
+
+       gadtRefineTys, BindFlag(..),
+
+       coreRefineTys, TypeRefinement,
 
        -- Re-export
        MaybeErr(..)
@@ -16,10 +19,11 @@ import Var          ( Var, TyVar, tyVarKind )
 import VarEnv
 import VarSet
 import Kind            ( isSubKind )
-import Type            ( predTypeRep, newTypeRep, typeKind, 
-                         tyVarsOfType, tyVarsOfTypes, 
-                         TvSubstEnv, TvSubst(..), substTy )
+import Type            ( typeKind, tyVarsOfType, tyVarsOfTypes, tyVarsOfTheta, mkTyVarTys,
+                         TvSubstEnv, emptyTvSubstEnv, TvSubst(..), substTy, tcEqTypeX,
+                         mkOpenTvSubst, tcView )
 import TypeRep          ( Type(..), PredType(..), funTyCon )
+import DataCon                 ( DataCon, dataConInstResTy )
 import Util            ( snocView )
 import ErrUtils                ( Message )
 import Outputable
@@ -29,116 +33,252 @@ import Maybes
 
 %************************************************************************
 %*                                                                     *
-               External interface
+               Matching
 %*                                                                     *
 %************************************************************************
 
-\begin{code}
-----------------------------
-tcRefineTys, tcMatchTys 
-       :: [TyVar]                      -- Try to unify these
-       -> TvSubstEnv                   -- Not idempotent
-       -> [Type] -> [Type]
-       -> MaybeErr TvSubstEnv Message  -- Not idempotent
--- This one is used by the type checker.  Neither the input nor result
--- substitition is idempotent
-tcRefineTys ex_tvs subst tys1 tys2
-  = initUM (tryToBind (mkVarSet ex_tvs)) (unify_tys Src subst tys1 tys2)
-
-tcMatchTys ex_tvs subst tys1 tys2
-  = initUM (bindOnly (mkVarSet ex_tvs)) (unify_tys Src subst tys1 tys2)
 
-tcMatchPreds
-       :: [TyVar]                      -- Bind these
-       -> [PredType] -> [PredType]
-       -> Maybe TvSubstEnv
-tcMatchPreds tvs preds1 preds2
-  = maybeErrToMaybe $ initUM (bindOnly (mkVarSet tvs)) $
-    unify_preds Src emptyVarEnv preds1 preds2
+Matching is much tricker than you might think.
 
-----------------------------
-coreRefineTys :: [TyVar]       -- Try to unify these
-             -> TvSubst        -- A full-blown apply-once substitition
-             -> Type           -- A fixed point of the incoming substitution
-             -> Type
-             -> Maybe TvSubstEnv       -- In-scope set is unaffected
--- Used by Core Lint and the simplifier.  Takes a full apply-once substitution.
--- The incoming substitution's in-scope set should mention all the variables free 
--- in the incoming types
-coreRefineTys ex_tvs subst@(TvSubst in_scope orig_env) ty1 ty2
-  = maybeErrToMaybe $ initUM (tryToBind (mkVarSet ex_tvs)) $
-    do {       -- Apply the input substitution; nothing int ty2
-         let ty1' = substTy subst ty1  
-               -- Run the unifier, starting with an empty env
-       ; extra_env <- unify Src emptyTvSubstEnv ty1' ty2
-
-               -- Find the fixed point of the resulting non-idempotent
-               -- substitution, and apply it to the 
-       ; let extra_subst     = TvSubst in_scope extra_env_fixpt
-             extra_env_fixpt = mapVarEnv (substTy extra_subst) extra_env
-             orig_env'       = mapVarEnv (substTy extra_subst) orig_env
-       ; return (orig_env' `plusVarEnv` extra_env_fixpt) }
-    
+1. The substitution we generate binds the *template type variables*
+   which are given to us explicitly.
 
-----------------------------
-matchTys :: TyVarSet           -- Template tyvars
+2. We want to match in the presence of foralls; 
+       e.g     (forall a. t1) ~ (forall b. t2)
+
+   That is what the RnEnv2 is for; it does the alpha-renaming
+   that makes it as if a and b were the same variable.
+   Initialising the RnEnv2, so that it can generate a fresh
+   binder when necessary, entails knowing the free variables of
+   both types.
+
+3. We must be careful not to bind a template type variable to a
+   locally bound variable.  E.g.
+       (forall a. x) ~ (forall b. b)
+   where x is the template type variable.  Then we do not want to
+   bind x to a/b!  This is a kind of occurs check.
+   The necessary locals accumulate in the RnEnv2.
+
+
+\begin{code}
+data MatchEnv
+  = ME { me_tmpls :: VarSet    -- Template tyvars
+       , me_env   :: RnEnv2    -- Renaming envt for nested foralls
+       }                       --   In-scope set includes template tyvars
+
+tcMatchTys :: TyVarSet         -- Template tyvars
         -> [Type]              -- Template
         -> [Type]              -- Target
-        -> Maybe TvSubstEnv    -- Idempotent, because when matching
-                               --      the range and domain are distinct
+        -> Maybe TvSubst       -- One-shot; in principle the template
+                               -- variables could be free in the target
 
--- PRE-CONDITION for matching: template variables are not free in the target
+tcMatchTys tmpls tys1 tys2
+  = case match_tys menv emptyTvSubstEnv tys1 tys2 of
+       Just subst_env -> Just (TvSubst in_scope subst_env)
+       Nothing        -> Nothing
+  where
+    menv     = ME { me_tmpls = tmpls, me_env = mkRnEnv2 in_scope }
+    in_scope = mkInScopeSet (tmpls `unionVarSet` tyVarsOfTypes tys2)
+       -- We're assuming that all the interesting 
+       -- tyvars in tys1 are in tmpls
+
+-- This is similar, but extends a substitution
+tcMatchTyX :: TyVarSet                 -- Template tyvars
+          -> TvSubst           -- Substitution to extend
+          -> Type              -- Template
+          -> Type              -- Target
+          -> Maybe TvSubst
+tcMatchTyX tmpls (TvSubst in_scope subst_env) ty1 ty2
+  = case match menv subst_env ty1 ty2 of
+       Just subst_env -> Just (TvSubst in_scope subst_env)
+       Nothing        -> Nothing
+  where
+    menv = ME {me_tmpls = tmpls, me_env = mkRnEnv2 in_scope}
 
-matchTys tmpls tys1 tys2
-  = ASSERT2( not (intersectsVarSet tmpls (tyVarsOfTypes tys2)),
-            ppr tmpls $$ ppr tys1 $$ ppr tys2 )
-    maybeErrToMaybe $ initUM (bindOnly tmpls)
-                            (unify_tys Src emptyTvSubstEnv tys1 tys2)
+tcMatchPreds
+       :: [TyVar]                      -- Bind these
+       -> [PredType] -> [PredType]
+       -> Maybe TvSubstEnv
+tcMatchPreds tmpls ps1 ps2
+  = match_list (match_pred menv) emptyTvSubstEnv ps1 ps2
+  where
+    menv = ME { me_tmpls = mkVarSet tmpls, me_env = mkRnEnv2 in_scope_tyvars }
+    in_scope_tyvars = mkInScopeSet (tyVarsOfTheta ps1 `unionVarSet` tyVarsOfTheta ps2)
 
-matchTyX :: TyVarSet           -- Template tyvars
-        -> TvSubstEnv          -- Idempotent substitution to extend
+-- This one is called from the expression matcher, which already has a MatchEnv in hand
+ruleMatchTyX :: MatchEnv 
+        -> TvSubstEnv          -- Substitution to extend
         -> Type                -- Template
         -> Type                -- Target
-        -> Maybe TvSubstEnv    -- Idempotent
+        -> Maybe TvSubstEnv
 
-matchTyX tmpls env ty1 ty2
-  = ASSERT( not (intersectsVarSet tmpls (tyVarsOfType ty2)) )
-    maybeErrToMaybe $ initUM (bindOnly tmpls)
-                            (unify Src env ty1 ty2)
+ruleMatchTyX menv subst ty1 ty2 = match menv subst ty1 ty2     -- Rename for export
+\end{code}
 
-matchTysX :: TyVarSet          -- Template tyvars
-         -> TvSubstEnv         -- Idempotent substitution to extend
-         -> [Type]             -- Template
-         -> [Type]             -- Target
-         -> Maybe TvSubstEnv   -- Idempotent
+Now the internals of matching
 
-matchTysX tmpls env tys1 tys2
-  = ASSERT( not (intersectsVarSet tmpls (tyVarsOfTypes tys2)) )
-    maybeErrToMaybe $ initUM (bindOnly tmpls) 
-                            (unify_tys Src env tys1 tys2)
+\begin{code}
+match :: MatchEnv      -- For the most part this is pushed downwards
+      -> TvSubstEnv    -- Substitution so far:
+                       --   Domain is subset of template tyvars
+                       --   Free vars of range is subset of 
+                       --      in-scope set of the RnEnv2
+      -> Type -> Type  -- Template and target respectively
+      -> Maybe TvSubstEnv
+-- This matcher works on source types; that is, 
+-- it respects NewTypes and PredType
+
+match menv subst ty1 ty2 | Just ty1' <- tcView ty1 = match menv subst ty1' ty2
+match menv subst ty1 ty2 | Just ty2' <- tcView ty2 = match menv subst ty1 ty2'
+
+match menv subst (TyVarTy tv1) ty2
+  | tv1 `elemVarSet` me_tmpls menv
+  = case lookupVarEnv subst tv1' of
+       Nothing | any (inRnEnvR rn_env) (varSetElems (tyVarsOfType ty2))
+               -> Nothing      -- Occurs check
+               | not (typeKind ty2 `isSubKind` tyVarKind tv1)
+               -> Nothing      -- Kind mis-match
+               | otherwise
+               -> Just (extendVarEnv subst tv1 ty2)
+
+       Just ty1' | tcEqTypeX (nukeRnEnvL rn_env) ty1' ty2
+               -- ty1 has no locally-bound variables, hence nukeRnEnvL
+               -- Note tcEqType...we are doing source-type matching here
+                 -> Just subst
+
+       other -> Nothing
+
+   | otherwise -- tv1 is not a template tyvar
+   = case ty2 of
+       TyVarTy tv2 | tv1' == rnOccR rn_env tv2 -> Just subst
+       other                                   -> Nothing
+  where
+    rn_env = me_env menv
+    tv1' = rnOccL rn_env tv1
+
+match menv subst (ForAllTy tv1 ty1) (ForAllTy tv2 ty2) 
+  = match menv' subst ty1 ty2
+  where                -- Use the magic of rnBndr2 to go under the binders
+    menv' = menv { me_env = rnBndr2 (me_env menv) tv1 tv2 }
+
+match menv subst (PredTy p1) (PredTy p2) 
+  = match_pred menv subst p1 p2
+match menv subst (TyConApp tc1 tys1) (TyConApp tc2 tys2) 
+  | tc1 == tc2 = match_tys menv subst tys1 tys2
+match menv subst (FunTy ty1a ty1b) (FunTy ty2a ty2b) 
+  = do { subst' <- match menv subst ty1a ty2a
+       ; match menv subst' ty1b ty2b }
+match menv subst (AppTy ty1a ty1b) ty2
+  | Just (ty2a, ty2b) <- repSplitAppTy_maybe ty2
+  = do { subst' <- match menv subst ty1a ty2a
+       ; match menv subst' ty1b ty2b }
+
+match menv subst ty1 ty2
+  = Nothing
+
+--------------
+match_tys menv subst tys1 tys2 = match_list (match menv) subst tys1 tys2
+
+--------------
+match_list :: (TvSubstEnv -> a -> a -> Maybe TvSubstEnv)
+          -> TvSubstEnv -> [a] -> [a] -> Maybe TvSubstEnv
+match_list fn subst []         []        = Just subst
+match_list fn subst (ty1:tys1) (ty2:tys2) = do { subst' <- fn subst ty1 ty2
+                                               ; match_list fn subst' tys1 tys2 }
+match_list fn subst tys1       tys2      = Nothing     
+
+--------------
+match_pred menv subst (ClassP c1 tys1) (ClassP c2 tys2)
+  | c1 == c2 = match_tys menv subst tys1 tys2
+match_pred menv subst (IParam n1 t1) (IParam n2 t2)
+  | n1 == n2 = match menv subst t1 t2
+match_pred menv subst p1 p2 = Nothing
+\end{code}
 
 
-----------------------------
-unifyTys :: TyVarSet -> [Type] -> [Type] -> Maybe TvSubstEnv
-unifyTys bind_these tys1 tys2
-  = maybeErrToMaybe $ initUM (bindOnly bind_these) $
-    unify_tys Src emptyTvSubstEnv tys1 tys2
+%************************************************************************
+%*                                                                     *
+               Unification
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+tcUnifyTys :: (TyVar -> BindFlag)
+          -> [Type] -> [Type]
+          -> Maybe TvSubst     -- A regular one-shot substitution
+-- The two types may have common type variables, and indeed do so in the
+-- second call to tcUnifyTys in FunDeps.checkClsFD
+tcUnifyTys bind_fn tys1 tys2
+  = maybeErrToMaybe $ initUM bind_fn $
+    do { subst_env <- unify_tys emptyTvSubstEnv tys1 tys2
+
+       -- Find the fixed point of the resulting non-idempotent substitution
+       ; let in_scope        = mkInScopeSet (tvs1 `unionVarSet` tvs2)
+             subst           = TvSubst in_scope subst_env_fixpt
+             subst_env_fixpt = mapVarEnv (substTy subst) subst_env
+       ; return subst }
+  where
+    tvs1 = tyVarsOfTypes tys1
+    tvs2 = tyVarsOfTypes tys2
 
-unifyTysX :: TyVarSet -> TvSubstEnv -> [Type] -> [Type] -> Maybe TvSubstEnv
-unifyTysX bind_these subst tys1 tys2
-  = maybeErrToMaybe $ initUM (bindOnly bind_these) $
-    unify_tys Src subst tys1 tys2
+----------------------------
+coreRefineTys :: DataCon -> [TyVar]    -- Case pattern (con tv1 .. tvn ...)
+             -> Type                   -- Type of scrutinee
+             -> Maybe TypeRefinement
+
+type TypeRefinement = (TvSubstEnv, Bool)
+       -- The Bool is True iff all the bindings in the 
+       -- env are for the pattern type variables
+       -- In this case, there is no type refinement 
+       -- for already-in-scope type variables
+
+-- Used by Core Lint and the simplifier.
+coreRefineTys con tvs scrut_ty
+  = maybeErrToMaybe $ initUM (tryToBind tv_set) $
+    do {       -- Run the unifier, starting with an empty env
+       ; subst_env <- unify emptyTvSubstEnv pat_res_ty scrut_ty
+
+       -- Find the fixed point of the resulting non-idempotent substitution
+       ; let subst           = mkOpenTvSubst subst_env_fixpt
+             subst_env_fixpt = mapVarEnv (substTy subst) subst_env
+               
+       ; return (subst_env_fixpt, all_bound_here subst_env) }
+  where
+    pat_res_ty = dataConInstResTy con (mkTyVarTys tvs)
+
+       -- 'tvs' are the tyvars bound by the pattern
+    tv_set            = mkVarSet tvs
+    all_bound_here env = all bound_here (varEnvKeys env)
+    bound_here uniq    = elemVarSetByKey uniq tv_set
+
+-- This version is used by the type checker
+gadtRefineTys :: TvSubst 
+             -> DataCon -> [TyVar]
+             -> [Type] -> [Type]       
+             -> MaybeErr Message (TvSubst, Bool)
+-- The bool is True <=> the only *new* bindings are for pat_tvs
+
+gadtRefineTys (TvSubst in_scope env1) con pat_tvs pat_tys ctxt_tys
+  = initUM (tryToBind tv_set) $
+    do {       -- Run the unifier, starting with an empty env
+       ; env2 <- unify_tys env1 pat_tys ctxt_tys
+
+       -- Find the fixed point of the resulting non-idempotent substitution
+       ; let subst2          = TvSubst in_scope subst_env_fixpt
+             subst_env_fixpt = mapVarEnv (substTy subst2) env2
+               
+       ; return (subst2, all_bound_here env2) }
+  where
+       -- 'tvs' are the tyvars bound by the pattern
+    tv_set            = mkVarSet pat_tvs
+    all_bound_here env = all bound_here (varEnvKeys env)
+    bound_here uniq    = elemVarEnvByKey uniq env1 || elemVarSetByKey uniq tv_set
+       -- The bool is True <=> the only *new* bindings are for pat_tvs
 
 ----------------------------
-tryToBind, bindOnly :: TyVarSet -> TyVar -> BindFlag
+tryToBind :: TyVarSet -> TyVar -> BindFlag
 tryToBind tv_set tv | tv `elemVarSet` tv_set = BindMe
                    | otherwise              = AvoidMe
-
-bindOnly tv_set tv | tv `elemVarSet` tv_set = BindMe
-                  | otherwise              = DontBindMe
-
-emptyTvSubstEnv :: TvSubstEnv
-emptyTvSubstEnv = emptyVarEnv
 \end{code}
 
 
@@ -149,8 +289,7 @@ emptyTvSubstEnv = emptyVarEnv
 %************************************************************************
 
 \begin{code}
-unify :: SrcFlag                -- True, unifying source types, false core types.
-      -> TvSubstEnv            -- An existing substitution to extend
+unify :: TvSubstEnv            -- An existing substitution to extend
       -> Type -> Type           -- Types to be unified
       -> UM TvSubstEnv         -- Just the extended substitution, 
                                -- Nothing if unification failed
@@ -158,76 +297,52 @@ unify :: SrcFlag                -- True, unifying source types, false core types
 -- nor guarantee that the outgoing one is.  That's fixed up by
 -- the wrappers.
 
--- ToDo: remove debugging junk
-unify s subst ty1 ty2 = -- pprTrace "unify" (ppr subst <+> pprParendType ty1 <+> pprParendType ty2) $
-                       unify_ s subst ty1 ty2
-
--- Look through NoteTy in the obvious fashion
-unify_ s subst (NoteTy _ ty1) ty2  = unify s subst ty1 ty2
-unify_ s subst ty1 (NoteTy _ ty2)  = unify s subst ty1 ty2
+-- Respects newtypes, PredTypes
 
--- In Core mode, look through NewTcApps and Preds
-unify_ Core subst (NewTcApp tc tys) ty2 = unify Core subst (newTypeRep tc tys) ty2
-unify_ Core subst ty1 (NewTcApp tc tys) = unify Core subst ty1 (newTypeRep tc tys)
+unify subst ty1 ty2 = -- pprTrace "unify" (ppr subst <+> pprParendType ty1 <+> pprParendType ty2) $
+                     unify_ subst ty1 ty2
 
-unify_ Core subst (PredTy p) ty2 = unify Core subst (predTypeRep p) ty2
-unify_ Core subst ty1 (PredTy p) = unify Core subst ty1 (predTypeRep p)
+-- in unify_, any NewTcApps/Preds should be taken at face value
+unify_ subst (TyVarTy tv1) ty2  = uVar False subst tv1 ty2
+unify_ subst ty1 (TyVarTy tv2)  = uVar True  subst tv2 ty1
 
--- From now on, any NewTcApps/Preds should be taken at face value
+unify_ subst ty1 ty2 | Just ty1' <- tcView ty1 = unify subst ty1' ty2
+unify_ subst ty1 ty2 | Just ty2' <- tcView ty2 = unify subst ty1 ty2'
 
-unify_ s subst (TyVarTy tv1) ty2  = uVar s False subst tv1 ty2
-unify_ s subst ty1 (TyVarTy tv2)  = uVar s True  subst tv2 ty1
+unify_ subst (PredTy p1) (PredTy p2) = unify_pred subst p1 p2
 
-unify_ s subst (PredTy p1) (PredTy p2) = unify_pred s subst p1 p2
+unify_ subst t1@(TyConApp tyc1 tys1) t2@(TyConApp tyc2 tys2) 
+  | tyc1 == tyc2 = unify_tys subst tys1 tys2
 
-unify_ s subst t1@(TyConApp tyc1 tys1) t2@(TyConApp tyc2 tys2) 
-  | tyc1 == tyc2 = unify_tys s subst tys1 tys2
-unify_ Src subst t1@(NewTcApp tc1 tys1) t2@(NewTcApp tc2 tys2)  
-  | tc1 == tc2 = unify_tys Src subst tys1 tys2
-unify_ s subst (FunTy ty1a ty1b) (FunTy ty2a ty2b) 
-  = do { subst' <- unify s subst ty1a ty2a
-       ; unify s subst' ty1b ty2b }
+unify_ subst (FunTy ty1a ty1b) (FunTy ty2a ty2b) 
+  = do { subst' <- unify subst ty1a ty2a
+       ; unify subst' ty1b ty2b }
 
        -- Applications need a bit of care!
        -- They can match FunTy and TyConApp, so use splitAppTy_maybe
        -- NB: we've already dealt with type variables and Notes,
        -- so if one type is an App the other one jolly well better be too
-unify_ s subst (AppTy ty1a ty1b) ty2
-  | Just (ty2a, ty2b) <- unifySplitAppTy_maybe ty2
-  = do { subst' <- unify s subst ty1a ty2a
-        ; unify s subst' ty1b ty2b }
+unify_ subst (AppTy ty1a ty1b) ty2
+  | Just (ty2a, ty2b) <- repSplitAppTy_maybe ty2
+  = do { subst' <- unify subst ty1a ty2a
+        ; unify subst' ty1b ty2b }
 
-unify_ s subst ty1 (AppTy ty2a ty2b)
-  | Just (ty1a, ty1b) <- unifySplitAppTy_maybe ty1
-  = do { subst' <- unify s subst ty1a ty2a
-        ; unify s subst' ty1b ty2b }
+unify_ subst ty1 (AppTy ty2a ty2b)
+  | Just (ty1a, ty1b) <- repSplitAppTy_maybe ty1
+  = do { subst' <- unify subst ty1a ty2a
+        ; unify subst' ty1b ty2b }
 
-unify_ s subst ty1 ty2 = failWith (misMatch ty1 ty2)
+unify_ subst ty1 ty2 = failWith (misMatch ty1 ty2)
 
 ------------------------------
-unify_pred s subst (ClassP c1 tys1) (ClassP c2 tys2)
-  | c1 == c2 = unify_tys s subst tys1 tys2
-unify_pred s subst (IParam n1 t1) (IParam n2 t2)
-  | n1 == n2 = unify s subst t1 t2
+unify_pred subst (ClassP c1 tys1) (ClassP c2 tys2)
+  | c1 == c2 = unify_tys subst tys1 tys2
+unify_pred subst (IParam n1 t1) (IParam n2 t2)
+  | n1 == n2 = unify subst t1 t2
+unify_pred subst p1 p2 = failWith (misMatch (PredTy p1) (PredTy p2))
  
 ------------------------------
-unifySplitAppTy_maybe :: Type -> Maybe (Type,Type)
--- NoteTy is already dealt with; take NewTcApps at face value
-unifySplitAppTy_maybe (FunTy ty1 ty2)   = Just (TyConApp funTyCon [ty1], ty2)
-unifySplitAppTy_maybe (AppTy ty1 ty2)   = Just (ty1, ty2)
-unifySplitAppTy_maybe (TyConApp tc tys) = case snocView tys of
-                                               Just (tys', ty') -> Just (TyConApp tc tys', ty')
-                                               Nothing          -> Nothing
-unifySplitAppTy_maybe (NewTcApp tc tys) = case snocView tys of
-                                               Just (tys', ty') -> Just (NewTcApp tc tys', ty')
-                                               Nothing          -> Nothing
-unifySplitAppTy_maybe other = Nothing
-
-------------------------------
-unify_tys s   = unifyList (unify s)
-
-unify_preds :: SrcFlag -> TvSubstEnv -> [PredType] -> [PredType] -> UM TvSubstEnv
-unify_preds s = unifyList (unify_pred s)
+unify_tys = unifyList unify
 
 unifyList :: Outputable a 
          => (TvSubstEnv -> a -> a -> UM TvSubstEnv)
@@ -241,87 +356,84 @@ unifyList unifier subst orig_xs orig_ys
     go subst _      _      = failWith (lengthMisMatch orig_xs orig_ys)
 
 ------------------------------
-uVar :: SrcFlag         -- True, unifying source types, false core types.
-     -> Bool            -- Swapped
+uVar :: Bool            -- Swapped
      -> TvSubstEnv     -- An existing substitution to extend
      -> TyVar           -- Type variable to be unified
      -> Type            -- with this type
      -> UM TvSubstEnv
 
-uVar s swap subst tv1 ty
- = -- check to see whether tv1 is refined
+uVar swap subst tv1 ty
+ = -- Check to see whether tv1 is refined by the substitution
    case (lookupVarEnv subst tv1) of
-     -- yes, call back into unify'
-     Just ty' | swap      -> unify s subst ty ty' 
-              | otherwise -> unify s subst ty' ty
+     -- Yes, call back into unify'
+     Just ty' | swap      -> unify subst ty ty' 
+              | otherwise -> unify subst ty' ty
      -- No, continue
-     Nothing          -> uUnrefined subst tv1 ty
+     Nothing          -> uUnrefined subst tv1 ty ty
 
 
 uUnrefined :: TvSubstEnv          -- An existing substitution to extend
            -> TyVar               -- Type variable to be unified
            -> Type                -- with this type
+           -> Type                -- (de-noted version)
            -> UM TvSubstEnv
 
 -- We know that tv1 isn't refined
-uUnrefined subst tv1 ty2@(TyVarTy tv2)
-  | tv1 == tv2    -- Same, do nothing
+
+uUnrefined subst tv1 ty2 ty2'
+  | Just ty2'' <- tcView ty2'
+  = uUnrefined subst tv1 ty2 ty2''     -- Unwrap synonyms
+               -- This is essential, in case we have
+               --      type Foo a = a
+               -- and then unify a :=: Foo a
+
+uUnrefined subst tv1 ty2 (TyVarTy tv2)
+  | tv1 == tv2         -- Same type variable
   = return subst
 
     -- Check to see whether tv2 is refined
   | Just ty' <- lookupVarEnv subst tv2
-  = uUnrefined subst tv1 ty'
+  = uUnrefined subst tv1 ty' ty'
 
   -- So both are unrefined; next, see if the kinds force the direction
   | k1 == k2   -- Can update either; so check the bind-flags
   = do { b1 <- tvBindFlag tv1
        ; b2 <- tvBindFlag tv2
        ; case (b1,b2) of
-           (DontBindMe, DontBindMe) -> failWith (misMatch ty1 ty2)
-           (DontBindMe, _)          -> bindTv subst tv2 ty1
-           (BindMe, _)              -> bindTv subst tv1 ty2
-           (AvoidMe, BindMe)        -> bindTv subst tv2 ty1
-           (AvoidMe, _)             -> bindTv subst tv1 ty2
-       }
+           (BindMe, _)          -> bind tv1 ty2
 
-  | k1 `isSubKind` k2  -- Must update tv2
-  = do { b2 <- tvBindFlag tv2
-       ; case b2 of
-           DontBindMe -> failWith (misMatch ty1 ty2)
-           other      -> bindTv subst tv2 ty1
-       }
+           (AvoidMe, BindMe)    -> bind tv2 ty1
+           (AvoidMe, _)         -> bind tv1 ty2
 
-  | k2 `isSubKind` k1  -- Must update tv1
-  = do { b1 <- tvBindFlag tv1
-       ; case b1 of
-           DontBindMe -> failWith (misMatch ty1 ty2)
-           other      -> bindTv subst tv1 ty2
+           (WildCard, WildCard) -> return subst
+           (WildCard, Skolem)   -> return subst
+           (WildCard, _)        -> bind tv2 ty1
+
+           (Skolem, WildCard)   -> return subst
+           (Skolem, Skolem)     -> failWith (misMatch ty1 ty2)
+           (Skolem, _)          -> bind tv2 ty1
        }
 
+  | k1 `isSubKind` k2 = bindTv subst tv2 ty1   -- Must update tv2
+  | k2 `isSubKind` k1 = bindTv subst tv1 ty2   -- Must update tv1
+
   | otherwise = failWith (kindMisMatch tv1 ty2)
   where
     ty1 = TyVarTy tv1
     k1 = tyVarKind tv1
     k2 = tyVarKind tv2
+    bind tv ty = return (extendVarEnv subst tv ty)
 
-uUnrefined subst tv1 ty2       -- ty2 is not a type variable
-       -- Do occurs check...
-  | tv1 `elemVarSet` substTvSet subst (tyVarsOfType ty2)
-  = failWith (occursCheck tv1 ty2)
-       -- And a kind check...
-  | k2 `isSubKind` k1
-  = do { b1 <- tvBindFlag tv1
-       ; case b1 of            -- And  check that tv1 is bindable
-           DontBindMe -> failWith (misMatch ty1 ty2)
-           other      -> bindTv subst tv1 ty2
-       }
+uUnrefined subst tv1 ty2 ty2'  -- ty2 is not a type variable
+  | tv1 `elemVarSet` substTvSet subst (tyVarsOfType ty2')
+  = failWith (occursCheck tv1 ty2)     -- Occurs check
+  | not (k2 `isSubKind` k1)
+  = failWith (kindMisMatch tv1 ty2)    -- Kind check
   | otherwise
-  = pprTrace "kind" (ppr tv1 <+> ppr k1 $$ ppr ty2 <+> ppr k2) $
-    failWith (kindMisMatch tv1 ty2)
+  = bindTv subst tv1 ty2               -- Bind tyvar to the synonym if poss
   where
-    ty1 = TyVarTy tv1
     k1 = tyVarKind tv1
-    k2 = typeKind ty2
+    k2 = typeKind ty2'
 
 substTvSet :: TvSubstEnv -> TyVarSet -> TyVarSet
 -- Apply the non-idempotent substitution to a set of type variables,
@@ -333,7 +445,13 @@ substTvSet subst tvs
                Nothing -> unitVarSet tv
                Just ty -> substTvSet subst (tyVarsOfType ty)
 
-bindTv subst tv ty = return (extendVarEnv subst tv ty)
+bindTv subst tv ty     -- ty is not a type variable
+  = do { b <- tvBindFlag tv
+       ; case b of
+           Skolem   -> failWith (misMatch (TyVarTy tv) ty)
+           WildCard -> return subst
+           other    -> return (extendVarEnv subst tv ty)
+       }
 \end{code}
 
 %************************************************************************
@@ -343,15 +461,18 @@ bindTv subst tv ty = return (extendVarEnv subst tv ty)
 %************************************************************************
 
 \begin{code}
-data SrcFlag = Src | Core      -- Unifying at the source level, or core level?
+data BindFlag 
+  = BindMe     -- A regular type variable
+  | AvoidMe    -- Like BindMe but, given the choice, avoid binding it
 
-data BindFlag = BindMe | AvoidMe | DontBindMe
+  | Skolem     -- This type variable is a skolem constant
+               -- Don't bind it; it only matches itself
 
-isCore Core = True
-isCore Src  = False
+  | WildCard   -- This type variable matches anything,
+               -- and does not affect the substitution
 
 newtype UM a = UM { unUM :: (TyVar -> BindFlag)
-                        -> MaybeErr a Message }
+                        -> MaybeErr Message a }
 
 instance Monad UM where
   return a = UM (\tvs -> Succeeded a)
@@ -360,7 +481,7 @@ instance Monad UM where
                           Failed err -> Failed err
                           Succeeded v  -> unUM (k v) tvs)
 
-initUM :: (TyVar -> BindFlag) -> UM a -> MaybeErr a Message
+initUM :: (TyVar -> BindFlag) -> UM a -> MaybeErr Message a
 initUM badtvs um = unUM um badtvs
 
 tvBindFlag :: TyVar -> UM BindFlag
@@ -369,9 +490,19 @@ tvBindFlag tv = UM (\tv_fn -> Succeeded (tv_fn tv))
 failWith :: Message -> UM a
 failWith msg = UM (\tv_fn -> Failed msg)
 
-maybeErrToMaybe :: MaybeErr succ fail -> Maybe succ
+maybeErrToMaybe :: MaybeErr fail succ -> Maybe succ
 maybeErrToMaybe (Succeeded a) = Just a
 maybeErrToMaybe (Failed m)    = Nothing
+
+------------------------------
+repSplitAppTy_maybe :: Type -> Maybe (Type,Type)
+-- Like Type.splitAppTy_maybe, but any coreView stuff is already done
+repSplitAppTy_maybe (FunTy ty1 ty2)   = Just (TyConApp funTyCon [ty1], ty2)
+repSplitAppTy_maybe (AppTy ty1 ty2)   = Just (ty1, ty2)
+repSplitAppTy_maybe (TyConApp tc tys) = case snocView tys of
+                                               Just (tys', ty') -> Just (TyConApp tc tys', ty')
+                                               Nothing          -> Nothing
+repSplitAppTy_maybe other = Nothing
 \end{code}