Make various assertions work when !DEBUG
[ghc-hetmet.git] / compiler / typecheck / TcGadt.lhs
index 6c63593..b556e89 100644 (file)
@@ -1,4 +1,5 @@
 %
+% (c) The University of Glasgow 2006
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 
 %************************************************************************
 
 \begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 module TcGadt (
-       Refinement, emptyRefinement, gadtRefine, 
-       refineType, refineResType,
-       dataConCanMatch,
+       Refinement, emptyRefinement, isEmptyRefinement, 
+       gadtRefine, 
+       refineType, refinePred, refineResType,
        tcUnifyTys, BindFlag(..)
   ) where
 
-import HsSyn   ( ExprCoFn(..), idCoercion, isIdCoercion )
-import Coercion        ( Coercion, mkSymCoercion, mkTransCoercion, mkUnsafeCoercion,
-                 mkLeftCoercion, mkRightCoercion, mkCoKind, coercionKindPredTy,
-                 splitCoercionKind, decomposeCo )
-import TcType  ( TvSubst(..), TvSubstEnv, substTy, mkTvSubst, 
-                 substTyVar, zipTopTvSubst, typeKind,
-                 eqKind, isSubKind, repSplitAppTy_maybe,
-                 tcView
-               )
-import Type    ( Type, tyVarsOfType, tyVarsOfTypes, tcEqType, mkTyVarTy )
-import TypeRep ( Type(..), PredType(..) )
-import DataCon ( DataCon, dataConUnivTyVars, dataConEqSpec )
-import Var     ( CoVar, TyVar, tyVarKind )
+#include "HsVersions.h"
+
+import HsSyn
+import Coercion
+import Type
+
+import TypeRep
+import Var
 import VarEnv
 import VarSet
-import ErrUtils                ( Message )
-import Maybes          ( MaybeErr(..), isJust )
-import Control.Monad   ( foldM )
+import ErrUtils
+import Maybes
+import Control.Monad
 import Outputable
-
-#include "HsVersions.h"
+import TcType
+import Unique
+import UniqFM
 \end{code}
 
 
@@ -48,6 +52,8 @@ import Outputable
 
 \begin{code}
 data Refinement = Reft InScopeSet InternalReft 
+
+type InternalReft = TyVarEnv (Coercion, Type)
 -- INVARIANT:   a->(co,ty)   then   co :: (a:=:ty)
 -- Not necessarily idemopotent
 
@@ -59,29 +65,44 @@ instance Outputable Refinement where
 emptyRefinement :: Refinement
 emptyRefinement = (Reft emptyInScopeSet emptyVarEnv)
 
