[project @ 2005-10-14 11:22:41 by simonpj]
[ghc-hetmet.git] / ghc / compiler / types / Unify.lhs
index be00045..e6a0878 100644 (file)
@@ -1,13 +1,13 @@
 \begin{code}
 module Unify ( 
        -- Matching and unification
-       tcMatchTys, tcMatchTyX, tcMatchPreds, MatchEnv(..), 
+       tcMatchTys, tcMatchTyX, ruleMatchTyX, tcMatchPreds, MatchEnv(..), 
 
        tcUnifyTys, 
 
        gadtRefineTys, BindFlag(..),
 
-       coreRefineTys,
+       coreRefineTys, TypeRefinement,
 
        -- Re-export
        MaybeErr(..)
@@ -19,9 +19,10 @@ import Var           ( Var, TyVar, tyVarKind )
 import VarEnv
 import VarSet
 import Kind            ( isSubKind )
-import Type            ( typeKind, tyVarsOfType, tyVarsOfTypes, tyVarsOfTheta, 
+import Type            ( typeKind, tyVarsOfType, tyVarsOfTypes, tyVarsOfTheta, mkTyVarTys,
                          TvSubstEnv, emptyTvSubstEnv, TvSubst(..), substTy, tcEqTypeX )
 import TypeRep          ( Type(..), PredType(..), funTyCon )
+import DataCon                 ( DataCon, dataConInstResTy )
 import Util            ( snocView )
 import ErrUtils                ( Message )
 import Outputable
@@ -80,6 +81,19 @@ tcMatchTys tmpls tys1 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}
+
 tcMatchPreds
        :: [TyVar]                      -- Bind these
        -> [PredType] -> [PredType]
@@ -91,13 +105,13 @@ tcMatchPreds tmpls ps1 ps2
     in_scope_tyvars = mkInScopeSet (tyVarsOfTheta ps1 `unionVarSet` tyVarsOfTheta ps2)
 
 -- This one is called from the expression matcher, which already has a MatchEnv in hand
-tcMatchTyX :: MatchEnv 
+ruleMatchTyX :: MatchEnv 
         -> TvSubstEnv          -- Substitution to extend
         -> Type                -- Template
         -> Type                -- Target
         -> Maybe TvSubstEnv
 
-tcMatchTyX menv subst ty1 ty2 = match menv subst ty1 ty2       -- Rename for export
+ruleMatchTyX menv subst ty1 ty2 = match menv subst ty1 ty2     -- Rename for export
 \end{code}
 
 Now the internals of matching
@@ -207,23 +221,36 @@ tcUnifyTys bind_fn tys1 tys2
     tvs2 = tyVarsOfTypes tys2
 
 ----------------------------
-coreRefineTys :: InScopeSet    -- Superset of free vars of either type
-             -> [TyVar]        -- Try to unify these
-             -> Type           -- Both types should be a fixed point 
-             -> Type           --   of the incoming substitution
-             -> 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 in_scope ex_tvs ty1 ty2
-  = maybeErrToMaybe $ initUM (tryToBind (mkVarSet ex_tvs)) $
+coreRefineTys :: InScopeSet            -- Superset of free vars of either type
+             -> 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 in_scope con tvs scrut_ty
+  = maybeErrToMaybe $ initUM (tryToBind tv_set) $
     do {       -- Run the unifier, starting with an empty env
-       ; subst_env <- unify emptyTvSubstEnv ty1 ty2
+       ; subst_env <- unify emptyTvSubstEnv pat_res_ty scrut_ty
 
        -- Find the fixed point of the resulting non-idempotent substitution
        ; let subst           = TvSubst in_scope subst_env_fixpt
              subst_env_fixpt = mapVarEnv (substTy subst) subst_env
-       ; return subst_env_fixpt }
+               
+       ; 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
+    
 
 ----------------------------
 gadtRefineTys
@@ -330,22 +357,30 @@ uVar swap subst tv1 ty
      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 (NoteTy _ 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
@@ -376,16 +411,16 @@ uUnrefined subst tv1 ty2@(TyVarTy tv2)
     k2 = tyVarKind tv2
     bind tv ty = return (extendVarEnv subst tv ty)
 
-uUnrefined subst tv1 ty2       -- ty2 is not a type variable
-  | tv1 `elemVarSet` substTvSet subst (tyVarsOfType 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
-  = bindTv subst tv1 ty2
+  = bindTv subst tv1 ty2               -- Bind tyvar to the synonym if poss
   where
     k1 = tyVarKind tv1
-    k2 = typeKind ty2
+    k2 = typeKind ty2'
 
 substTvSet :: TvSubstEnv -> TyVarSet -> TyVarSet
 -- Apply the non-idempotent substitution to a set of type variables,