Equality constraint solver is now externally pure
authorManuel M T Chakravarty <chak@cse.unsw.edu.au>
Mon, 27 Apr 2009 14:03:16 +0000 (14:03 +0000)
committerManuel M T Chakravarty <chak@cse.unsw.edu.au>
Mon, 27 Apr 2009 14:03:16 +0000 (14:03 +0000)
- This patch changes the equality constraint solver such that it does not
  instantiate any type variables that occur in the constraints that are to be
  solved (or in the environment).  Instead, it returns a bag of type bindings.
- If these type bindings (together with the other results of the solver) are
  discarded, solver invocation has no effect (outside the solver) and can be
  repeated (that's imported for TcSimplifyRestricted).
- For the type bindings to take effect, the caller of the solver needs to
  execute them.
- The solver will still instantiate type variables thet were created during
  solving (e.g., skolem flexibles used during type flattening).

  See also http://hackage.haskell.org/trac/ghc/wiki/TypeFunctionsSolving

compiler/coreSyn/CoreFVs.lhs
compiler/typecheck/Inst.lhs
compiler/typecheck/TcMType.lhs
compiler/typecheck/TcRnMonad.lhs
compiler/typecheck/TcRnTypes.lhs
compiler/typecheck/TcSimplify.lhs
compiler/typecheck/TcTyFuns.lhs
compiler/typecheck/TcType.lhs

index d2d1383..e2eb3a2 100644 (file)
@@ -25,7 +25,7 @@ module CoreFVs (
        exprFreeNames, exprsFreeNames,
 
         -- * Free variables of Rules, Vars and Ids
-       idRuleVars, idFreeVars, varTypeTyVars, 
+       idRuleVars, idFreeVars, varTypeTyVars, varTypeTcTyVars, 
        ruleRhsFreeVars, rulesFreeVars,
        ruleLhsFreeNames, ruleLhsFreeIds, 
 
@@ -370,6 +370,13 @@ varTypeTyVars var
   | isLocalId var || isCoVar var = tyVarsOfType (idType var)
   | otherwise = emptyVarSet    -- Global Ids and non-coercion TyVars
 
+varTypeTcTyVars :: Var -> TyVarSet
+-- Find the type variables free in the type of the variable
+-- Remember, coercion variables can mention type variables...
+varTypeTcTyVars var
+  | isLocalId var || isCoVar var = tcTyVarsOfType (idType var)
+  | otherwise = emptyVarSet    -- Global Ids and non-coercion TyVars
+
 idFreeVars :: Id -> VarSet
 idFreeVars id = ASSERT( isId id) idRuleVars id `unionVarSet` varTypeTyVars id
 
index cada794..2e08113 100644 (file)
@@ -22,9 +22,9 @@ module Inst (
        tcInstClassOp, 
        tcSyntaxName, isHsVar,
 
-       tyVarsOfInst, tyVarsOfInsts, tyVarsOfLIE, 
-       ipNamesOfInst, ipNamesOfInsts, fdPredsOfInst, fdPredsOfInsts,
-       growInstsTyVars, getDictClassTys, dictPred,
+       tyVarsOfInst, tyVarsOfInsts, tyVarsOfLIE, tcTyVarsOfInst,
+       tcTyVarsOfInsts, ipNamesOfInst, ipNamesOfInsts, fdPredsOfInst,
+       fdPredsOfInsts, growInstsTyVars, getDictClassTys, dictPred,
 
        lookupSimpleInst, LookupInstResult(..), 
        tcExtendLocalInstEnv, tcGetInstEnvs, getOverlapFlag,
@@ -193,22 +193,53 @@ ipNamesOfInst (Method {tci_theta = theta})   = [ipNameName n | IParam n _ <- the
 ipNamesOfInst _                              = []
 
 ---------------------------------
-tyVarsOfInst :: Inst -> TcTyVarSet
+
+-- |All free type variables (not including the coercion variables of
+-- equalities)
+--
+tyVarsOfInst :: Inst -> TyVarSet
 tyVarsOfInst (LitInst {tci_ty = ty})  = tyVarsOfType  ty
 tyVarsOfInst (Dict {tci_pred = pred}) = tyVarsOfPred pred
-tyVarsOfInst (Method {tci_oid = id, tci_tys = tys}) = tyVarsOfTypes tys `unionVarSet` varTypeTyVars id
-                                -- The id might have free type variables; in the case of
-                                -- locally-overloaded class methods, for example
-tyVarsOfInst (ImplicInst {tci_tyvars = tvs, tci_given = givens, tci_wanted = wanteds})
+tyVarsOfInst (Method {tci_oid = id, tci_tys = tys}) 
+  = tyVarsOfTypes tys `unionVarSet` varTypeTyVars id
+    -- The id might have free type variables; in the case of
+    -- locally-overloaded class methods, for example
+tyVarsOfInst (ImplicInst {tci_tyvars = tvs, tci_given = givens, 
+                          tci_wanted = wanteds})
   = (tyVarsOfInsts givens `unionVarSet` tyVarsOfInsts wanteds) 
     `minusVarSet` mkVarSet tvs
     `unionVarSet` unionVarSets (map varTypeTyVars tvs)
                -- Remember the free tyvars of a coercion
-tyVarsOfInst (EqInst {tci_left = ty1, tci_right = ty2}) = tyVarsOfType ty1 `unionVarSet` tyVarsOfType ty2
+tyVarsOfInst (EqInst {tci_left = ty1, tci_right = ty2}) 
+  = tyVarsOfType ty1 `unionVarSet` tyVarsOfType ty2
+
+-- |All free meta type variables *including* the coercion variables of
+-- equalities
+--
+tcTyVarsOfInst :: Inst -> TyVarSet
+tcTyVarsOfInst (LitInst {tci_ty = ty})  = tcTyVarsOfType  ty
+tcTyVarsOfInst (Dict {tci_pred = pred}) = tcTyVarsOfPred pred
+tcTyVarsOfInst (Method {tci_oid = id, tci_tys = tys}) 
+  = tcTyVarsOfTypes tys `unionVarSet` varTypeTcTyVars id
+    -- The id might have free type variables; in the case of
+    -- locally-overloaded class methods, for example
+tcTyVarsOfInst (ImplicInst {tci_tyvars = tvs, tci_given = givens, 
+                            tci_wanted = wanteds})
+  = (tcTyVarsOfInsts givens `unionVarSet` tcTyVarsOfInsts wanteds) 
+    `minusVarSet` mkVarSet tvs
+    `unionVarSet` unionVarSets (map varTypeTcTyVars tvs)
+               -- Remember the free tyvars of a coercion
+tcTyVarsOfInst (EqInst {tci_co = co, tci_left = ty1, tci_right = ty2}) 
+  = either unitVarSet tcTyVarsOfType co `unionVarSet`   -- include covars
+    tcTyVarsOfType ty1 `unionVarSet` tcTyVarsOfType ty2
 
-tyVarsOfInsts :: [Inst] -> VarSet
+tyVarsOfInsts :: [Inst] -> TyVarSet
 tyVarsOfInsts insts = foldr (unionVarSet . tyVarsOfInst) emptyVarSet insts
-tyVarsOfLIE :: Bag Inst -> VarSet
+
+tcTyVarsOfInsts :: [Inst] -> TcTyVarSet
+tcTyVarsOfInsts insts = foldr (unionVarSet . tcTyVarsOfInst) emptyVarSet insts
+
+tyVarsOfLIE :: Bag Inst -> TyVarSet
 tyVarsOfLIE   lie   = tyVarsOfInsts (lieToList lie)
 
 
@@ -1029,7 +1060,7 @@ depending on whether a EqInstCo is for a wanted or local equality:
 --
 mkIdEqInstCo :: EqInstCo -> Type -> TcM ()
 mkIdEqInstCo (Left cotv) t
-  = writeMetaTyVar cotv t
+  = bindMetaTyVar cotv t
 mkIdEqInstCo (Right _) _
   = return ()
 
@@ -1038,7 +1069,7 @@ mkIdEqInstCo (Right _) _
 mkSymEqInstCo :: EqInstCo -> (Type, Type) -> TcM EqInstCo
 mkSymEqInstCo (Left cotv) (ty1, ty2)
   = do { cotv' <- newMetaCoVar ty1 ty2
-       ; writeMetaTyVar cotv (mkSymCoercion (TyVarTy cotv'))
+       ; bindMetaTyVar cotv (mkSymCoercion (TyVarTy cotv'))
        ; return $ Left cotv'
        }
 mkSymEqInstCo (Right co) _ 
@@ -1049,7 +1080,7 @@ mkSymEqInstCo (Right co) _
 mkLeftTransEqInstCo :: EqInstCo -> Coercion -> (Type, Type) -> TcM EqInstCo
 mkLeftTransEqInstCo (Left cotv) given_co (ty1, ty2)
   = do { cotv' <- newMetaCoVar ty1 ty2
-       ; writeMetaTyVar cotv (TyVarTy cotv' `mkTransCoercion` given_co)
+       ; bindMetaTyVar cotv (TyVarTy cotv' `mkTransCoercion` given_co)
        ; return $ Left cotv'
        }
 mkLeftTransEqInstCo (Right co) given_co _ 
@@ -1060,7 +1091,7 @@ mkLeftTransEqInstCo (Right co) given_co _
 mkRightTransEqInstCo :: EqInstCo -> Coercion -> (Type, Type) -> TcM EqInstCo
 mkRightTransEqInstCo (Left cotv) given_co (ty1, ty2)
   = do { cotv' <- newMetaCoVar ty1 ty2
-       ; writeMetaTyVar cotv (given_co `mkTransCoercion` TyVarTy cotv')
+       ; bindMetaTyVar cotv (given_co `mkTransCoercion` TyVarTy cotv')
        ; return $ Left cotv'
        }
 mkRightTransEqInstCo (Right co) given_co _ 
@@ -1073,7 +1104,7 @@ mkAppEqInstCo :: EqInstCo -> (Type, Type) -> (Type, Type)
 mkAppEqInstCo (Left cotv) (ty1_l, ty2_l) (ty1_r, ty2_r)
   = do { cotv_l <- newMetaCoVar ty1_l ty2_l
        ; cotv_r <- newMetaCoVar ty1_r ty2_r
-       ; writeMetaTyVar cotv (mkAppCoercion (TyVarTy cotv_l) (TyVarTy cotv_r))
+       ; bindMetaTyVar cotv (mkAppCoercion (TyVarTy cotv_l) (TyVarTy cotv_r))
        ; return (Left cotv_l, Left cotv_r)
        }
 mkAppEqInstCo (Right co) _ _
@@ -1084,7 +1115,7 @@ mkAppEqInstCo (Right co) _ _
 mkTyConEqInstCo :: EqInstCo -> TyCon -> [(Type, Type)] -> TcM ([EqInstCo])
 mkTyConEqInstCo (Left cotv) con ty12s
   = do { cotvs <- mapM (uncurry newMetaCoVar) ty12s
-       ; writeMetaTyVar cotv (mkTyConCoercion con (mkTyVarTys cotvs))
+       ; bindMetaTyVar cotv (mkTyConCoercion con (mkTyVarTys cotvs))
        ; return (map Left cotvs)
        }
 mkTyConEqInstCo (Right co) _ args
@@ -1102,7 +1133,7 @@ mkFunEqInstCo :: EqInstCo -> (Type, Type) -> (Type, Type)
 mkFunEqInstCo (Left cotv) (ty1_l, ty2_l) (ty1_r, ty2_r)
   = do { cotv_l <- newMetaCoVar ty1_l ty2_l
        ; cotv_r <- newMetaCoVar ty1_r ty2_r
-       ; writeMetaTyVar cotv (mkFunCoercion (TyVarTy cotv_l) (TyVarTy cotv_r))
+       ; bindMetaTyVar cotv (mkFunCoercion (TyVarTy cotv_l) (TyVarTy cotv_r))
        ; return (Left cotv_l, Left cotv_r)
        }
 mkFunEqInstCo (Right co) _ _
index 9a17b0f..525ba0d 100644 (file)
@@ -35,14 +35,14 @@ module TcMType (
   tcInstTyVar, tcInstType, tcInstTyVars, tcInstBoxyTyVar,
   tcInstSigType,
   tcInstSkolTyVars, tcInstSkolType, 
-  tcSkolSigType, tcSkolSigTyVars, occurCheckErr,
+  tcSkolSigType, tcSkolSigTyVars, occurCheckErr, execTcTyVarBinds,
 
   --------------------------------
   -- Checking type validity
   Rank, UserTypeCtxt(..), checkValidType, checkValidMonoType,
   SourceTyCtxt(..), checkValidTheta, checkFreeness,
   checkValidInstHead, checkValidInstance, 
-  checkInstTermination, checkValidTypeInst, checkTyFamFreeness,
+  checkInstTermination, checkValidTypeInst, checkTyFamFreeness, checkKinds,
   checkUpdateMeta, updateMeta, checkTauTvUpdate, fillBoxWithTau, unifyKindCtxt,
   unifyKindMisMatch, validDerivPred, arityErr, notMonoType, notMonoArgs,
   growPredTyVars, growTyVars, growThetaTyVars,
@@ -78,6 +78,7 @@ import VarSet
 import ErrUtils
 import DynFlags
 import Util
+import Bag
 import Maybes
 import ListSetOps
 import UniqSupply
@@ -337,6 +338,27 @@ Rather, we should bind t to () (= non_var_ty2).
 
 --------------
 
+Execute a bag of type variable bindings.
+
+\begin{code}
+execTcTyVarBinds :: TcTyVarBinds -> TcM ()
+execTcTyVarBinds = mapM_ execTcTyVarBind . bagToList
+  where
+    execTcTyVarBind (TcTyVarBind tv ty)
+      = do { ASSERTM2( do { details <- readMetaTyVar tv
+                          ; return (isFlexi details) }, ppr tv )
+           ; ty' <- if isCoVar tv 
+                    then return ty 
+                    else do { maybe_ty <- checkTauTvUpdate tv ty
+                            ; case maybe_ty of
+                                Nothing -> pprPanic "TcRnMonad.execTcTyBind"
+                                             (ppr tv <+> text ":=" <+> ppr ty)
+                                Just ty' -> return ty'
+                            }
+           ; writeMetaTyVar tv ty'
+           }
+\end{code}
+
 Error mesages in case of kind mismatch.
 
 \begin{code}
@@ -522,19 +544,17 @@ writeMetaTyVar tyvar ty
     return ()
   | otherwise
   = ASSERT( isMetaTyVar tyvar )
-    -- TOM: It should also work for coercions
-    -- ASSERT2( k2 `isSubKind` k1, (ppr tyvar <+> ppr k1) $$ (ppr ty <+> ppr k2) )
+    ASSERT2( isCoVar tyvar || typeKind ty `isSubKind` tyVarKind tyvar, 
+             (ppr tyvar <+> ppr (tyVarKind tyvar)) 
+             $$ (ppr ty <+> ppr (typeKind ty)) )
     do { if debugIsOn then do { details <- readMetaTyVar tyvar; 
+-- FIXME                              ; ASSERT2( not (isFlexi details), ppr tyvar )
                               ; WARN( not (isFlexi details), ppr tyvar )
                                 return () }
                        else return () 
-               -- Temporarily make this a warning, until we fix Trac #2999
 
        ; traceTc (text "writeMetaTyVar" <+> ppr tyvar <+> text ":=" <+> ppr ty)
        ; writeMutVar (metaTvRef tyvar) (Indirect ty) }
-  where
-    _k1 = tyVarKind tyvar
-    _k2 = typeKind ty
 \end{code}
 
 
index 6df6e28..ca11d17 100644 (file)
@@ -9,6 +9,8 @@ module TcRnMonad(
        module IOEnv
   ) where
 
+#include "HsVersions.h"
+
 import TcRnTypes       -- Re-export all
 import IOEnv           -- Re-export all
 
@@ -123,7 +125,9 @@ initTc hsc_env hsc_src keep_rn_syntax mod do_this
                tcl_arrow_ctxt = NoArrowCtxt,
                tcl_env        = emptyNameEnv,
                tcl_tyvars     = tvs_var,
-               tcl_lie        = panic "initTc:LIE"     -- LIE only valid inside a getLIE
+               tcl_lie        = panic "initTc:LIE", -- only valid inside getLIE
+               tcl_tybinds    = panic "initTc:tybinds" 
+                                               -- only valid inside a getTyBinds
             } ;
        } ;
    
@@ -823,7 +827,7 @@ debugTc thing
  | otherwise = return ()
 \end{code}
 
- %************************************************************************
+%************************************************************************
 %*                                                                     *
             Type constraints (the so-called LIE)
 %*                                                                     *
@@ -881,6 +885,44 @@ setLclTypeEnv lcl_env thing_inside
 
 %************************************************************************
 %*                                                                     *
+            Meta type variable bindings
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+getTcTyVarBindsVar :: TcM (TcRef TcTyVarBinds)
+getTcTyVarBindsVar = do { env <- getLclEnv; return (tcl_tybinds env) }
+
+getTcTyVarBinds :: TcM a -> TcM (a, TcTyVarBinds)
+getTcTyVarBinds thing_inside
+  = do { tybinds_var <- newMutVar emptyBag
+       ; res <- updLclEnv (\ env -> env { tcl_tybinds = tybinds_var }) 
+                         thing_inside
+       ; tybinds <- readMutVar tybinds_var
+       ; return (res, tybinds) 
+       }
+
+bindMetaTyVar :: TcTyVar -> TcType -> TcM ()
+bindMetaTyVar tv ty
+  = do { ASSERTM2( do { details <- readMutVar (metaTvRef tv)
+                      ; return (isFlexi details) }, ppr tv )
+       ; tybinds_var <- getTcTyVarBindsVar
+       ; tybinds <- readMutVar tybinds_var
+       ; writeMutVar tybinds_var (tybinds `snocBag` TcTyVarBind tv ty) 
+       }
+
+getTcTyVarBindsRelation :: TcM [(TcTyVar, TcTyVarSet)]
+getTcTyVarBindsRelation
+  = do { tybinds_var <- getTcTyVarBindsVar
+       ; tybinds <- readMutVar tybinds_var
+       ; return $ map freeTvs (bagToList tybinds)
+       }
+  where
+    freeTvs (TcTyVarBind tv ty) = (tv, tyVarsOfType ty)
+\end{code}
+
+%************************************************************************
+%*                                                                     *
             Template Haskell context
 %*                                                                     *
 %************************************************************************
index 28bfd8e..cbc0fe4 100644 (file)
@@ -34,7 +34,7 @@ module TcRnTypes(
        plusLIEs, mkLIE, isEmptyLIE, lieToList, listToLIE,
 
        -- Misc other types
-       TcId, TcIdSet, TcDictBinds,
+       TcId, TcIdSet, TcDictBinds, TcTyVarBind(..), TcTyVarBinds
        
   ) where
 
@@ -98,6 +98,18 @@ type RnM  a = TcRn a         -- Historical
 type TcM  a = TcRn a           -- Historical
 \end{code}
 
+Representation of type bindings to uninstantiated meta variables used during
+constraint solving.
+
+\begin{code}
+data TcTyVarBind = TcTyVarBind TcTyVar TcType
+
+type TcTyVarBinds = Bag TcTyVarBind
+
+instance Outputable TcTyVarBind where
+  ppr (TcTyVarBind tv ty) = ppr tv <+> text ":=" <+> ppr ty
+\end{code}
+
 
 %************************************************************************
 %*                                                                     *
@@ -343,15 +355,20 @@ data TcLclEnv             -- Changes as we move inside an expression
                -- We still need the unsullied global name env so that
                --   we can look up record field names
 
-       tcl_env  :: NameEnv TcTyThing,  -- The local type environment: Ids and TyVars
-                                       -- defined in this module
+       tcl_env  :: NameEnv TcTyThing,  -- The local type environment: Ids and
+                                       -- TyVars defined in this module
                                        
        tcl_tyvars :: TcRef TcTyVarSet, -- The "global tyvars"
                        -- Namely, the in-scope TyVars bound in tcl_env, 
-                       -- plus the tyvars mentioned in the types of Ids bound in tcl_lenv
-                       -- Why mutable? see notes with tcGetGlobalTyVars
+                       -- plus the tyvars mentioned in the types of Ids bound
+                       -- in tcl_lenv. 
+                        -- Why mutable? see notes with tcGetGlobalTyVars
+
+       tcl_lie   :: TcRef LIE,         -- Place to accumulate type constraints
 
-       tcl_lie   :: TcRef LIE          -- Place to accumulate type constraints
+        tcl_tybinds :: TcRef TcTyVarBinds -- Meta and coercion type variable
+                                          -- bindings accumulated during
+                                          -- constraint solving
     }
 
 
index 4cf93e8..cd3da49 100644 (file)
@@ -1115,7 +1115,9 @@ checkLoop env wanteds
                 ; env'     <- zonkRedEnv env
                ; wanteds' <- zonkInsts  wanteds
        
-               ; (improved, binds, irreds) <- reduceContext env' wanteds'
+               ; (improved, tybinds, binds, irreds) 
+                    <- reduceContext env' wanteds'
+                ; execTcTyVarBinds tybinds
 
                ; if null irreds || not improved then
                    return (irreds, binds)
@@ -1450,7 +1452,8 @@ tcSimplifyRestricted doc top_lvl bndrs tau_tvs wanteds
        -- HOWEVER, some unification may take place, if we instantiate
        --          a method Inst with an equality constraint
        ; let env = mkNoImproveRedEnv doc (\_ -> ReduceMe)
-       ; (_imp, _binds, constrained_dicts) <- reduceContext env wanteds_z
+       ; (_imp, _tybinds, _binds, constrained_dicts) 
+            <- reduceContext env wanteds_z
 
        -- Next, figure out the tyvars we will quantify over
        ; tau_tvs' <- zonkTcTyVarsAndFV (varSetElems tau_tvs)
@@ -1478,13 +1481,6 @@ tcSimplifyRestricted doc top_lvl bndrs tau_tvs wanteds
                ppr _binds,
                ppr constrained_tvs', ppr tau_tvs', ppr qtvs ])
 
-          -- Zonk wanteds again!  The first call to reduceContext may have
-          -- instantiated some variables. 
-          -- FIXME: If red_improve would work, we could propagate that into
-          --        the equality solver, too, to prevent instantating any
-          --        variables.
-       ; wanteds_zz <- zonkInsts wanteds_z
-
        -- The first step may have squashed more methods than
        -- necessary, so try again, this time more gently, knowing the exact
        -- set of type variables to quantify over.
@@ -1506,7 +1502,8 @@ tcSimplifyRestricted doc top_lvl bndrs tau_tvs wanteds
                           (is_nested_group || isDict inst) = Stop
                          | otherwise                       = ReduceMe 
              env = mkNoImproveRedEnv doc try_me
-       ; (_imp, binds, irreds) <- reduceContext env wanteds_zz
+       ; (_imp, tybinds, binds, irreds) <- reduceContext env wanteds_z
+        ; execTcTyVarBinds tybinds
 
        -- See "Notes on implicit parameters, Question 4: top level"
        ; ASSERT( all (isFreeWrtTyVars qtvs) irreds )   -- None should be captured
@@ -1683,7 +1680,8 @@ tcSimplifyIPs given_ips wanteds
                -- Unusually for checking, we *must* zonk the given_ips
 
        ; let env = mkRedEnv doc try_me given_ips'
-       ; (improved, binds, irreds) <- reduceContext env wanteds'
+       ; (improved, tybinds, binds, irreds) <- reduceContext env wanteds'
+        ; execTcTyVarBinds tybinds
 
        ; if null irreds || not improved then 
                ASSERT( all is_free irreds )
@@ -1872,6 +1870,7 @@ discharge with the explicit instance.
 reduceContext :: RedEnv
              -> [Inst]                 -- Wanted
              -> TcM (ImprovementDone,
+                      TcTyVarBinds,     -- Type variable bindings
                      TcDictBinds,      -- Dictionary bindings
                      [Inst])           -- Irreducible
 
@@ -1898,10 +1897,11 @@ reduceContext env wanteds0
               givens  = red_givens env
         ; (givens', 
            wanteds', 
-           normalise_binds,
-           eq_improved)     <- tcReduceEqs givens wanteds
+           tybinds,
+           normalise_binds) <- tcReduceEqs givens wanteds
        ; traceTc $ text "reduceContext: tcReduceEqs result" <+> vcat
-                     [ppr givens', ppr wanteds', ppr normalise_binds]
+                     [ppr givens', ppr wanteds', ppr tybinds, 
+                       ppr normalise_binds]
 
           -- Build the Avail mapping from "given_dicts"
        ; (init_state, _) <- getLIE $ do 
@@ -1941,7 +1941,7 @@ reduceContext env wanteds0
           -- Collect all irreducible instances, and determine whether we should
           -- go round again.  We do so in either of two cases:
           -- (1) If dictionary reduction or equality solving led to
-          --     improvement (i.e., instantiated type variables).
+          --     improvement (i.e., bindings for type variables).
           -- (2) If we reduced dictionaries (i.e., got dictionary bindings),
           --     they may have exposed further opportunities to normalise
           --     family applications.  See Note [Dictionary Improvement]
@@ -1954,6 +1954,7 @@ reduceContext env wanteds0
 
        ; let all_irreds       = dict_irreds ++ implic_irreds ++ extra_eqs
              avails_improved  = availsImproved avails
+              eq_improved      = anyBag (not . isCoVarBind) tybinds
               improvedFlexible = avails_improved || eq_improved
               reduced_dicts    = not (isEmptyBag dict_binds)
               improved         = improvedFlexible || reduced_dicts
@@ -1967,6 +1968,7 @@ reduceContext env wanteds0
             text "given" <+> ppr givens,
             text "wanted" <+> ppr wanteds0,
             text "----",
+            text "tybinds" <+> ppr tybinds,
             text "avails" <+> pprAvails avails,
             text "improved =" <+> ppr improved <+> text improvedHint,
             text "(all) irreds = " <+> ppr all_irreds,
@@ -1976,10 +1978,13 @@ reduceContext env wanteds0
             ]))
 
        ; return (improved, 
+                  tybinds,
                   normalise_binds `unionBags` dict_binds 
                                   `unionBags` implic_binds, 
                   all_irreds) 
         }
+  where
+    isCoVarBind (TcTyVarBind tv _) = isCoVar tv
 
 tcImproveOne :: Avails -> Inst -> TcM ImprovementDone
 tcImproveOne avails inst
index 1e65471..c7fac2d 100644 (file)
@@ -37,7 +37,6 @@ import Name
 import Bag
 import Outputable
 import SrcLoc  ( Located(..) )
-import Util    ( debugIsOn )
 import Maybes
 import MonadUtils
 import FastString
@@ -199,23 +198,67 @@ tcGenericNormaliseFamInstPred fun (EqPred ty1 ty2)
 %*                                                                     *
 %************************************************************************
 
+Given a set of given, local constraints and a set of wanted constraints,
+simplify the wanted equalities as far as possible and normalise both local and
+wanted dictionaries with respect to the equalities.
+
+In addition to the normalised local dictionaries and simplified wanteds, the
+function yields bindings for instantiated meta variables (due to solving
+equality constraints) and dictionary bindings (due to simplifying class
+constraints).  The bag of type variable bindings only contains bindings for
+non-local variables - i.e., type variables other than those newly created by
+the present function.  Consequently, type improvement took place iff the bag
+of bindings contains any bindings for proper type variables (not just covars).
+The solver does not instantiate any non-local variables; i.e., the bindings
+must be executed by the caller.
+
+All incoming constraints are assumed to be zonked already.  All outgoing
+constraints will be zonked again.
+
+NB: The solver only has local effects that cannot be observed from outside.
+    In particular, it can be executed twice on the same constraint set with
+    the same result (modulo generated variables names).
+
 \begin{code}
 tcReduceEqs :: [Inst]             -- locals
             -> [Inst]             -- wanteds
             -> TcM ([Inst],       -- normalised locals (w/o equalities)
                     [Inst],       -- normalised wanteds (including equalities)
-                    TcDictBinds,  -- bindings for all simplified dictionaries
-                    Bool)         -- whether any flexibles where instantiated
+                    TcTyVarBinds, -- bindings for meta type variables
+                    TcDictBinds)  -- bindings for all simplified dictionaries
 tcReduceEqs locals wanteds
-  = do { let (local_eqs  , local_dicts)   = partition isEqInst locals
-             (wanteds_eqs, wanteds_dicts) = partition isEqInst wanteds
-       ; eqCfg1 <- normaliseEqs (local_eqs ++ wanteds_eqs)
-       ; eqCfg2 <- normaliseDicts False local_dicts
-       ; eqCfg3 <- normaliseDicts True  wanteds_dicts
-       ; eqCfg <- propagateEqs (eqCfg1 `unionEqConfig` eqCfg2 
-                                       `unionEqConfig` eqCfg3)
-       ; finaliseEqsAndDicts eqCfg
+  = do { ((locals, wanteds, dictBinds), tyBinds) <- getTcTyVarBinds $
+           do { let (local_eqs  , local_dicts)   = partition isEqInst locals
+                    (wanteds_eqs, wanteds_dicts) = partition isEqInst wanteds
+              ; eqCfg1 <- normaliseEqs (local_eqs ++ wanteds_eqs)
+              ; eqCfg2 <- normaliseDicts False local_dicts
+              ; eqCfg3 <- normaliseDicts True  wanteds_dicts
+              ; eqCfg <- propagateEqs (eqCfg1 `unionEqConfig` 
+                                       eqCfg2 `unionEqConfig`
+                                       eqCfg3) 
+              ; finaliseEqsAndDicts freeFlexibles eqCfg
+              }
+         -- execute type bindings of skolem flexibles...
+       ; tyBinds_pruned <- pruneTyBinds tyBinds freeFlexibles
+         -- ...and zonk the constraints to propagate the bindings
+       ; locals_z  <- zonkInsts locals
+       ; wanteds_z <- zonkInsts wanteds
+       ; return (locals_z, wanteds_z, tyBinds_pruned, dictBinds)
        }
+   where
+     -- unification variables that appear in the environment and may not be
+     -- instantiated - this includes coercion variables
+     freeFlexibles = tcTyVarsOfInsts locals `unionVarSet` 
+                     tcTyVarsOfInsts wanteds
+
+     pruneTyBinds tybinds freeFlexibles
+       = do { let tybinds'                      = bagToList tybinds
+                  (skolem_tybinds, env_tybinds) = partition isSkolem tybinds'
+            ; execTcTyVarBinds (listToBag skolem_tybinds)
+            ; return $ listToBag env_tybinds
+            }
+       where
+         isSkolem (TcTyVarBind tv _ ) = not (tv `elemVarSet` freeFlexibles)
 \end{code}
 
 
@@ -235,13 +278,8 @@ data EqConfig = EqConfig { eqs     :: [RewriteInst]     -- all equalities
                          , locals  :: [Inst]            -- given dicts
                          , wanteds :: [Inst]            -- wanted dicts
                          , binds   :: TcDictBinds       -- bindings
-                         , skolems :: TyVarSet          -- flattening skolems
                          }
 
-addSkolems :: EqConfig -> TyVarSet -> EqConfig
-addSkolems eqCfg newSkolems 
-  = eqCfg {skolems = skolems eqCfg `unionVarSet` newSkolems}
-
 addEq :: EqConfig -> RewriteInst -> EqConfig
 addEq eqCfg eq = eqCfg {eqs = eq : eqs eqCfg}
 
@@ -251,7 +289,6 @@ unionEqConfig eqc1 eqc2 = EqConfig
                           , locals  = locals eqc1 ++ locals eqc2
                           , wanteds = wanteds eqc1 ++ wanteds eqc2
                           , binds   = binds eqc1 `unionBags` binds eqc2
-                          , skolems = skolems eqc1 `unionVarSet` skolems eqc2
                           }
 
 emptyEqConfig :: EqConfig
@@ -260,7 +297,6 @@ emptyEqConfig = EqConfig
                 , locals  = []
                 , wanteds = []
                 , binds   = emptyBag
-                , skolems = emptyVarSet
                 }
 
 instance Outputable EqConfig where
@@ -280,21 +316,11 @@ no further propoagation is possible.
 --
 normaliseEqs :: [Inst] -> TcM EqConfig
 normaliseEqs eqs 
-  = do { if debugIsOn then do { all_unsolved <- allM wantedEqInstIsUnsolved eqs
-                                     ; let msg = ptext (sLit "(This warning is harmless; for Simon & Manuel)")
-                                     ; WARN( not all_unsolved, msg $$ ppr eqs ) return () }
-                     else return ()
-           -- This is just a warning (not an error) because a current
-           -- harmless bug means that we sometimes solve the same
-           -- equality more than once It'll go away with the new
-           -- solver. See Trac #2999 for example
-
+  = do { ASSERTM2( allM wantedEqInstIsUnsolved eqs, ppr eqs )
        ; traceTc $ ptext (sLit "Entering normaliseEqs")
 
-       ; (eqss, skolemss) <- mapAndUnzipM normEqInst eqs
-       ; return $ emptyEqConfig { eqs = concat eqss
-                                , skolems = unionVarSets skolemss 
-                                }
+       ; eqss <- mapM normEqInst eqs
+       ; return $ emptyEqConfig { eqs = concat eqss }
        }
 
 -- |Flatten the type arguments of all dictionaries, returning the result as a 
@@ -309,8 +335,8 @@ normaliseDicts isWanted insts
                          ptext (if isWanted then sLit "[Wanted] for" 
                                             else sLit "[Local] for"))
                      4 (ppr insts)
-       ; (insts', eqss, bindss, skolemss) <- mapAndUnzip4M (normDict isWanted) 
-                                                           insts
+
+       ; (insts', eqss, bindss) <- mapAndUnzip3M (normDict isWanted) insts
 
        ; traceTc $ hang (ptext (sLit "normaliseDicts returns"))
                      4 (ppr insts' $$ ppr eqss)
@@ -318,7 +344,6 @@ normaliseDicts isWanted insts
                                 , locals  = if isWanted then [] else insts'
                                 , wanteds = if isWanted then insts' else []
                                 , binds   = unionManyBags bindss
-                                , skolems = unionVarSets skolemss
                                 }
        }
 
@@ -333,23 +358,22 @@ propagateEqs eqCfg@(EqConfig {eqs = todoEqs})
        }
 
 -- |Finalise a set of equalities and associated dictionaries after
--- propagation.  The returned Boolean value is `True' iff any flexible
--- variables, except those introduced by flattening (i.e., those in the
--- `skolems' component of the argument) where instantiated. The first returned
--- set of instances are the locals (without equalities) and the second set are
--- all residual wanteds, including equalities. 
+-- propagation.  The first returned set of instances are the locals (without
+-- equalities) and the second set are all residual wanteds, including
+-- equalities.  In addition, we return all generated dictionary bindings.
 --
-finaliseEqsAndDicts :: EqConfig 
-                    -> TcM ([Inst], [Inst], TcDictBinds, Bool)
-finaliseEqsAndDicts (EqConfig { eqs     = eqs
-                              , locals  = locals
-                              , wanteds = wanteds
-                              , binds   = binds
-                              , skolems = skolems
-                              })
+finaliseEqsAndDicts :: TcTyVarSet -> EqConfig 
+                    -> TcM ([Inst], [Inst], TcDictBinds)
+finaliseEqsAndDicts freeFlexibles (EqConfig { eqs     = eqs
+                                            , locals  = locals
+                                            , wanteds = wanteds
+                                            , binds   = binds
+                                            })
   = do { traceTc $ ptext (sLit "finaliseEqsAndDicts")
-       ; (eqs', subst_binds, locals', wanteds') <- substitute eqs locals wanteds
-       ; (eqs'', improved) <- instantiateAndExtract eqs' (null locals) skolems
+
+       ; (eqs', subst_binds, locals', wanteds') 
+           <- substitute eqs locals wanteds checkingMode freeFlexibles
+       ; eqs'' <- bindAndExtract eqs' checkingMode freeFlexibles
        ; let final_binds = subst_binds `unionBags` binds
 
          -- Assert that all cotvs of wanted equalities are still unfilled, and
@@ -357,8 +381,11 @@ finaliseEqsAndDicts (EqConfig { eqs     = eqs
        ; ASSERTM2( allM wantedEqInstIsUnsolved eqs'', ppr eqs'' )
        ; zonked_locals  <- zonkInsts locals'
        ; zonked_wanteds <- zonkInsts (eqs'' ++ wanteds')
-       ; return (zonked_locals, zonked_wanteds, final_binds, improved)
+       ; return (zonked_locals, zonked_wanteds, final_binds)
        }
+  where
+    checkingMode = length eqs > length wanteds || not (null locals)
+                     -- no local equalities or dicts => checking mode
 \end{code}
 
 
@@ -411,6 +438,16 @@ data RewriteInst
 isWantedRewriteInst :: RewriteInst -> Bool
 isWantedRewriteInst = isWantedCo . rwi_co
 
+isRewriteVar :: RewriteInst -> Bool
+isRewriteVar (RewriteVar {}) = True
+isRewriteVar _               = False
+
+tyVarsOfRewriteInst :: RewriteInst -> TyVarSet
+tyVarsOfRewriteInst (RewriteVar {rwi_var = tv, rwi_right = ty})
+  = unitVarSet tv `unionVarSet` tyVarsOfType ty
+tyVarsOfRewriteInst (RewriteFam {rwi_args = args, rwi_right = ty})
+  = tyVarsOfTypes args `unionVarSet` tyVarsOfType ty
+
 rewriteInstToInst :: RewriteInst -> TcM Inst
 rewriteInstToInst eq@(RewriteVar {rwi_var = tv})
   = deriveEqInst eq (mkTyVarTy tv) (rwi_right eq) (rwi_co eq)
@@ -472,7 +509,7 @@ we drop that equality and raise an error if it is a wanted or a warning if it
 is a local.
 
 \begin{code}
-normEqInst :: Inst -> TcM ([RewriteInst], TyVarSet)
+normEqInst :: Inst -> TcM [RewriteInst]
 -- Normalise one equality.
 normEqInst inst
   = ASSERT( isEqInst inst )
@@ -480,6 +517,7 @@ normEqInst inst
                    pprEqInstCo co <+> text "::" <+> 
                    ppr ty1 <+> text "~" <+> ppr ty2
        ; res <- go ty1 ty2 co
+
        ; traceTc $ ptext (sLit "normEqInst returns") <+> ppr res
        ; return res
        }
@@ -505,8 +543,8 @@ normEqInst inst
 
       -- no outermost family
     go ty1 ty2 co
-      = do { (ty1', co1, ty1_eqs, ty1_skolems) <- flattenType inst ty1
-           ; (ty2', co2, ty2_eqs, ty2_skolems) <- flattenType inst ty2
+      = do { (ty1', co1, ty1_eqs) <- flattenType inst ty1
+           ; (ty2', co2, ty2_eqs) <- flattenType inst ty2
            ; let ty12_eqs  = ty1_eqs ++ ty2_eqs
                  sym_co2   = mkSymCoercion co2
                  eqTys     = (ty1', ty2')
@@ -519,17 +557,15 @@ normEqInst inst
                             eqInstMisMatch inst
                        else
                          warnDroppingLoopyEquality ty1 ty2
-                     ; return ([], emptyVarSet)         -- drop the equality
+                     ; return ([])                 -- drop the equality
                      }
              else
-               return (eqs ++ ty12_eqs',
-                      ty1_skolems `unionVarSet` ty2_skolems)
+               return (eqs ++ ty12_eqs')
            }
 
     mkRewriteFam swapped con args ty2 co
-      = do { (args', cargs, args_eqss, args_skolemss) 
-               <- mapAndUnzip4M (flattenType inst) args
-           ; (ty2', co2, ty2_eqs, ty2_skolems) <- flattenType inst ty2
+      = do { (args', cargs, args_eqss) <- mapAndUnzip3M (flattenType inst) args
+           ; (ty2', co2, ty2_eqs) <- flattenType inst ty2
            ; let co1       = mkTyConApp con cargs
                  sym_co2   = mkSymCoercion co2
                  all_eqs   = concat args_eqss ++ ty2_eqs
@@ -544,40 +580,37 @@ normEqInst inst
                                   , rwi_name    = tci_name inst
                                   , rwi_swapped = swapped
                                   }
-           ; return $ (thisRewriteFam : all_eqs',
-                       unionVarSets (ty2_skolems:args_skolemss))
+           ; return $ thisRewriteFam : all_eqs'
            }
 
     -- If the original equality has the form a ~ T .. (F ...a...) ..., we will
     -- have a variable equality with 'a' on the lhs as the first equality.
     -- Then, check whether 'a' occurs in the lhs of any family equality
     -- generated by flattening.
-    isLoopyEquality (RewriteVar {rwi_var = tv}:_) eqs
-      = any inRewriteFam eqs
+    isLoopyEquality (RewriteVar {rwi_var = tv}:_) eqs = any inRewriteFam eqs
       where
         inRewriteFam (RewriteFam {rwi_args = args}) 
           = tv `elemVarSet` tyVarsOfTypes args
         inRewriteFam _ = False
     isLoopyEquality _ _ = False
 
-normDict :: Bool -> Inst -> TcM (Inst, [RewriteInst], TcDictBinds, TyVarSet)
+normDict :: Bool -> Inst -> TcM (Inst, [RewriteInst], TcDictBinds)
 -- Normalise one dictionary or IP constraint.
 normDict isWanted inst@(Dict {tci_pred = ClassP clas args})
-  = do { (args', cargs, args_eqss, args_skolemss) 
-           <- mapAndUnzip4M (flattenType inst) args
+  = do { (args', cargs, args_eqss) <- mapAndUnzip3M (flattenType inst) args
        ; let rewriteCo = PredTy $ ClassP clas cargs
              eqs       = concat args_eqss
              pred'     = ClassP clas args'
        ; if null eqs
          then  -- don't generate a binding if there is nothing to flatten
-           return (inst, [], emptyBag, emptyVarSet)
+           return (inst, [], emptyBag)
          else do {
        ; (inst', bind) <- mkDictBind inst isWanted rewriteCo pred'
        ; eqs' <- if isWanted then return eqs else mapM wantedToLocal eqs
-       ; return (inst', eqs', bind, unionVarSets args_skolemss)
+       ; return (inst', eqs', bind)
        }}
 normDict _isWanted inst
-  = return (inst, [], emptyBag, emptyVarSet)
+  = return (inst, [], emptyBag)
 -- !!!TODO: Still need to normalise IP constraints.
 
 checkOrientation :: Type -> Type -> EqInstCo -> Inst -> TcM [RewriteInst]
@@ -722,31 +755,29 @@ flattenType :: Inst     -- context to get location  & name
             -> Type     -- the type to flatten
             -> TcM (Type,           -- the flattened type
                     Coercion,       -- coercion witness of flattening wanteds
-                    [RewriteInst],  -- extra equalities
-                    TyVarSet)       -- new intermediate skolems
+                    [RewriteInst])  -- extra equalities
 -- Removes all family synonyms from a type by moving them into extra equalities
-flattenType inst ty
-  = go ty
+flattenType inst ty = go ty
   where
       -- look through synonyms
     go ty | Just ty' <- tcView ty 
-      = do { (ty_flat, co, eqs, skolems) <- go ty'
+      = do { (ty_flat, co, eqs) <- go ty'
            ; if null eqs
              then     -- unchanged, keep the old type with folded synonyms
-               return (ty, ty, [], emptyVarSet)
+               return (ty, ty, [])
              else 
-               return (ty_flat, co, eqs, skolems)
+               return (ty_flat, co, eqs)
            }
 
       -- type variable => nothing to do
     go ty@(TyVarTy _)
-      = return (ty, ty, [] , emptyVarSet)
+      = return (ty, ty, [])
 
       -- type family application & family arity matches number of args
       -- => flatten to "gamma :: F t1'..tn' ~ alpha" (alpha & gamma fresh)
     go ty@(TyConApp con args)
       | isOpenSynTyConApp ty   -- only if not oversaturated
-      = do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
+      = do { (args', cargs, args_eqss) <- mapAndUnzip3M go args
            ; alpha <- newFlexiTyVar (typeKind ty)
            ; let alphaTy = mkTyVarTy alpha
            ; cotv <- newMetaCoVar (mkTyConApp con args') alphaTy
@@ -761,38 +792,35 @@ flattenType inst ty
                                   }
            ; return (alphaTy,
                      mkTyConApp con cargs `mkTransCoercion` mkTyVarTy cotv,
-                     thisRewriteFam : concat args_eqss,
-                     unionVarSets args_skolemss `extendVarSet` alpha)
-           }           -- adding new unflatten var inst
+                     thisRewriteFam : concat args_eqss)
+           }
 
       -- data constructor application => flatten subtypes
       -- NB: Special cased for efficiency - could be handled as type application
     go ty@(TyConApp con args)
       | not (isOpenSynTyCon con)   -- don't match oversaturated family apps
-      = do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
+      = do { (args', cargs, args_eqss) <- mapAndUnzip3M go args
            ; if null args_eqss
              then     -- unchanged, keep the old type with folded synonyms
-               return (ty, ty, [], emptyVarSet)
+               return (ty, ty, [])
              else 
                return (mkTyConApp con args', 
                        mkTyConApp con cargs,
-                       concat args_eqss,
-                       unionVarSets args_skolemss)
+                       concat args_eqss)
            }
 
       -- function type => flatten subtypes
       -- NB: Special cased for efficiency - could be handled as type application
     go ty@(FunTy ty_l ty_r)
-      = do { (ty_l', co_l, eqs_l, skolems_l) <- go ty_l
-           ; (ty_r', co_r, eqs_r, skolems_r) <- go ty_r
+      = do { (ty_l', co_l, eqs_l) <- go ty_l
+           ; (ty_r', co_r, eqs_r) <- go ty_r
            ; if null eqs_l && null eqs_r
              then     -- unchanged, keep the old type with folded synonyms
-               return (ty, ty, [], emptyVarSet)
+               return (ty, ty, [])
              else 
                return (mkFunTy ty_l' ty_r', 
                        mkFunTy co_l co_r,
-                       eqs_l ++ eqs_r, 
-                       skolems_l `unionVarSet` skolems_r)
+                       eqs_l ++ eqs_r)
            }
 
       -- type application => flatten subtypes
@@ -800,16 +828,15 @@ flattenType inst ty
       | Just (ty_l, ty_r) <- repSplitAppTy_maybe ty
                              -- need to use the smart split as ty may be an
                              -- oversaturated family application
-      = do { (ty_l', co_l, eqs_l, skolems_l) <- go ty_l
-           ; (ty_r', co_r, eqs_r, skolems_r) <- go ty_r
+      = do { (ty_l', co_l, eqs_l) <- go ty_l
+           ; (ty_r', co_r, eqs_r) <- go ty_r
            ; if null eqs_l && null eqs_r
              then     -- unchanged, keep the old type with folded synonyms
-               return (ty, ty, [], emptyVarSet)
+               return (ty, ty, [])
              else 
                return (mkAppTy ty_l' ty_r', 
                        mkAppTy co_l co_r, 
-                       eqs_l ++ eqs_r, 
-                       skolems_l `unionVarSet` skolems_r)
+                       eqs_l ++ eqs_r)
            }
 
       -- forall type => panic if the body contains a type family
@@ -818,7 +845,7 @@ flattenType inst ty
       --          variable???
     go ty@(ForAllTy _ body)
       | null (tyFamInsts body)
-      = return (ty, ty, [] , emptyVarSet)
+      = return (ty, ty, [])
       | otherwise
       = panic "TcTyFuns.flattenType: synonym family in a rank-n type"
 
@@ -841,7 +868,7 @@ adjustCoercions :: EqInstCo            -- coercion of original equality
 adjustCoercions (Left cotv) co1 co2 (ty_l, ty_r) all_eqs
     -- wanted => generate a fresh coercion variable for the flattened equality
   = do { cotv' <- newMetaCoVar ty_l ty_r
-       ; writeMetaTyVar cotv $ 
+       ; bindMetaTyVar cotv $ 
            (co1 `mkTransCoercion` TyVarTy cotv' `mkTransCoercion` co2)
        ; return (Left cotv', all_eqs)
        }
@@ -890,6 +917,12 @@ mkDictBind dict isWanted rewriteCo pred
 --  NB: It's crucial to update *both* alpha and gamma, as gamma may already
 --      have escaped into some other coercions during normalisation.
 --
+--      We do actually update alpha and gamma by side effect (instead of
+--      only remembering the binding with `bindMetaTyVar', as we do for all
+--      other tyvars).  We can do this as the side effects are strictly
+--      *local*; we know that both alpha and gamma were just a moment ago
+--      introduced by normalisation. 
+--
 wantedToLocal :: RewriteInst -> TcM RewriteInst
 wantedToLocal eq@(RewriteFam {rwi_fam   = fam, 
                               rwi_args  = args, 
@@ -919,35 +952,32 @@ propagate (eq:eqs) eqCfg
        ; case optEqs of
 
               -- Top applied to 'eq' => retry with new equalities
-           Just (eqs2, skolems2) 
-             -> propagate (eqs2 ++ eqs) (eqCfg `addSkolems` skolems2)
+           Just eqs2 -> propagate (eqs2 ++ eqs) eqCfg
 
               -- Top doesn't apply => try subst rules with all other
               --   equalities, after that 'eq' can go into the residual list
-           Nothing
-             -> do { (eqs', eqCfg') <- applySubstRules eq eqs eqCfg
-                   ; propagate eqs' (eqCfg' `addEq` eq)
-                   }
-   }
+           Nothing   -> do { (eqs', eqCfg') <- applySubstRules eq eqs eqCfg
+                           ; propagate eqs' (eqCfg' `addEq` eq)
+                           }
+       }
 
 applySubstRules :: RewriteInst                    -- currently considered eq
                 -> [RewriteInst]                  -- todo eqs list
                 -> EqConfig                       -- residual
                 -> TcM ([RewriteInst], EqConfig)  -- new todo & residual
 applySubstRules eq todoEqs (eqConfig@EqConfig {eqs = resEqs})
-  = do { (newEqs_t, unchangedEqs_t, skolems_t) <- mapSubstRules eq todoEqs
-       ; (newEqs_r, unchangedEqs_r, skolems_r) <- mapSubstRules eq resEqs
+  = do { (newEqs_t, unchangedEqs_t) <- mapSubstRules eq todoEqs
+       ; (newEqs_r, unchangedEqs_r) <- mapSubstRules eq resEqs
        ; return (newEqs_t ++ newEqs_r ++ unchangedEqs_t,
-                 eqConfig {eqs = unchangedEqs_r} 
-                   `addSkolems` (skolems_t `unionVarSet` skolems_r))
+                 eqConfig {eqs = unchangedEqs_r})
        }
 
 mapSubstRules :: RewriteInst     -- try substituting this equality
               -> [RewriteInst]   -- into these equalities
-              -> TcM ([RewriteInst], [RewriteInst], TyVarSet)
+              -> TcM ([RewriteInst], [RewriteInst])
 mapSubstRules eq eqs
-  = do { (newEqss, unchangedEqss, skolemss) <- mapAndUnzip3M (substRules eq) eqs
-       ; return (concat newEqss, concat unchangedEqss, unionVarSets skolemss)
+  = do { (newEqss, unchangedEqss) <- mapAndUnzipM (substRules eq) eqs
+       ; return (concat newEqss, concat unchangedEqss)
        }
   where
     substRules eq1 eq2
@@ -957,18 +987,18 @@ mapSubstRules eq eqs
                -- try the SubstFam rule
            ; optEqs <- applySubstFam eq1 eq2
            ; case optEqs of
-               Just (eqs, skolems) -> return (eqs, [], skolems)
-               Nothing             -> do 
+               Just eqs -> return (eqs, [])
+               Nothing  -> do 
            {   -- try the SubstVarVar rule
              optEqs <- applySubstVarVar eq1 eq2
            ; case optEqs of
-               Just (eqs, skolems) -> return (eqs, [], skolems)
-               Nothing             -> do 
+               Just eqs -> return (eqs, [])
+               Nothing  -> do 
            {   -- try the SubstVarFam rule
              optEqs <- applySubstVarFam eq1 eq2
            ; case optEqs of
-               Just eq -> return ([eq], [], emptyVarSet)
-               Nothing -> return ([], [eq2], emptyVarSet)
+               Just eq -> return ([eq], [])
+               Nothing -> return ([], [eq2])
                  -- if no rule matches, we return the equlity we tried to
                  -- substitute into unchanged
            }}}
@@ -986,7 +1016,7 @@ Returns Nothing if the rule could not be applied.  Otherwise, the resulting
 equality is normalised and a list of the normal equalities is returned.
 
 \begin{code}
-applyTop :: RewriteInst -> TcM (Maybe ([RewriteInst], TyVarSet))
+applyTop :: RewriteInst -> TcM (Maybe [RewriteInst])
 
 applyTop eq@(RewriteFam {rwi_fam = fam, rwi_args = args})
   = do { optTyCo <- tcUnfoldSynFamInst (TyConApp fam args)
@@ -1020,7 +1050,7 @@ equality co1 is not returned as it remain unaltered.)
 \begin{code}
 applySubstFam :: RewriteInst 
               -> RewriteInst 
-              -> TcM (Maybe ([RewriteInst], TyVarSet))
+              -> TcM (Maybe ([RewriteInst]))
 applySubstFam eq1@(RewriteFam {rwi_fam = fam1, rwi_args = args1})
               eq2@(RewriteFam {rwi_fam = fam2, rwi_args = args2})
 
@@ -1035,7 +1065,7 @@ applySubstFam eq1@(RewriteFam {rwi_fam = fam1, rwi_args = args1})
     -- rule would match with eq1 and eq2 swapped => put eq2 into todo list
   | fam1 == fam2 && tcEqTypes args1 args2 &&
     (isWantedRewriteInst eq1 || not (isWantedRewriteInst eq2))
-  = return $ Just ([eq2], emptyVarSet)
+  = return $ Just [eq2]
 
   where
     lhs = rwi_right eq1
@@ -1059,9 +1089,7 @@ co2' is normalised and a list of the normal equalities is returned.  (The
 equality co1 is not returned as it remain unaltered.)
 
 \begin{code}
-applySubstVarVar :: RewriteInst 
-                 -> RewriteInst 
-                 -> TcM (Maybe ([RewriteInst], TyVarSet))
+applySubstVarVar :: RewriteInst -> RewriteInst -> TcM (Maybe [RewriteInst])
 applySubstVarVar eq1@(RewriteVar {rwi_var = tv1})
                  eq2@(RewriteVar {rwi_var = tv2})
 
@@ -1076,7 +1104,7 @@ applySubstVarVar eq1@(RewriteVar {rwi_var = tv1})
     -- rule would match with eq1 and eq2 swapped => put eq2 into todo list
   | tv1 == tv2 &&
     (isWantedRewriteInst eq1 || not (isWantedRewriteInst eq2))
-  = return $ Just ([eq2], emptyVarSet)
+  = return $ Just [eq2]
 
   where
     lhs = rwi_right eq1
@@ -1135,28 +1163,54 @@ applySubstVarFam _ _ = return Nothing
 %************************************************************************
 
 Exhaustive substitution of all variable equalities of the form co :: x ~ t
-(both local and wanted) into the left-hand sides of all other equalities.  This
-may lead to recursive equalities; i.e., (1) we need to apply the substitution
-implied by one variable equality exhaustively before turning to the next and
-(2) we need an occurs check.
+(both local and wanted) into the right-hand sides of all other equalities and
+of family equalities of the form co :: F t1..tn ~ alpha into both sides of all
+other *family* equalities.  This may lead to recursive equalities; i.e., (1)
+we need to apply the substitution implied by one equality exhaustively before
+turning to the next and (2) we need an occurs check.
 
 We also apply the same substitutions to the local and wanted class and IP
-dictionaries.
+dictionaries.  
+
+We perform the substitutions in two steps:
+
+  Step A: Substitute variable equalities into the right-hand sides of all
+          other equalities (but wanted only into wanteds) and into class and IP 
+          constraints (again wanteds only into wanteds).
+
+  Step B: Substitute wanted family equalities `co :: F t1..tn ~ alpha', where
+          'alpha' is a skolem flexible (i.e., not free in the environment),
+          into the right-hand sides of all wanted variable equalities and into
+          both sides of all wanted family equalities.
+
+  Step C: Substitute the remaining wanted family equalities `co :: F t1..tn ~
+          alpha' into the right-hand sides of all wanted variable equalities
+          and into both sides of all wanted family equalities.
+
+In inference mode, we do not substitute into variable equalities in Steps B & C.
 
 The treatment of flexibles in wanteds is quite subtle.  We absolutely want to
-substitute them into right-hand sides of equalities, to avoid getting two
-competing instantiations for a type variables; e.g., consider
+substitute variable equalities first; e.g., consider
 
   F s ~ alpha, alpha ~ t
 
-If we don't substitute `alpha ~ t', we may instantiate t with `F s' instead.
+If we don't substitute `alpha ~ t', we may instantiate `t' with `F s' instead.
 This would be bad as `F s' is less useful, eg, as an argument to a class
-constraint.
+constraint.  
+
+The restriction on substituting locals is necessary due to examples, such as
 
-However, there is no reason why we would want to *substitute* `alpha ~ t' into a
-class constraint.  We rather wait until `alpha' is instantiated to `t` and
-save the extra dictionary binding that substitution would introduce.
-Moreover, we may substitute wanted equalities only into wanted dictionaries.
+  F delta ~ alpha, F alpha ~ delta,
+
+where `alpha' is a skolem flexible and `delta' a environment flexible. We need
+to produce `F (F delta) ~ delta' (and not `F (F alpha) ~ alpha'). Otherwise,
+we may wrongly claim to having performed an improvement, which can lead to
+non-termination of the combined class-family solver.
+
+We do also substitute flexibles, as in `alpha ~ t' into class constraints.
+When `alpha' is later instantiated, we'd get the same effect, but in the
+meantime the class constraint would miss some information, which would be a
+problem in an integrated equality-class solver.
 
 NB: 
 * Given that we apply the substitution corresponding to a single equality
@@ -1168,25 +1222,43 @@ NB:
 substitute :: [RewriteInst]       -- equalities
            -> [Inst]              -- local class dictionaries
            -> [Inst]              -- wanted class dictionaries
+           -> Bool                -- True ~ checking mode; False ~ inference
+           -> TyVarSet            -- flexibles free in the environment
            -> TcM ([RewriteInst], -- equalities after substitution
                    TcDictBinds,   -- all newly generated dictionary bindings
                    [Inst],        -- local dictionaries after substitution
                    [Inst])        -- wanted dictionaries after substitution
-substitute eqs locals wanteds = subst eqs [] emptyBag locals wanteds
+substitute eqs locals wanteds checkingMode freeFlexibles
+  = -- We achieve the sequencing of "Step A", "Step B", and "Step C" above by
+    -- sorting the equalities appropriately: first all variable, then all
+    -- family/skolem, and then the remaining family equalities. 
+    let (var_eqs, fam_eqs)             = partition isRewriteVar eqs
+        (fam_skolem_eqs, fam_eqs_rest) = partition isFamSkolemEq fam_eqs
+    in 
+    subst (var_eqs ++ fam_skolem_eqs ++ fam_eqs_rest) [] emptyBag locals wanteds
   where
+    isFamSkolemEq (RewriteFam {rwi_right = ty})
+      | Just tv <- tcGetTyVar_maybe ty = not (tv `elemVarSet` freeFlexibles)
+    isFamSkolemEq _ = False
+
     subst [] res binds locals wanteds 
       = return (res, binds, locals, wanteds)
 
+    -- co :: x ~ t
     subst (eq@(RewriteVar {rwi_var = tv, rwi_right = ty, rwi_co = co}):eqs) 
           res binds locals wanteds
-      = do { traceTc $ ptext (sLit "TcTyFuns.substitute:") <+> ppr eq
+      = do { traceTc $ ptext (sLit "TcTyFuns.substitute[RewriteVar]:") <+> 
+                       ppr eq
 
+             -- create the substitution
            ; let coSubst = zipOpenTvSubst [tv] [eqInstCoType co]
                  tySubst = zipOpenTvSubst [tv] [ty]
+
+             -- substitute into all other equalities
            ; eqs' <- mapM (substEq eq coSubst tySubst) eqs
            ; res' <- mapM (substEq eq coSubst tySubst) res
 
-             -- only susbtitute local equalities into local dictionaries
+             -- only substitute local equalities into local dictionaries
            ; (lbinds, locals')  <- if not (isWantedCo co)
                                    then 
                                      mapAndUnzipM 
@@ -1195,28 +1267,48 @@ substitute eqs locals wanteds = subst eqs [] emptyBag locals wanteds
                                    else
                                      return ([], locals)
 
-              -- flexible tvs in wanteds will be instantiated anyway, there is
-              -- no need to substitute them into dictionaries
-           ; (wbinds, wanteds') <- if not (isMetaTyVar tv && isWantedCo co)
-                                   then
-                                     mapAndUnzipM 
-                                       (substDict eq coSubst tySubst True) 
-                                       wanteds
-                                   else
-                                     return ([], wanteds)
+              -- substitute all equalities into wanteds dictionaries
+           ; (wbinds, wanteds') <- mapAndUnzipM 
+                                     (substDict eq coSubst tySubst True) 
+                                     wanteds
 
            ; let binds' = unionManyBags $ binds : lbinds ++ wbinds
            ; subst eqs' (eq:res') binds' locals' wanteds'
            }
+
+    -- co ::^w F t1..tn ~ alpha
+    subst (eq@(RewriteFam {rwi_fam = fam, rwi_args = args, rwi_right = ty, 
+                           rwi_co = co}):eqs) 
+          res binds locals wanteds
+      | Just tv <- tcGetTyVar_maybe ty
+      , isMetaTyVar tv
+      , isWantedCo co
+      = do { traceTc $ ptext (sLit "TcTyFuns.substitute[RewriteFam]:") <+> 
+                       ppr eq
+
+             -- create the substitution
+           ; let coSubst = zipOpenTvSubst [tv] [mkSymCoercion $ eqInstCoType co]
+                 tySubst = zipOpenTvSubst [tv] [mkTyConApp fam args]
+
+             -- substitute into other wanted equalities (`substEq' makes sure
+             -- that we only substitute into wanteds)
+           ; eqs' <- mapM (substEq eq coSubst tySubst) eqs
+           ; res' <- mapM (substEq eq coSubst tySubst) res
+
+           ; subst eqs' (eq:res') binds locals wanteds
+           }
+
     subst (eq:eqs) res binds locals wanteds
       = subst eqs (eq:res) binds locals wanteds
 
       -- We have, co :: tv ~ ty 
       -- => apply [ty/tv] to right-hand side of eq2
-      --    (but only if tv actually occurs in the right-hand side of eq2)
-    substEq (RewriteVar {rwi_var = tv, rwi_right = ty}) 
+      --    (but only if tv actually occurs in the right-hand side of eq2
+      --    and if eq2 is a local, co :: tv ~ ty needs to be a local, too)
+    substEq (RewriteVar {rwi_var = tv, rwi_right = ty, rwi_co = co}) 
             coSubst tySubst eq2
-      | tv `elemVarSet` tyVarsOfType (rwi_right eq2)
+      |  tv `elemVarSet` tyVarsOfType (rwi_right eq2)
+      && (isWantedRewriteInst eq2 || not (isWantedCo co))
       = do { let co1Subst = mkSymCoercion $ substTy coSubst (rwi_right eq2)
                  right2'  = substTy tySubst (rwi_right eq2)
                  left2    = case eq2 of
@@ -1230,6 +1322,44 @@ substitute eqs locals wanteds = subst eqs [] emptyBag locals wanteds
                _ -> return $ eq2 {rwi_right = right2', rwi_co = co2'}
            }
 
+      -- We have, co ::^w F t1..tn ~ tv
+      -- => apply [F t1..tn/tv] to eq2
+      --    (but only if tv actually occurs in eq2
+      --    and eq2 is a wanted equality
+      --    and we are either in checking mode or eq2 is a family equality)
+    substEq (RewriteFam {rwi_args = args, rwi_right = ty}) 
+            coSubst tySubst eq2
+      | Just tv <- tcGetTyVar_maybe ty
+      , tv `elemVarSet` tyVarsOfRewriteInst eq2
+      , isWantedRewriteInst eq2
+      , checkingMode || not (isRewriteVar eq2)
+      = do { -- substitute into the right-hand side
+           ; let co1Subst = mkSymCoercion $ substTy coSubst (rwi_right eq2)
+                 right2'  = substTy tySubst (rwi_right eq2)
+                 left2    = case eq2 of
+                              RewriteVar {rwi_var = tv2}   -> mkTyVarTy tv2
+                              RewriteFam {rwi_fam = fam,
+                                          rwi_args = args} -> mkTyConApp fam args
+           ; co2' <- mkLeftTransEqInstCo (rwi_co eq2) co1Subst (left2, right2')
+           ; case eq2 of
+               RewriteVar {rwi_var = tv2} 
+                 -- variable equality: perform an occurs check
+                 | tv2 `elemVarSet` tyVarsOfTypes args
+                 -> occurCheckErr left2 right2'
+                 | otherwise
+                 -> return $ eq2 {rwi_right = right2', rwi_co = co2'}
+               RewriteFam {rwi_fam = fam}
+                 -- family equality: substitute also into the left-hand side
+                 -> do { let co1Subst = substTy coSubst left2
+                             args2'   = substTys tySubst (rwi_args  eq2)
+                             left2'   = mkTyConApp fam args2'
+                       ; co2'' <- mkRightTransEqInstCo co2' co1Subst 
+                                                       (left2', right2')
+                       ; return $ eq2 {rwi_args = args2', rwi_right = right2', 
+                                       rwi_co = co2''}
+                       }
+           }
+
       -- unchanged
     substEq _ _ _ eq2
       = return eq2
@@ -1253,73 +1383,107 @@ substitute eqs locals wanteds = subst eqs [] emptyBag locals wanteds
 \end{code}
 
 For any *wanted* variable equality of the form co :: alpha ~ t or co :: a ~
-alpha, we instantiate alpha with t or a, respectively, and set co := id.
-Return all remaining wanted equalities.  The Boolean result component is True
-if at least one instantiation of a flexible that is *not* a skolem from
-flattening was performed.
-
-We need to instantiate all flexibles that arose as skolems during flattening
-of wanteds before we instantiate any other flexibles. Consider F delta ~
-alpha, F alpha ~ delta, where alpha is a skolem and delta a free flexible. We
-need to produce F (F delta) ~ delta (and not F (F alpha) ~ alpha). Otherwise,
-we may wrongly claim to having performed an improvement, which can lead to
-non-termination of the combined class-family solver.
+alpha, we record a binding of alpha with t or a, respectively, and for co :=
+id.  We do the same for equalities of the form co :: F t1..tn ~ alpha unless
+we are in inference mode and alpha appears in the environment - i.e., it is
+not a flexible introduced by flattening locals or it is local, but was
+propagated into the environment by the instantiation of a variable equality.
+
+We proceed in two phases: (1) first we consider all variable equalities and then
+(2) we consider all family equalities.  The two phase structure is required as
+the recorded variable equalities determine which skolems flexibles escape, and
+hence, which family equalities may be recorded as bindings.
+
+We return all wanted equalities for which we did not generate a binding.
+(These can be skolem variable equalities, cyclic variable equalities, and
+family equalities.)
+
+We don't update any meta variables.  Instead, instantiation simply implies
+putting a type variable binding into the binding pool of TcM.
+
+NB:
+ * We may encounter filled flexibles due to the instant filling of local
+   skolems in local-given constraints during flattening.
+ * Be careful with SigTVs.  They can only be instantiated with other SigTVs or
+   rigid skolems.
 
 \begin{code}
-instantiateAndExtract :: [RewriteInst] -> Bool -> TyVarSet -> TcM ([Inst], Bool)
-instantiateAndExtract eqs localsEmpty skolems
-  = do { traceTc $ hang (ptext (sLit "instantiateAndExtract:"))
-                     4 (ppr eqs $$ ppr skolems)
-           -- start by *only* instantiating skolem flexibles from flattening
-       ; unflat_wanteds <- liftM catMaybes $ 
-                             mapM (inst (`elemVarSet` skolems)) wanteds
-           -- only afterwards instantiate free flexibles
-       ; residuals <- liftM catMaybes $ mapM (inst (const True)) unflat_wanteds
-       ; let improvement = length residuals < length unflat_wanteds
-       ; residuals' <- mapM rewriteInstToInst residuals
-       ; return (residuals', improvement)
+bindAndExtract :: [RewriteInst] -> Bool -> TyVarSet -> TcM [Inst]
+bindAndExtract eqs checkingMode freeFlexibles
+  = do { traceTc $ hang (ptext (sLit "bindAndExtract:"))
+                     4 (ppr eqs $$ ppr freeFlexibles)
+       ; residuals1 <- mapMaybeM instVarEq (filter isWantedRewriteInst eqs)
+       ; escapingSkolems <- getEscapingSkolems
+       ; let newFreeFlexibles = freeFlexibles `unionVarSet` escapingSkolems
+       ; residuals2 <- mapMaybeM (instFamEq newFreeFlexibles) residuals1
+       ; mapM rewriteInstToInst residuals2
        }
   where
-    wanteds      = filter (isWantedCo . rwi_co) eqs
-    checkingMode = length eqs > length wanteds || not localsEmpty
-                     -- no local equalities or dicts => checking mode
+    -- NB: we don't have to transitively chase the relation as the substitution
+    --     process applied before generating the bindings was exhaustive
+    getEscapingSkolems
+      = do { tybinds_rel <- getTcTyVarBindsRelation
+           ; return (unionVarSets . map snd . filter isFree $ tybinds_rel)
+           }
+      where
+        isFree (tv, _) = tv `elemVarSet` freeFlexibles
 
         -- co :: alpha ~ t or co :: a ~ alpha
-    inst mayInst eq@(RewriteVar {rwi_var = tv1, rwi_right = ty2, rwi_co = co})
-      = do { flexi_tv1       <- isFlexible mayInst tv1
-           ; maybe_flexi_tv2 <- isFlexibleTy mayInst ty2
+    instVarEq eq@(RewriteVar {rwi_var = tv1, rwi_right = ty2, rwi_co = co})
+      = do { flexi_tv1       <- isFlexible   tv1
+           ; maybe_flexi_tv2 <- isFlexibleTy ty2
            ; case (flexi_tv1, maybe_flexi_tv2) of
+               (True, Just tv2)
+                 | isSigTyVar tv1 && isSigTyVar tv2
+                 -> -- co :: alpha ~ beta, where both a SigTvs
+                    doInst (rwi_swapped eq) tv1 ty2 co eq
+               (True, Nothing) 
+                 | Just tv2 <- tcGetTyVar_maybe ty2
+                 , isSigTyVar tv1
+                 , isSkolemTyVar tv2
+                 -> -- co :: alpha ~ a, where alpha is a SigTv
+                    doInst (rwi_swapped eq) tv1 ty2 co eq
                (True, _) 
-                 -> -- co :: alpha ~ t
+                 | not (isSigTyVar tv1)
+                 -> -- co :: alpha ~ t, where alpha is not a SigTv
                     doInst (rwi_swapped eq) tv1 ty2 co eq
                (False, Just tv2) 
-                 -> -- co :: a ~ alpha                  
+                 | isSigTyVar tv2
+                 , isSkolemTyVar tv1
+                 -> -- co :: a ~ alpha, where alpha is a SigTv
+                    doInst (not $ rwi_swapped eq) tv2 (mkTyVarTy tv1) co eq
+                 | not (isSigTyVar tv2)
+                 -> -- co :: a ~ alpha, where alpha is not a SigTv 
+                    --                        ('a' may be filled)
                     doInst (not $ rwi_swapped eq) tv2 (mkTyVarTy tv1) co eq
                _ -> return $ Just eq
            }
+    instVarEq eq = return $ Just eq
 
-        -- co :: F args ~ alpha, and we are in checking mode (ie, no locals)
-    inst mayInst eq@(RewriteFam {rwi_fam = fam, rwi_args = args, 
-                                 rwi_right = ty2, rwi_co = co})
+        -- co :: F args ~ alpha, 
+        -- and we are either in checking mode or alpha is a skolem flexible that
+        --     doesn't escape
+    instFamEq newFreeFlexibles eq@(RewriteFam {rwi_fam = fam, rwi_args = args, 
+                                               rwi_right = ty2, rwi_co = co})
       | Just tv2 <- tcGetTyVar_maybe ty2
-      , isMetaTyVar tv2
-      , mayInst tv2 && (checkingMode || tv2 `elemVarSet` skolems)
-                        -- !!!FIXME: this is too liberal, even if tv2 is in 
-                        -- skolems we shouldn't instantiate if tvs occurs 
-                        -- in other equalities that may propagate it into the
-                        -- environment
-      = doInst (not $ rwi_swapped eq) tv2 (mkTyConApp fam args) co eq
-
-    inst _mayInst eq = return $ Just eq
-
-    -- tv is a meta var and not filled
-    isFlexible mayInst tv
-      | isMetaTyVar tv && mayInst tv = liftM isFlexi $ readMetaTyVar tv
-      | otherwise                    = return False
-
-    -- type is a tv that is a meta var and not filled
-    isFlexibleTy mayInst ty
-      | Just tv <- tcGetTyVar_maybe ty = do {flexi <- isFlexible mayInst tv
+      , checkingMode || not (tv2 `elemVarSet` newFreeFlexibles)
+      = do { flexi_tv2 <- isFlexible tv2
+           ; if flexi_tv2
+             then
+               doInst (not $ rwi_swapped eq) tv2 (mkTyConApp fam args) co eq
+             else
+               return $ Just eq
+           }
+    instFamEq _ eq = return $ Just eq
+
+    -- tv is a meta var, but not a SigTV and not filled
+    isFlexible tv
+      | isMetaTyVar tv = liftM isFlexi $ readMetaTyVar tv
+      | otherwise      = return False
+
+    -- type is a tv that is a meta var, but not a SigTV and not filled
+    isFlexibleTy ty
+      | Just tv <- tcGetTyVar_maybe ty = do {flexi <- isFlexible tv
                                             ; if flexi then return $ Just tv 
                                                        else return Nothing
                                             }
@@ -1329,15 +1493,15 @@ instantiateAndExtract eqs localsEmpty skolems
       = pprPanic "TcTyFuns.doInst: local eq: " (ppr ty)
     doInst swapped tv ty (Left cotv) eq
       = do { lookupTV <- lookupTcTyVar tv
-           ; uMeta swapped tv lookupTV ty cotv
+           ; bMeta swapped tv lookupTV ty cotv
            }
       where
-        -- Try to fill in a meta variable.  There is *no* need to consider
-        -- reorienting the underlying equality; `checkOrientation' makes sure
-        -- that we get variable-variable equalities only in the appropriate
-        -- orientation.
+        -- Try to create a binding for a meta variable.  There is *no* need to
+        -- consider reorienting the underlying equality; `checkOrientation'
+        -- makes sure that we get variable-variable equalities only in the
+        -- appropriate orientation.
         --
-        uMeta :: Bool                    -- is this a swapped equality?
+        bMeta :: Bool                    -- is this a swapped equality?
               -> TcTyVar                 -- tyvar to instantiate
               -> LookupTyVarResult       -- lookup result of that tyvar
               -> TcType                  -- to to instantiate tyvar with
@@ -1347,58 +1511,52 @@ instantiateAndExtract eqs localsEmpty skolems
                                          -- and hence, the equality must be kept
 
         -- meta variable has been filled already
-        -- => keep the equality
-        uMeta _swapped tv (IndirectTv fill_ty) ty _cotv
-          = do { traceTc $ 
-                   ptext (sLit "flexible") <+> ppr tv <+>
-                   ptext (sLit "already filled with") <+> ppr fill_ty <+>
-                   ptext (sLit "meant to fill with") <+> ppr ty
-               ; return $ Just eq
-               }
-
-        -- signature skolem
-        -- => cannot update (retain the equality)!
-        uMeta _swapped _tv (DoneTv (MetaTv (SigTv _) _)) _non_tv_ty _cotv
-          = return $ Just eq
+        -- => this should never happen due to the use of `isFlexible' above
+        bMeta _swapped tv (IndirectTv fill_ty) ty _cotv
+          = pprPanic "TcTyFuns.bMeta" $ 
+              ptext (sLit "flexible") <+> ppr tv <+>
+              ptext (sLit "already filled with") <+> ppr fill_ty <+>
+              ptext (sLit "meant to fill with") <+> ppr ty
 
         -- type variable meets type variable
         -- => `checkOrientation' already ensures that it is fine to instantiate
-        --    tv1 with tv2, but chase tv2's instantiations if necessary
+        --    tv1 with tv2, but chase tv2's instantiations if necessary, so that
+        --    we eventually can perform a kinds check in bMetaInst
         -- NB: tv's instantiations won't alter the orientation in which we
         --     want to instantiate as they either constitute a family 
         --     application or are themselves due to a properly oriented
         --     instantiation
-        uMeta swapped tv1 details1@(DoneTv (MetaTv _ ref)) ty@(TyVarTy tv2) cotv
+        bMeta swapped tv1 details1@(DoneTv (MetaTv _ _)) ty@(TyVarTy tv2) cotv
           = do { lookupTV2 <- lookupTcTyVar tv2
                ; case lookupTV2 of
-                   IndirectTv ty' -> 
-                     uMeta swapped tv1 details1 ty' cotv
-                   DoneTv _       -> 
-                     uMetaInst swapped tv1 ref ty cotv
+                   IndirectTv ty' -> bMeta swapped tv1 details1 ty' cotv
+                   DoneTv _       -> bMetaInst swapped tv1 ty cotv
                }
 
         -- updatable meta variable meets non-variable type
-        -- => occurs check, monotype check, and kinds match check, then update
-        uMeta swapped tv (DoneTv (MetaTv _ ref)) non_tv_ty cotv
-          = uMetaInst swapped tv ref non_tv_ty cotv
+        -- => occurs check, monotype check, and kinds match check, then bind
+        bMeta swapped tv (DoneTv (MetaTv _ _ref)) non_tv_ty cotv
+          = bMetaInst swapped tv non_tv_ty cotv
 
-        uMeta _ _ _ _ _ = panic "TcTyFuns.uMeta"
+        bMeta _ _ _ _ _ = panic "TcTyFuns.bMeta"
 
         -- We know `tv' can be instantiated; check that `ty' is alright for
-        -- instantiating `tv' with and then do it; otherwise, return the original
-        -- equality.
-        uMetaInst swapped tv ref ty cotv
+        -- instantiating `tv' with and then record a binding; we return the
+        -- original equality if it is cyclic through a synonym family
+        bMetaInst swapped tv ty cotv
           = do {   -- occurs + monotype check
                ; mb_ty' <- checkTauTvUpdate tv ty    
                              
                ; case mb_ty' of
                    Nothing  -> 
                      -- there may be a family in non_tv_ty due to an unzonked,
-                     -- but updated skolem for a local equality
+                     -- but updated skolem for a local equality 
+                     -- (cf `wantedToLocal')
                      return $ Just eq
                    Just ty' ->
-                     do { checkUpdateMeta swapped tv ref ty'  -- update meta var
-                        ; writeMetaTyVar cotv ty'             -- update co var
+                     do { checkKinds swapped tv ty'
+                        ; bindMetaTyVar tv ty'          -- bind meta var
+                        ; bindMetaTyVar cotv ty'        -- bind co var
                         ; return Nothing
                         }
                }
index 1e524b2..2d45334 100644 (file)
@@ -124,7 +124,8 @@ module TcType (
   typeKind, tidyKind,
 
   tyVarsOfType, tyVarsOfTypes, tyVarsOfPred, tyVarsOfTheta,
-  tcTyVarsOfType, tcTyVarsOfTypes, exactTyVarsOfType, exactTyVarsOfTypes,
+  tcTyVarsOfType, tcTyVarsOfTypes, tcTyVarsOfPred, exactTyVarsOfType,
+  exactTyVarsOfTypes, 
 
   pprKind, pprParendKind,
   pprType, pprParendType, pprTypeApp, pprTyThingCategory,