[project @ 2001-04-14 22:32:14 by qrczak]
[ghc-hetmet.git] / ghc / compiler / types / Unify.lhs
index 68c342c..b284a6f 100644 (file)
@@ -7,52 +7,102 @@ This module contains a unifier and a matcher, both of which
 use an explicit substitution
 
 \begin{code}
-module Unify ( Subst,
-              unifyTysX, unifyTyListsX,
-              matchTy, matchTys
+module Unify ( unifyTysX, unifyTyListsX, unifyExtendTysX,
+              allDistinctTyVars,
+              match, matchTy, matchTys,
   ) where 
 
-import Var     ( GenTyVar, TyVar, tyVarKind )
-import VarEnv
-import VarSet  ( varSetElems )
-import Type    ( GenType(..), funTyCon, typeKind, tyVarsOfType, hasMoreBoxityInfo,
-                 splitAppTy_maybe
+#include "HsVersions.h"
+
+import TypeRep ( Type(..) )     -- friend
+import Type    ( typeKind, tyVarsOfType, splitAppTy_maybe, getTyVar_maybe,
+                  splitUTy, isUTy, deNoteType
+               )
+
+import PprType ()      -- Instances
+                       -- This import isn't strictly necessary, but it makes sure that
+                       -- PprType is below Unify in the hierarchy, which in turn makes
+                       -- fewer modules boot-import PprType
+
+import Var     ( tyVarKind )
+import VarSet
+import VarEnv  ( TyVarSubstEnv, emptySubstEnv, lookupSubstEnv, extendSubstEnv, 
+                 SubstResult(..)
                )
-import Unique  ( Uniquable(..) )
-import Outputable( panic )
-import Util    ( snocView )
+
+import Outputable
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection{Unification wih a explicit substitution}
+\subsection{Unification with an explicit substitution}
+%*                                                                     *
+%************************************************************************
+
+(allDistinctTyVars tys tvs) = True 
+       iff 
+all the types tys are type variables, 
+distinct from each other and from tvs.
+
+This is useful when checking that unification hasn't unified signature
+type variables.  For example, if the type sig is
+       f :: forall a b. a -> b -> b
+we want to check that 'a' and 'b' havn't 
+       (a) been unified with a non-tyvar type
+       (b) been unified with each other (all distinct)
+       (c) been unified with a variable free in the environment
+
+\begin{code}
+allDistinctTyVars :: [Type] -> TyVarSet -> Bool
+
+allDistinctTyVars []       acc
+  = True
+allDistinctTyVars (ty:tys) acc 
+  = case getTyVar_maybe ty of
+       Nothing                       -> False  -- (a)
+       Just tv | tv `elemVarSet` acc -> False  -- (b) or (c)
+               | otherwise           -> allDistinctTyVars tys (acc `extendVarSet` tv)
+\end{code}    
+
+%************************************************************************
+%*                                                                     *
+\subsection{Unification with an explicit substitution}
 %*                                                                     *
 %************************************************************************
 
 Unify types with an explicit substitution and no monad.
+Ignore usage annotations.
 
 \begin{code}
-type Subst flexi_tmpl flexi_result
-   = ([GenTyVar flexi_tmpl],           -- Set of template tyvars
-      TyVarEnv (GenType flexi_result)) -- Not necessarily idempotent
-
-unifyTysX :: [GenTyVar flexi]          -- Template tyvars
-         -> GenType flexi
-          -> GenType flexi
-          -> Maybe (TyVarEnv (GenType flexi))
+type MySubst
+   = (TyVarSet,                -- Set of template tyvars
+      TyVarSubstEnv)   -- Not necessarily idempotent
+
+unifyTysX :: TyVarSet          -- Template tyvars
+         -> Type
+          -> Type
+          -> Maybe TyVarSubstEnv
 unifyTysX tmpl_tyvars ty1 ty2
-  = uTysX ty1 ty2 (\(_,s) -> Just s) (tmpl_tyvars, emptyVarEnv)
-
-unifyTyListsX :: [GenTyVar flexi] -> [GenType flexi] -> [GenType flexi]
-              -> Maybe (TyVarEnv (GenType flexi))
+  = uTysX ty1 ty2 (\(_,s) -> Just s) (tmpl_tyvars, emptySubstEnv)
+
+unifyExtendTysX :: TyVarSet            -- Template tyvars
+               -> TyVarSubstEnv        -- Substitution to start with
+               -> Type
+               -> Type
+               -> Maybe TyVarSubstEnv  -- Extended substitution
+unifyExtendTysX tmpl_tyvars subst ty1 ty2
+  = uTysX ty1 ty2 (\(_,s) -> Just s) (tmpl_tyvars, subst)
+
+unifyTyListsX :: TyVarSet -> [Type] -> [Type]
+              -> Maybe TyVarSubstEnv
 unifyTyListsX tmpl_tyvars tys1 tys2
-  = uTyListsX tys1 tys2 (\(_,s) -> Just s) (tmpl_tyvars, emptyVarEnv)
+  = uTyListsX tys1 tys2 (\(_,s) -> Just s) (tmpl_tyvars, emptySubstEnv)
 
 
-uTysX :: GenType flexi
-      -> GenType flexi
-      -> (Subst flexi flexi -> Maybe result)
-      -> Subst flexi flexi
+uTysX :: Type
+      -> Type
+      -> (MySubst -> Maybe result)
+      -> MySubst
       -> Maybe result
 
 uTysX (NoteTy _ ty1) ty2 k subst = uTysX ty1 ty2 k subst
@@ -63,10 +113,10 @@ uTysX (TyVarTy tyvar1) (TyVarTy tyvar2) k subst
   | tyvar1 == tyvar2
   = k subst
 uTysX (TyVarTy tyvar1) ty2 k subst@(tmpls,_)
-  | tyvar1 `elem` tmpls
+  | tyvar1 `elemVarSet` tmpls
   = uVarX tyvar1 ty2 k subst
 uTysX ty1 (TyVarTy tyvar2) k subst@(tmpls,_)
-  | tyvar2 `elem` tmpls
+  | tyvar2 `elemVarSet` tmpls
   = uVarX tyvar2 ty1 k subst
 
        -- Functions; just check the two parts
@@ -98,6 +148,10 @@ uTysX (ForAllTy _ _) ty2 k subst = panic "Unify.uTysX subst:ForAllTy (1st arg)"
 uTysX ty1 (ForAllTy _ _) k subst = panic "Unify.uTysX subst:ForAllTy (2nd arg)"
 #endif
 
+       -- Ignore usages
+uTysX (UsageTy _ t1) t2 k subst = uTysX t1 t2 k subst
+uTysX t1 (UsageTy _ t2) k subst = uTysX t1 t2 k subst
+
        -- Anything else fails
 uTysX ty1 ty2 k subst = Nothing
 
@@ -110,23 +164,24 @@ uTyListsX tys1         tys2       k subst = Nothing   -- Fail if the lists are diff
 \begin{code}
 -- Invariant: tv1 is a unifiable variable
 uVarX tv1 ty2 k subst@(tmpls, env)
-  = case lookupVarEnv env tv1 of
-      Just ty1 ->    -- Already bound
+  = case lookupSubstEnv env tv1 of
+      Just (DoneTy ty1) ->    -- Already bound
                     uTysX ty1 ty2 k subst
 
       Nothing       -- Not already bound
-              |  typeKind ty2 `hasMoreBoxityInfo` tyVarKind tv1
+              |  typeKind ty2 == tyVarKind tv1
               && occur_check_ok ty2
               ->     -- No kind mismatch nor occur check
-                 k (tmpls, extendVarEnv env tv1 ty2)
+                 UASSERT( not (isUTy ty2) )
+                  k (tmpls, extendSubstEnv env tv1 (DoneTy ty2))
 
               | otherwise -> Nothing   -- Fail if kind mis-match or occur check
   where
     occur_check_ok ty = all occur_check_ok_tv (varSetElems (tyVarsOfType ty))
     occur_check_ok_tv tv | tv1 == tv = False
-                        | otherwise = case lookupVarEnv env tv of
-                                        Nothing -> True
-                                        Just ty -> occur_check_ok ty
+                        | otherwise = case lookupSubstEnv env tv of
+                                        Nothing           -> True
+                                        Just (DoneTy ty)  -> occur_check_ok ty
 \end{code}
 
 
@@ -144,79 +199,105 @@ template, so that it simply returns a mapping of type variables to
 types.  It also fails on nested foralls.
 
 @matchTys@ matches corresponding elements of a list of templates and
-types.
+types.  It and @matchTy@ both ignore usage annotations, unlike the
+main function @match@.
 
 \begin{code}
-matchTy :: [GenTyVar flexi_tmpl]                       -- Template tyvars
-       -> GenType flexi_tmpl                           -- Template
-       -> GenType flexi_result                         -- Proposed instance of template
-       -> Maybe (TyVarEnv (GenType flexi_result))      -- Matching substitution
+matchTy :: TyVarSet                    -- Template tyvars
+       -> Type                         -- Template
+       -> Type                         -- Proposed instance of template
+       -> Maybe TyVarSubstEnv          -- Matching substitution
                                        
 
-matchTys :: [GenTyVar flexi_tmpl]                      -- Template tyvars
-        -> [GenType flexi_tmpl]                        -- Templates
-        -> [GenType flexi_result]                      -- Proposed instance of template
-        -> Maybe (TyVarEnv (GenType flexi_result),     -- Matching substitution
-                  [GenType flexi_result])              -- Left over instance types
+matchTys :: TyVarSet                   -- Template tyvars
+        -> [Type]                      -- Templates
+        -> [Type]                      -- Proposed instance of template
+        -> Maybe (TyVarSubstEnv,               -- Matching substitution
+                  [Type])              -- Left over instance types
 
-matchTy  tmpls ty1  ty2  = match      ty1  ty2  (\(_,env)       -> Just env)
-                                               (tmpls, emptyVarEnv)
+matchTy tmpls ty1 ty2 = match False ty1 ty2 tmpls (\ senv -> Just senv) emptySubstEnv
 
-matchTys tmpls tys1 tys2 = match_list tys1 tys2 (\((_,env),tys) -> Just (env,tys))
-                                               (tmpls, emptyVarEnv)
+matchTys tmpls tys1 tys2 = match_list False tys1 tys2 tmpls 
+                                     (\ (senv,tys) -> Just (senv,tys))
+                                     emptySubstEnv
 \end{code}
 
-@match@ is the main function.
+@match@ is the main function.  It takes a flag indicating whether
+usage annotations are to be respected.
 
 \begin{code}
-match :: GenType flexi_tmpl -> GenType flexi_result                -- Current match pair
-      -> (Subst flexi_tmpl flexi_result -> Maybe result)    -- Continuation
-      -> Subst flexi_tmpl flexi_result                     -- Current substitution
+match :: Bool                                   -- Respect usages?
+      -> Type -> Type                          -- Current match pair
+      -> TyVarSet                              -- Template vars
+      -> (TyVarSubstEnv -> Maybe result)       -- Continuation
+      -> TyVarSubstEnv                         -- Current subst
       -> Maybe result
 
 -- When matching against a type variable, see if the variable
 -- has already been bound.  If so, check that what it's bound to
 -- is the same as ty; if not, bind it and carry on.
 
-match (TyVarTy v) ty k = \  s@(tmpls,env) ->
-                        if v `elem` tmpls then
-                               -- v is a template variable
-                               case lookupVarEnv env v of
-                                 Nothing  -> k (tmpls, extendVarEnv env v ty)
-                                 Just ty' | ty' == ty -> k s      -- Succeeds
-                                          | otherwise -> Nothing  -- Fails
-                         else
-                                     -- v is not a template variable; ty had better match
-                                     -- Can't use (==) because types differ
-                               case ty of
-                                  TyVarTy v' | getUnique v == getUnique v'
-                                             -> k s       -- Success
-                                  other      -> Nothing   -- Failure
-
-match (FunTy arg1 res1)   (FunTy arg2 res2)   k = match arg1 arg2 (match res1 res2 k)
-match (AppTy fun1 arg1)   ty2                k = case splitAppTy_maybe ty2 of
-                                                       Just (fun2,arg2) -> match fun1 fun2 (match arg1 arg2 k)
-                                                       Nothing          -> \ _ -> Nothing      -- Fail
-match (TyConApp tc1 tys1) (TyConApp tc2 tys2) k | tc1 == tc2
-                                               = match_list tys1 tys2 ( \(s,tys2') ->
-                                                 if null tys2' then 
-                                                       k s     -- Succeed
-                                                 else
-                                                       Nothing -- Fail 
-                                                 )
+match uflag (TyVarTy v) ty tmpls k senv
+  | v `elemVarSet` tmpls
+  =     -- v is a template variable
+    case lookupSubstEnv senv v of
+       Nothing -> UASSERT( not (isUTy ty) )
+                   k (extendSubstEnv senv v (DoneTy ty))
+       Just (DoneTy ty')  | ty' == ty         -> k senv   -- Succeeds
+                          | otherwise         -> Nothing  -- Fails
+
+  | otherwise
+  =     -- v is not a template variable; ty had better match
+        -- Can't use (==) because types differ
+    case deNoteType ty of
+        TyVarTy v' | v == v' -> k senv    -- Success
+        other               -> Nothing   -- Failure
+    -- This deNoteType is *required* and cost me much pain.  I guess
+    -- the reason the Note-stripping case is *last* rather than first
+    -- is to preserve type synonyms etc., so I'm not moving it to the
+    -- top; but this means that (without the deNotetype) a type
+    -- variable may not match the pattern (TyVarTy v') as one would
+    -- expect, due to an intervening Note.  KSW 2000-06.
+
+match uflag (FunTy arg1 res1) (FunTy arg2 res2) tmpls k senv
+  = match uflag arg1 arg2 tmpls (match uflag res1 res2 tmpls k) senv
+
+match uflag (AppTy fun1 arg1) ty2 tmpls k senv 
+  = case splitAppTy_maybe ty2 of
+       Just (fun2,arg2) -> match uflag fun1 fun2 tmpls (match uflag arg1 arg2 tmpls k) senv
+       Nothing          -> Nothing     -- Fail
+
+match uflag (TyConApp tc1 tys1) (TyConApp tc2 tys2) tmpls k senv
+  | tc1 == tc2
+  = match_list uflag tys1 tys2 tmpls k' senv
+  where
+    k' (senv', tys2') | null tys2' = k senv'   -- Succeed
+                     | otherwise  = Nothing    -- Fail 
+
+match False (UsageTy _ ty1) ty2 tmpls k senv = match False ty1 ty2 tmpls k senv
+match False ty1 (UsageTy _ ty2) tmpls k senv = match False ty1 ty2 tmpls k senv
+
+match True (UsageTy u1 ty1) (UsageTy u2 ty2) tmpls k senv
+  = match True u1 u2 tmpls (match True ty1 ty2 tmpls k) senv
+match True ty1@(UsageTy _ _) ty2 tmpls k senv
+  = case splitUTy ty2 of { (u,ty2') -> match True ty1 ty2' tmpls k senv }
+match True ty1 ty2@(UsageTy _ _) tmpls k senv
+  = case splitUTy ty1 of { (u,ty1') -> match True ty1' ty2 tmpls k senv }
 
        -- With type synonyms, we have to be careful for the exact
        -- same reasons as in the unifier.  Please see the
        -- considerable commentary there before changing anything
        -- here! (WDP 95/05)
-match (NoteTy _ ty1) ty2           k = match ty1 ty2 k
-match ty1          (NoteTy _ ty2) k = match ty1 ty2 k
+match uflag (NoteTy _ ty1) ty2      tmpls k senv = match uflag ty1 ty2 tmpls k senv
+match uflag ty1             (NoteTy _ ty2) tmpls k senv = match uflag ty1 ty2 tmpls k senv
 
 -- Catch-all fails
-match _ _ _ = \s -> Nothing
+match _ _ _ _ _ _ = Nothing
 
-match_list []         tys2       k = \s -> k (s, tys2)
-match_list (ty1:tys1) []         k = \s -> Nothing     -- Not enough arg tys => failure
-match_list (ty1:tys1) (ty2:tys2) k = match ty1 ty2 (match_list tys1 tys2 k)
+match_list uflag []         tys2       tmpls k senv = k (senv, tys2)
+match_list uflag (ty1:tys1) []         tmpls k senv = Nothing  -- Not enough arg tys => failure
+match_list uflag (ty1:tys1) (ty2:tys2) tmpls k senv
+  = match uflag ty1 ty2 tmpls (match_list uflag tys1 tys2 tmpls k) senv
 \end{code}
 
+