-refineType :: Refinement -> Type -> (ExprCoFn, Type)
+isEmptyRefinement :: Refinement -> Bool
+isEmptyRefinement (Reft _ env) = isEmptyVarEnv env
+
+refineType :: Refinement -> Type -> Maybe (Coercion, Type)
 -- Apply the refinement to the type.
 -- If (refineType r ty) = (co, ty')
 -- Then co :: ty:=:ty'
+-- Nothing => the refinement does nothing to this type
 refineType (Reft in_scope env) ty
   | not (isEmptyVarEnv env),           -- Common case
     any (`elemVarEnv` env) (varSetElems (tyVarsOfType ty))
-  = (ExprCoFn (substTy co_subst ty), substTy tv_subst ty)
+  = Just (substTy co_subst ty, substTy tv_subst ty)
   | otherwise
-  = (idCoercion, ty)   -- The type doesn't mention any refined type variables
+  = Nothing    -- The type doesn't mention any refined type variables
   where
     tv_subst = mkTvSubst in_scope (mapVarEnv snd env)
     co_subst = mkTvSubst in_scope (mapVarEnv fst env)
  
-refineResType :: Refinement -> Type -> (ExprCoFn, Type)
+refinePred :: Refinement -> PredType -> Maybe (Coercion, PredType)
+refinePred (Reft in_scope env) pred
+  | not (isEmptyVarEnv env),           -- Common case
+    any (`elemVarEnv` env) (varSetElems (tyVarsOfPred pred))
+  = Just (mkPredTy (substPred co_subst pred), substPred tv_subst pred)
+  | otherwise
+  = Nothing    -- The type doesn't mention any refined type variables
+  where
+    tv_subst = mkTvSubst in_scope (mapVarEnv snd env)
+    co_subst = mkTvSubst in_scope (mapVarEnv fst env)
+refineResType :: Refinement -> Type -> (HsWrapper, Type)
 -- Like refineType, but returns the 'sym' coercion
 -- If (refineResType r ty) = (co, ty')
 -- Then co :: ty':=:ty
+-- It's convenient to return a HsWrapper here
 refineResType reft ty
   = case refineType reft ty of
-       (ExprCoFn co, ty1) -> (ExprCoFn (mkSymCoercion co), ty1)
-       (id_co,       ty1) -> ASSERT( isIdCoercion id_co )
-                             (idCoercion, ty1)
+       Just (co, ty1) -> (WpCo (mkSymCoercion co), ty1)
+       Nothing        -> (idHsWrapper,             ty)
 \end{code}
 
 
@@ -138,9 +159,11 @@ gadtRefine (Reft in_scope env1)
           ex_tvs co_vars
 -- Precondition: fvs( co_vars ) # env1
 -- That is, the kinds of the co_vars are a
--- fixed point of the  incoming refinement
+-- fixed point of the incoming refinement
 
-  = initUM (tryToBind tv_set) $
+  = ASSERT2( not $ any (`elemVarEnv` env1) (varSetElems $ tyVarsOfTypes $ map tyVarKind co_vars),
+            ppr env1 $$ ppr co_vars $$ ppr (map tyVarKind co_vars) )
+    initUM (tryToBind tv_set) $
     do {       -- Run the unifier, starting with an empty env
        ; env2 <- foldM do_one emptyInternalReft co_vars
 
@@ -148,18 +171,22 @@ gadtRefine (Reft in_scope env1)
                -- non-idempotent substitution
        ; let tmp_env = env1 `plusVarEnv` env2
               out_env = fixTvCoEnv in_scope' tmp_env
-       ; return (Reft in_scope' out_env) }
+       ; WARN( not (null (badReftElts tmp_env)), ppr (badReftElts tmp_env) $$ ppr tmp_env )
+         WARN( not (null (badReftElts out_env)), ppr (badReftElts out_env) $$ ppr out_env )
+         return (Reft in_scope' out_env) }
   where
     tv_set = mkVarSet ex_tvs
     in_scope' = foldr extend in_scope co_vars
+
+       -- For each co_var, add it *and* the tyvars it mentions, to in_scope
     extend co_var in_scope
-       = extendInScopeSetSet (extendInScopeSet in_scope co_var)
-                             (tyVarsOfType (tyVarKind co_var))
+       = extendInScopeSetSet in_scope $
+         extendVarSet (tyVarsOfType (tyVarKind co_var)) co_var
        
     do_one reft co_var = unify reft (TyVarTy co_var) ty1 ty2
        where
           (ty1,ty2) = splitCoercionKind (tyVarKind co_var)
-\end{code} 
+\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -201,17 +228,13 @@ fixTvCoEnv in_scope env
   where
     fixpt         = mapVarEnv step env
 
-    step (co, ty) = (co1, ty')
+    step (co, ty) = case refineType (Reft in_scope fixpt) ty of
+                       Nothing         -> (co,                     ty)
+                       Just (co', ty') -> (mkTransCoercion co co', ty')
       -- Apply fixpt one step:
       -- Use refineType to get a substituted type, ty', and a coercion, co_fn,
       -- which justifies the substitution.  If the coercion is not the identity
       -- then use transitivity with the original coercion
-      where
-        (co_fn, ty') = refineType (Reft in_scope fixpt) ty
-        co1 | ExprCoFn co'' <- co_fn = mkTransCoercion co'' co
-                                         -- This trans looks backwards, but it
-                                         -- works somehow
-            | otherwise              = ASSERT( isIdCoercion co_fn ) co 
 
 -----------------------------
 fixTvSubstEnv :: InScopeSet -> TvSubstEnv -> TvSubstEnv
@@ -221,26 +244,10 @@ fixTvSubstEnv in_scope env
     fixpt = mapVarEnv (substTy (mkTvSubst in_scope fixpt)) env
 
 ----------------------------
-dataConCanMatch :: DataCon -> [Type] -> Bool
--- Returns True iff the data con can match a scrutinee of type (T tys)
---                 where T is the type constructor for the data con
---
--- Instantiate the equations and try to unify them
-dataConCanMatch con tys
-  = isJust (tcUnifyTys (\tv -> BindMe) 
-                      (map (substTyVar subst . fst) eq_spec)
-                      (map snd eq_spec))
-  where
-    dc_tvs  = dataConUnivTyVars con
-    eq_spec = dataConEqSpec con
-    subst   = zipTopTvSubst dc_tvs tys
-
-----------------------------
 tryToBind :: TyVarSet -> TyVar -> BindFlag
 tryToBind tv_set tv | tv `elemVarSet` tv_set = BindMe
                    | otherwise              = AvoidMe
 
-
 \end{code}
 
 
@@ -251,10 +258,18 @@ tryToBind tv_set tv | tv `elemVarSet` tv_set = BindMe
 %************************************************************************
 
 \begin{code}
-type InternalReft = TyVarEnv (Coercion, Type)
-
--- INVARIANT:   a->(co,ty)   then   co :: (a:=:ty)
--- Not necessarily idemopotent
+badReftElts :: InternalReft -> [(Unique, (Coercion,Type))]
+-- Return the BAD elements of the refinement
+-- Should be empty; used in asserions only
+badReftElts env
+  = filter (not . ok) (ufmToList env)
+  where
+    ok :: (Unique, (Coercion, Type)) -> Bool
+    ok (u, (co, ty)) | Just tv <- tcGetTyVar_maybe ty1
+                    = varUnique tv == u && ty `tcEqType` ty2 
+                    | otherwise = False
+       where
+         (ty1,ty2) = coercionKind co
 
 emptyInternalReft :: InternalReft
 emptyInternalReft = emptyVarEnv
@@ -356,11 +371,12 @@ uVar swap subst co tv1 ty
        -> unify subst (mkTransCoercion (mkSymCoercion co') co) ty' ty
 
      -- No, continue
-     Nothing -> uUnrefined subst (if swap then mkSymCoercion co else co)
+     Nothing -> uUnrefined swap subst co
                           tv1 ty ty
 
 
-uUnrefined :: InternalReft        -- An existing substitution to extend
+uUnrefined :: Bool                -- Whether the input is swapped
+           -> InternalReft        -- An existing substitution to extend
           -> Coercion
            -> TyVar               -- Type variable to be unified
            -> Type                -- with this type
@@ -368,65 +384,62 @@ uUnrefined :: InternalReft        -- An existing substitution to extend
            -> UM InternalReft
 
 -- We know that tv1 isn't refined
--- PRE-CONDITION: in the call (uUnrefined r co tv ty ty'), we know that
---     co :: tv:=:ty
+-- PRE-CONDITION: in the call (uUnrefined False r co tv1 ty2 ty2'), we know that
+--     co :: tv1:=:ty2
+-- and if the first argument is True instead, we know
+--      co :: ty2:=:tv1
 
-uUnrefined subst co tv1 ty2 ty2'
+uUnrefined swap subst co tv1 ty2 ty2'
   | Just ty2'' <- tcView ty2'
-  = uUnrefined subst co tv1 ty2 ty2''  -- Unwrap synonyms
+  = uUnrefined swap subst co tv1 ty2 ty2''     -- Unwrap synonyms
                -- This is essential, in case we have
                --      type Foo a = a
                -- and then unify a :=: Foo a
 
-uUnrefined subst co tv1 ty2 (TyVarTy tv2)
+uUnrefined swap subst co tv1 ty2 (TyVarTy tv2)
   | tv1 == tv2         -- Same type variable
   = return subst
 
     -- Check to see whether tv2 is refined
-  | Just (co',ty') <- lookupVarEnv subst tv2
-  = uUnrefined subst (mkTransCoercion co co') tv1 ty' ty'
+  | Just (co',ty') <- lookupVarEnv subst tv2   -- co' :: tv2:=:ty'
+  = uUnrefined False subst (mkTransCoercion (doSwap swap co) co') tv1 ty' ty'
 
   -- So both are unrefined; next, see if the kinds force the direction
   | eqKind k1 k2       -- Can update either; so check the bind-flags
   = do { b1 <- tvBindFlag tv1
        ; b2 <- tvBindFlag tv2
        ; case (b1,b2) of
-           (BindMe, _)          -> bind False tv1 ty2
+           (BindMe, _)          -> bind swap tv1 ty2
 
-           (AvoidMe, BindMe)    -> bind True tv2 ty1
-           (AvoidMe, _)         -> bind False tv1 ty2
+           (AvoidMe, BindMe)    -> bind (not swap) tv2 ty1
+           (AvoidMe, _)         -> bind swap tv1 ty2
 
            (WildCard, WildCard) -> return subst
            (WildCard, Skolem)   -> return subst
-           (WildCard, _)        -> bind True tv2 ty1
+           (WildCard, _)        -> bind (not swap) tv2 ty1
 
            (Skolem, WildCard)   -> return subst
            (Skolem, Skolem)     -> failWith (misMatch ty1 ty2)
-           (Skolem, _)          -> bind True tv2 ty1
+           (Skolem, _)          -> bind (not swap) tv2 ty1
        }
 
-  | k1 `isSubKind` k2 = bindTv subst (mkSymCoercion co) tv2 ty1        -- Must update tv2
-  | k2 `isSubKind` k1 = bindTv subst co tv1 ty2        -- Must update tv1
+  | k1 `isSubKind` k2 = bindTv (not swap) subst co tv2 ty1  -- Must update tv2
+  | k2 `isSubKind` k1 = bindTv swap subst co tv1 ty2       -- Must update tv1
 
   | otherwise = failWith (kindMisMatch tv1 ty2)
   where
     ty1 = TyVarTy tv1
     k1 = tyVarKind tv1
     k2 = tyVarKind tv2
-    bind swap tv ty = 
-        ASSERT2( (coercionKindPredTy co1 `tcEqType` mkCoKind (mkTyVarTy tv) ty)
-               , (text "Refinement invariant failure: co = " <+> ppr co  <+> ppr (coercionKindPredTy co) $$ text "subst = " <+> ppr tv <+> ppr (mkCoKind (mkTyVarTy tv) ty)))
-        return (extendVarEnv subst tv (co1,ty))
-      where
-        co1 = if swap then mkSymCoercion co else co
-
-uUnrefined subst co tv1 ty2 ty2'       -- ty2 is not a type variable
+    bind swap tv ty = extendReft swap subst tv co ty
+
+uUnrefined swap subst co 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 co tv1 ty2            -- Bind tyvar to the synonym if poss
+  = bindTv swap subst co tv1 ty2               -- Bind tyvar to the synonym if poss
   where
     k1 = tyVarKind tv1
     k2 = typeKind ty2'
@@ -441,15 +454,30 @@ substTvSet subst tvs
                Nothing     -> unitVarSet tv
                Just (_,ty) -> substTvSet subst (tyVarsOfType ty)
 
-bindTv subst co tv ty  -- ty is not a type variable
-  = ASSERT2( (coercionKindPredTy co `tcEqType` mkCoKind (mkTyVarTy tv) ty), 
-          (text "Refinement invariant failure: co = " <+> ppr co  <+> ppr (coercionKindPredTy co) $$ text "subst = " <+> ppr tv <+> ppr (mkCoKind (mkTyVarTy tv) ty))  )
-    do  { b <- tvBindFlag tv
+bindTv swap subst co 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 (co,ty))
+           other    -> extendReft swap subst tv co ty
        }
+
+doSwap :: Bool -> Coercion -> Coercion
+doSwap swap co = if swap then mkSymCoercion co else co
+
+extendReft :: Bool 
+           -> InternalReft 
+           -> TyVar 
+           -> Coercion 
+           -> Type 
+           -> UM InternalReft
+extendReft swap subst tv  co ty
+  = ASSERT2( (coercionKindPredTy co1 `tcEqType` mkCoKind (mkTyVarTy tv) ty), 
+          (text "Refinement invariant failure: co = " <+> ppr co1  <+> ppr (coercionKindPredTy co1) $$ text "subst = " <+> ppr tv <+> ppr (mkCoKind (mkTyVarTy tv) ty)) )
+    return (extendVarEnv subst tv (co1, ty))
+  where
+    co1 = doSwap swap co
+
 \end{code}
 
 %************************************************************************
@@ -521,4 +549,4 @@ kindMisMatch tv1 t2
 occursCheck tv ty
   = hang (ptext SLIT("Can't construct the infinite type"))
        2 (ppr tv <+> equals <+> ppr ty)
-\end{code}
\ No newline at end of file
+\end{code}