\begin{code}
module Inst (
- Inst,
+ Inst,
pprInstances, pprDictsTheta, pprDictsInFull, -- User error messages
showLIE, pprInst, pprInsts, pprInstInFull, -- Debugging messages
InstOrigin(..), InstLoc, pprInstLoc,
mkWantedCo, mkGivenCo,
- fromWantedCo, fromGivenCo,
- eitherEqInst, mkEqInst, mkEqInsts, mkWantedEqInst,
- finalizeEqInst, writeWantedCoercion,
+ isWantedCo, fromWantedCo, fromGivenCo, eqInstCoType,
+ mkIdEqInstCo, mkSymEqInstCo, mkLeftTransEqInstCo,
+ mkRightTransEqInstCo, mkAppEqInstCo,
+ eitherEqInst, mkEqInst, mkEqInsts, mkWantedEqInst, finalizeEqInst,
eqInstType, updateEqInstCoercion,
eqInstCoercion, eqInstTys
) where
\end{code}
+
Selection
~~~~~~~~~
\begin{code}
%* *
%************************************************************************
+Operations on EqInstCo.
+
\begin{code}
-mkGivenCo :: Coercion -> Either TcTyVar Coercion
+mkGivenCo :: Coercion -> EqInstCo
mkGivenCo = Right
-mkWantedCo :: TcTyVar -> Either TcTyVar Coercion
+mkWantedCo :: TcTyVar -> EqInstCo
mkWantedCo = Left
-fromGivenCo :: Either TcTyVar Coercion -> Coercion
+isWantedCo :: EqInstCo -> Bool
+isWantedCo (Left _) = True
+isWantedCo _ = False
+
+fromGivenCo :: EqInstCo -> Coercion
fromGivenCo (Right co) = co
fromGivenCo _ = panic "fromGivenCo: not a wanted coercion"
-fromWantedCo :: String -> Either TcTyVar Coercion -> TcTyVar
+fromWantedCo :: String -> EqInstCo -> TcTyVar
fromWantedCo _ (Left covar) = covar
-fromWantedCo msg _ = panic ("fromWantedCo: not a wanted coercion: " ++ msg)
+fromWantedCo msg _ =
+ panic ("fromWantedCo: not a wanted coercion: " ++ msg)
+
+eqInstCoType :: EqInstCo -> TcType
+eqInstCoType (Left cotv) = mkTyVarTy cotv
+eqInstCoType (Right co) = co
+\end{code}
+
+Coercion transformations on EqInstCo. These transformations work differently
+depending on whether a EqInstCo is for a wanted or local equality:
+
+ Local : apply the inverse of the specified coercion
+ Wanted: obtain a fresh coercion hole (meta tyvar) and update the old hole
+ to be the specified coercion applied to the new coercion hole
+
+\begin{code}
+-- Coercion transformation: co = id
+--
+mkIdEqInstCo :: EqInstCo -> Type -> TcM ()
+mkIdEqInstCo (Left cotv) t
+ = writeMetaTyVar cotv t
+mkIdEqInstCo (Right _) _
+ = return ()
+
+-- Coercion transformation: co = sym co'
+--
+mkSymEqInstCo :: EqInstCo -> (Type, Type) -> TcM EqInstCo
+mkSymEqInstCo (Left cotv) (ty1, ty2)
+ = do { cotv' <- newMetaCoVar ty1 ty2
+ ; writeMetaTyVar cotv (mkSymCoercion (TyVarTy cotv'))
+ ; return $ Left cotv'
+ }
+mkSymEqInstCo (Right co) _
+ = return $ Right (mkSymCoercion co)
+
+-- Coercion transformation: co = co' |> given_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)
+ ; return $ Left cotv'
+ }
+mkLeftTransEqInstCo (Right co) given_co _
+ = return $ Right (co `mkTransCoercion` mkSymCoercion given_co)
+
+-- Coercion transformation: co = given_co |> 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')
+ ; return $ Left cotv'
+ }
+mkRightTransEqInstCo (Right co) given_co _
+ = return $ Right (mkSymCoercion given_co `mkTransCoercion` co)
+
+-- Coercion transformation: co = col cor
+--
+mkAppEqInstCo :: EqInstCo -> (Type, Type) -> (Type, Type)
+ -> TcM (EqInstCo, EqInstCo)
+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))
+ ; return (Left cotv_l, Left cotv_r)
+ }
+mkAppEqInstCo (Right co) _ _
+ = return (Right $ mkLeftCoercion co, Right $ mkRightCoercion co)
+\end{code}
+
+Operations on entire EqInst.
+\begin{code}
eitherEqInst :: Inst -- given or wanted EqInst
-> (TcTyVar -> a) -- result if wanted
-> (Coercion -> a) -- result if given
Right co -> withGiven co
eitherEqInst i _ _ = pprPanic "eitherEqInst" (ppr i)
-mkEqInsts :: [PredType] -> [Either TcTyVar Coercion] -> TcM [Inst]
+mkEqInsts :: [PredType] -> [EqInstCo] -> TcM [Inst]
mkEqInsts preds cos = zipWithM mkEqInst preds cos
-mkEqInst :: PredType -> Either TcTyVar Coercion -> TcM Inst
+mkEqInst :: PredType -> EqInstCo -> TcM Inst
mkEqInst (EqPred ty1 ty2) co
= do { uniq <- newUnique
; src_span <- getSrcSpanM
; err_ctxt <- getErrCtxt
; let loc = InstLoc EqOrigin src_span err_ctxt
name = mkName uniq src_span
- inst = EqInst {tci_left = ty1, tci_right = ty2, tci_co = co, tci_loc = loc, tci_name = name}
+ inst = EqInst { tci_left = ty1
+ , tci_right = ty2
+ , tci_co = co
+ , tci_loc = loc
+ , tci_name = name
+ }
; return inst
}
- where mkName uniq src_span = mkInternalName uniq (mkVarOcc "co") src_span
+ where
+ mkName uniq src_span = mkInternalName uniq (mkVarOcc "co") src_span
mkEqInst pred _ = pprPanic "mkEqInst" (ppr pred)
mkWantedEqInst :: PredType -> TcM Inst
}
mkWantedEqInst pred = pprPanic "mkWantedEqInst" (ppr pred)
--- type inference:
--- We want to promote the wanted EqInst to a given EqInst
--- in the signature context.
--- This means we have to give the coercion a name
--- and fill it in as its own name.
-finalizeEqInst
- :: Inst -- wanted
- -> TcM Inst -- given
-finalizeEqInst wanted@(EqInst {tci_left = ty1, tci_right = ty2, tci_name = name})
- = do { let var = Var.mkCoVar name (PredTy $ EqPred ty1 ty2)
- ; writeWantedCoercion wanted (TyVarTy var)
- ; let given = wanted { tci_co = mkGivenCo $ TyVarTy var }
- ; return given
- }
-finalizeEqInst i = pprPanic "finalizeEqInst" (ppr i)
+-- Turn a wanted into a local EqInst (needed during type inference for
+-- signatures)
+--
+-- * Give it a name and change the coercion around.
+--
+finalizeEqInst :: Inst -- wanted
+ -> TcM Inst -- given
+finalizeEqInst wanted@(EqInst{tci_left = ty1, tci_right = ty2, tci_name = name})
+ = do { let var = Var.mkCoVar name (PredTy $ EqPred ty1 ty2)
+
+ -- fill the coercion hole
+ ; let cotv = fromWantedCo "writeWantedCoercion" $ tci_co wanted
+ ; writeMetaTyVar cotv (TyVarTy var)
+
+ -- set the new coercion
+ ; let given = wanted { tci_co = mkGivenCo $ TyVarTy var }
+ ; return given
+ }
-writeWantedCoercion
- :: Inst -- wanted EqInst
- -> Coercion -- coercion to fill the hole with
- -> TcM ()
-writeWantedCoercion wanted co
- = do { let cotv = fromWantedCo "writeWantedCoercion" $ tci_co wanted
- ; writeMetaTyVar cotv co
- }
+finalizeEqInst i = pprPanic "finalizeEqInst" (ppr i)
eqInstType :: Inst -> TcType
eqInstType inst = eitherEqInst inst mkTyVarTy id
-eqInstCoercion :: Inst -> Either TcTyVar Coercion
+eqInstCoercion :: Inst -> EqInstCo
eqInstCoercion = tci_co
eqInstTys :: Inst -> (TcType, TcType)
eqInstTys inst = (tci_left inst, tci_right inst)
-updateEqInstCoercion :: (Either TcTyVar Coercion -> Either TcTyVar Coercion) -> Inst -> Inst
+updateEqInstCoercion :: (EqInstCo -> EqInstCo) -> Inst -> Inst
updateEqInstCoercion f inst = inst {tci_co = f $ tci_co inst}
\end{code}
\begin{code}
module TcTyFuns (
- tcNormaliseFamInst,
+ -- type normalisation wrt to toplevel equalities only
+ tcNormaliseFamInst,
- normaliseGivenEqs, normaliseGivenDicts,
- normaliseWantedEqs, normaliseWantedDicts,
+ -- normalisation and solving of equalities
+ EqConfig,
+ normaliseEqs, propagateEqs, finaliseEqs, normaliseDicts,
+
+ -- errors
+ misMatchMsg, failWithMisMatch,
+
+ -- DEPRECATED: interface for the ICFP'08 algorithm
+ normaliseGivenEqs, normaliseGivenDicts,
+ normaliseWantedEqs, normaliseWantedDicts,
- -- errors
- misMatchMsg, failWithMisMatch
) where
import TyCon
import HsSyn
import VarEnv
+import VarSet
import Var
import Name
import Bag
%************************************************************************
%* *
- Normalisation of types
+ Normalisation of types wrt toplevel equality schemata
%* *
%************************************************************************
then co : ty ~ ty'
\begin{code}
+-- |Normalise the given type as far as possible with toplevel equalities.
+-- This results in a coercion witnessing the type equality, in addition to the
+-- normalised type.
+--
tcNormaliseFamInst :: TcType -> TcM (CoercionI, TcType)
tcNormaliseFamInst = tcGenericNormaliseFamInst tcUnfoldSynFamInst
tcNormaliseFamInstPred = tcGenericNormaliseFamInstPred tcUnfoldSynFamInst
\end{code}
+%************************************************************************
+%* *
+ Equality Configurations
+%* *
+%************************************************************************
+
+We maintain normalised equalities together with the skolems introduced as
+intermediates during flattening of equalities.
+
+!!!TODO: Do we really need to keep track of the skolem variables? They are at
+the moment not used in instantiateAndExtract, but it is hard to say until we
+know exactly how finalisation will fianlly look like.
+
+\begin{code}
+-- |Configuration of normalised equalities used during solving.
+--
+data EqConfig = EqConfig { eqs :: [RewriteInst]
+ , skolems :: TyVarSet
+ }
+
+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}
+\end{code}
+
+The set of operations on an equality configuration. We obtain the initialise
+configuration by normalisation ('normaliseEqs'), solve the equalities by
+propagation ('propagateEqs'), and eventually finalise the configuration when
+no further propoagation is possible.
+
+!!!TODO: Eventually, normalisation of dictionaries and dictionary
+simplification should be included in propagation.
+
+\begin{code}
+-- |Turn a set of equalities into an equality configuration for solving.
+--
+-- Precondition: The Insts are zonked.
+--
+normaliseEqs :: [Inst] -> TcM EqConfig
+normaliseEqs eqs
+ = do { (eqss, skolemss) <- mapAndUnzipM normEqInst eqs
+ ; return $ EqConfig { eqs = concat eqss
+ , skolems = unionVarSets skolemss
+ }
+ }
+
+-- |Solves the equalities as far as possible by applying propagation rules.
+--
+propagateEqs :: EqConfig -> TcM EqConfig
+propagateEqs eqCfg@(EqConfig {eqs = todoEqs})
+ = propagate todoEqs (eqCfg {eqs = []})
+
+-- |Finalise a set of equalities after propagation. The 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 returned set of instances are all residual wanteds.
+--
+finaliseEqs :: EqConfig -> TcM ([Inst], Bool)
+finaliseEqs (EqConfig {eqs = eqs, skolems = skolems})
+ = do { eqs' <- substitute eqs
+ ; instantiateAndExtract eqs' skolems
+ }
+
+-- |Normalise a set of class instances under a given equality configuration.
+-- Both the class instances and the equality configuration may change. The
+-- function returns 'Nothing' if neither changes.
+--
+normaliseDicts :: EqConfig -> [Inst] -> TcM (Maybe (EqConfig, [Inst]))
+normaliseDicts = error "TcTyFuns.normaliseDicts"
+\end{code}
+
+
+%************************************************************************
+%* *
+ Normalisation of equalities
+%* *
+%************************************************************************
+
+A normal equality is a properly oriented equality with associated coercion
+that contains at most one family equality (in its left-hand side) is oriented
+such that it may be used as a reqrite rule. It has one of the following two
+forms:
+
+(1) co :: F t1..tn ~ t (family equalities)
+(2) co :: x ~ t (variable equalities)
+
+Variable equalities fall again in two classes:
+
+(2a) co :: x ~ t, where t is *not* a variable, or
+(2b) co :: x ~ y, where x > y.
+
+The types t, t1, ..., tn may not contain any occurrences of synonym
+families. Moreover, in Forms (2) & (3), the left-hand side may not occur in
+the right-hand side, and the relation x > y is an arbitrary, but total order
+on type variables
+
+!!!TODO: We may need to keep track of swapping for error messages (and to
+re-orient on finilisation).
+
+\begin{code}
+data RewriteInst
+ = RewriteVar -- Form (2) above
+ { rwi_var :: TyVar -- may be rigid or flexible
+ , rwi_right :: TcType -- contains no synonym family applications
+ , rwi_co :: EqInstCo -- the wanted or given coercion
+ , rwi_loc :: InstLoc
+ , rwi_name :: Name -- no semantic significance (cf. TcRnTypes.EqInst)
+ }
+ | RewriteFam -- Forms (1) above
+ { rwi_fam :: TyCon -- synonym family tycon
+ , rwi_args :: [Type] -- contain no synonym family applications
+ , rwi_right :: TcType -- contains no synonym family applications
+ , rwi_co :: EqInstCo -- the wanted or given coercion
+ , rwi_loc :: InstLoc
+ , rwi_name :: Name -- no semantic significance (cf. TcRnTypes.EqInst)
+ }
+
+isWantedRewriteInst :: RewriteInst -> Bool
+isWantedRewriteInst = isWantedCo . rwi_co
+
+rewriteInstToInst :: RewriteInst -> Inst
+rewriteInstToInst eq@(RewriteVar {rwi_var = tv})
+ = EqInst
+ { tci_left = mkTyVarTy tv
+ , tci_right = rwi_right eq
+ , tci_co = rwi_co eq
+ , tci_loc = rwi_loc eq
+ , tci_name = rwi_name eq
+ }
+rewriteInstToInst eq@(RewriteFam {rwi_fam = fam, rwi_args = args})
+ = EqInst
+ { tci_left = mkTyConApp fam args
+ , tci_right = rwi_right eq
+ , tci_co = rwi_co eq
+ , tci_loc = rwi_loc eq
+ , tci_name = rwi_name eq
+ }
+\end{code}
+
+The following functions turn an arbitrary equality into a set of normal
+equalities.
+
+\begin{code}
+normEqInst :: Inst -> TcM ([RewriteInst], TyVarSet)
+normEqInst inst
+ = ASSERT( isEqInst inst )
+ go ty1 ty2 (eqInstCoercion inst)
+ where
+ (ty1, ty2) = eqInstTys inst
+
+ -- look through synonyms
+ go ty1 ty2 co | Just ty1' <- tcView ty1 = go ty1' ty2 co
+ go ty1 ty2 co | Just ty2' <- tcView ty2 = go ty1 ty2' co
+
+ -- left-to-right rule with type family head
+ go (TyConApp con args) ty2 co
+ | isOpenSynTyCon con
+ = mkRewriteFam con args ty2 co
+
+ -- right-to-left rule with type family head
+ go ty1 ty2@(TyConApp con args) co
+ | isOpenSynTyCon con
+ = do { co' <- mkSymEqInstCo co (ty2, ty1)
+ ; mkRewriteFam con args ty1 co'
+ }
+
+ -- 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
+ ; let ty12_eqs = ty1_eqs ++ ty2_eqs
+ rewriteCo = co1 `mkTransCoercion` mkSymCoercion co2
+ eqTys = (ty1', ty2')
+ ; (co', ty12_eqs') <- adjustCoercions co rewriteCo eqTys ty12_eqs
+ ; eqs <- checkOrientation ty1' ty2' co' inst
+ ; return $ (eqs ++ ty12_eqs',
+ ty1_skolems `unionVarSet` ty2_skolems)
+ }
+
+ mkRewriteFam con args ty2 co
+ = do { (args', cargs, args_eqss, args_skolemss)
+ <- mapAndUnzip4M (flattenType inst) args
+ ; (ty2', co2, ty2_eqs, ty2_skolems) <- flattenType inst ty2
+ ; let rewriteCo = mkTyConApp con cargs `mkTransCoercion`
+ mkSymCoercion co2
+ all_eqs = concat args_eqss ++ ty2_eqs
+ eqTys = (mkTyConApp con args', ty2')
+ ; (co', all_eqs') <- adjustCoercions co rewriteCo eqTys all_eqs
+ ; let thisRewriteFam = RewriteFam
+ { rwi_fam = con
+ , rwi_args = args'
+ , rwi_right = ty2'
+ , rwi_co = co'
+ , rwi_loc = tci_loc inst
+ , rwi_name = tci_name inst
+ }
+ ; return $ (thisRewriteFam : all_eqs',
+ unionVarSets (ty2_skolems:args_skolemss))
+ }
+
+checkOrientation :: Type -> Type -> EqInstCo -> Inst -> TcM [RewriteInst]
+-- Performs the occurs check, decomposition, and proper orientation
+-- (returns a singleton, or an empty list in case of a trivial equality)
+-- NB: We cannot assume that the two types already have outermost type
+-- synonyms expanded due to the recursion in the case of type applications.
+checkOrientation ty1 ty2 co inst
+ = go ty1 ty2
+ where
+ -- look through synonyms
+ go ty1 ty2 | Just ty1' <- tcView ty1 = go ty1' ty2
+ go ty1 ty2 | Just ty2' <- tcView ty2 = go ty1 ty2'
+
+ -- identical types => trivial
+ go ty1 ty2
+ | ty1 `tcEqType` ty2
+ = do { mkIdEqInstCo co ty1
+ ; return []
+ }
+
+ -- two tvs, left greater => unchanged
+ go ty1@(TyVarTy tv1) ty2@(TyVarTy tv2)
+ | tv1 > tv2
+ = mkRewriteVar tv1 ty2 co
+
+ -- two tvs, right greater => swap
+ | otherwise
+ = do { co' <- mkSymEqInstCo co (ty2, ty1)
+ ; mkRewriteVar tv2 ty1 co'
+ }
+
+ -- only lhs is a tv => unchanged
+ go ty1@(TyVarTy tv1) ty2
+ | ty1 `tcPartOfType` ty2 -- occurs check!
+ = occurCheckErr ty1 ty2
+ | otherwise
+ = mkRewriteVar tv1 ty2 co
+
+ -- only rhs is a tv => swap
+ go ty1 ty2@(TyVarTy tv2)
+ | ty2 `tcPartOfType` ty1 -- occurs check!
+ = occurCheckErr ty2 ty1
+ | otherwise
+ = do { co' <- mkSymEqInstCo co (ty2, ty1)
+ ; mkRewriteVar tv2 ty1 co'
+ }
+
+ -- type applications => decompose
+ go ty1 ty2
+ | Just (ty1_l, ty1_r) <- repSplitAppTy_maybe ty1 -- won't split fam apps
+ , Just (ty2_l, ty2_r) <- repSplitAppTy_maybe ty2
+ = do { (co_l, co_r) <- mkAppEqInstCo co (ty1_l, ty2_l) (ty1_r, ty2_r)
+ ; eqs_l <- checkOrientation ty1_l ty2_l co_l inst
+ ; eqs_r <- checkOrientation ty1_r ty2_r co_r inst
+ ; return $ eqs_l ++ eqs_r
+ }
+-- !!!TODO: would be more efficient to handle the FunApp and the data
+-- constructor application explicitly.
+
+ -- inconsistency => type error
+ go ty1 ty2
+ = ASSERT( (not . isForAllTy $ ty1) && (not . isForAllTy $ ty2) )
+ eqInstMisMatch inst
+
+ mkRewriteVar tv ty co = return [RewriteVar
+ { rwi_var = tv
+ , rwi_right = ty
+ , rwi_co = co
+ , rwi_loc = tci_loc inst
+ , rwi_name = tci_name inst
+ }]
+
+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
+-- Removes all family synonyms from a type by moving them into extra equalities
+flattenType inst ty
+ = go ty
+ where
+ -- look through synonyms
+ go ty | Just ty' <- tcView ty = go ty'
+
+ -- type family application => flatten to "id :: F t1'..tn' ~ alpha"
+ go ty@(TyConApp con args)
+ | isOpenSynTyCon con
+ = do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
+ ; alpha <- newFlexiTyVar (typeKind ty)
+ ; let alphaTy = mkTyVarTy alpha
+ ; cotv <- newMetaCoVar (mkTyConApp con args') alphaTy
+ ; let thisRewriteFam = RewriteFam
+ { rwi_fam = con
+ , rwi_args = args'
+ , rwi_right = alphaTy
+ , rwi_co = mkWantedCo cotv
+ , rwi_loc = tci_loc inst
+ , rwi_name = tci_name inst
+ }
+ ; return (alphaTy,
+ mkTyConApp con cargs `mkTransCoercion` mkTyVarTy cotv,
+ thisRewriteFam : concat args_eqss,
+ unionVarSets args_skolemss `extendVarSet` alpha)
+ } -- adding new unflatten var inst
+
+ -- data constructor application => flatten subtypes
+ -- NB: Special cased for efficiency - could be handled as type application
+ go (TyConApp con args)
+ = do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
+ ; return (mkTyConApp con args',
+ mkTyConApp con cargs,
+ concat args_eqss,
+ unionVarSets args_skolemss)
+ }
+
+ -- function type => flatten subtypes
+ -- NB: Special cased for efficiency - could be handled as type application
+ go (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
+ ; return (mkFunTy ty_l' ty_r',
+ mkFunTy co_l co_r,
+ eqs_l ++ eqs_r,
+ skolems_l `unionVarSet` skolems_r)
+ }
+
+ -- type application => flatten subtypes
+ go (AppTy ty_l ty_r)
+-- | Just (ty_l, ty_r) <- repSplitAppTy_maybe ty
+ = do { (ty_l', co_l, eqs_l, skolems_l) <- go ty_l
+ ; (ty_r', co_r, eqs_r, skolems_r) <- go ty_r
+ ; return (mkAppTy ty_l' ty_r',
+ mkAppTy co_l co_r,
+ eqs_l ++ eqs_r,
+ skolems_l `unionVarSet` skolems_r)
+ }
+
+ -- free of type families => leave as is
+ go ty
+ = ASSERT( not . isForAllTy $ ty )
+ return (ty, ty, [] , emptyVarSet)
+
+adjustCoercions :: EqInstCo -- coercion of original equality
+ -> Coercion -- coercion witnessing the rewrite
+ -> (Type, Type) -- type sof flattened equality
+ -> [RewriteInst] -- equalities from flattening
+ -> TcM (EqInstCo, -- coercion for flattened equality
+ [RewriteInst]) -- final equalities from flattening
+-- Depending on whether we flattened a local or wanted equality, that equality's
+-- coercion and that of the new ones are adjusted
+adjustCoercions co rewriteCo eqTys all_eqs
+ | isWantedCo co
+ = do { co' <- mkRightTransEqInstCo co rewriteCo eqTys
+ ; return (co', all_eqs)
+ }
+ | otherwise
+ = return (co, map wantedToLocal all_eqs)
+ where
+ wantedToLocal eq = eq {rwi_co = mkGivenCo (rwi_right eq)}
+\end{code}
+
+
+%************************************************************************
+%* *
+ Propagation of equalities
+%* *
+%************************************************************************
+
+Apply the propagation rules exhaustively.
+
+\begin{code}
+propagate :: [RewriteInst] -> EqConfig -> TcM EqConfig
+propagate [] eqCfg = return eqCfg
+propagate (eq:eqs) eqCfg
+ = do { optEqs <- applyTop eq
+ ; case optEqs of
+
+ -- Top applied to 'eq' => retry with new equalities
+ Just (eqs2, skolems2)
+ -> propagate (eqs2 ++ eqs) (eqCfg `addSkolems` skolems2)
+
+ -- 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)
+ }
+ }
+
+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
+ ; return (newEqs_t ++ newEqs_r ++ unchangedEqs_t,
+ eqConfig {eqs = unchangedEqs_r}
+ `addSkolems` (skolems_t `unionVarSet` skolems_r))
+ }
+
+mapSubstRules :: RewriteInst -- try substituting this equality
+ -> [RewriteInst] -- into these equalities
+ -> TcM ([RewriteInst], [RewriteInst], TyVarSet)
+mapSubstRules eq eqs
+ = do { (newEqss, unchangedEqss, skolemss) <- mapAndUnzip3M (substRules eq) eqs
+ ; return (concat newEqss, concat unchangedEqss, unionVarSets skolemss)
+ }
+ where
+ substRules eq1 eq2
+ = do { -- try the SubstFam rule
+ optEqs <- applySubstFam eq1 eq2
+ ; case optEqs of
+ Just (eqs, skolems) -> return (eqs, [], skolems)
+ Nothing -> do
+ { -- try the SubstVarVar rule
+ optEqs <- applySubstVarVar eq1 eq2
+ ; case optEqs of
+ Just (eqs, skolems) -> return (eqs, [], skolems)
+ Nothing -> do
+ { -- try the SubstVarFam rule
+ optEqs <- applySubstVarFam eq1 eq2
+ ; case optEqs of
+ Just eq -> return ([eq], [], emptyVarSet)
+ Nothing -> return ([], [eq2], emptyVarSet)
+ -- if no rule matches, we return the equlity we tried to
+ -- substitute into unchanged
+ }}}
+\end{code}
+
+Attempt to apply the Top rule. The rule is
+
+ co :: F t1..tn ~ t
+ =(Top)=>
+ co' :: [s1/x1, .., sm/xm]s ~ t with co = g s1..sm |> co'
+
+where g :: forall x1..xm. F u1..um ~ s and [s1/x1, .., sm/xm]u1 == t1.
+
+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 eq@(RewriteFam {rwi_fam = fam, rwi_args = args})
+ = do { optTyCo <- tcUnfoldSynFamInst (TyConApp fam args)
+ ; case optTyCo of
+ Nothing -> return Nothing
+ Just (lhs, rewrite_co)
+ -> do { co' <- mkRightTransEqInstCo co rewrite_co (lhs, rhs)
+ ; let eq' = EqInst
+ { tci_left = lhs
+ , tci_right = rhs
+ , tci_co = co'
+ , tci_loc = rwi_loc eq
+ , tci_name = rwi_name eq
+ }
+ ; liftM Just $ normEqInst eq'
+ }
+ }
+ where
+ co = rwi_co eq
+ rhs = rwi_right eq
+
+applyTop _ = return Nothing
+\end{code}
+
+Attempt to apply the SubstFam rule. The rule is
+
+ co1 :: F t1..tn ~ t & co2 :: F t1..tn ~ s
+ =(SubstFam)=>
+ co1 :: F t1..tn ~ t & co2' :: t ~ s with co2 = co1 |> co2'
+
+where co1 may be a wanted only if co2 is a wanted, too.
+
+Returns Nothing if the rule could not be applied. Otherwise, the equality
+co2' is normalised and a list of the normal equalities is returned. (The
+equality co1 is not returned as it remain unaltered.)
+
+\begin{code}
+applySubstFam :: RewriteInst
+ -> RewriteInst
+ -> TcM (Maybe ([RewriteInst], TyVarSet))
+applySubstFam eq1@(RewriteFam {rwi_fam = fam1, rwi_args = args1})
+ eq2@(RewriteFam {rwi_fam = fam2, rwi_args = args2})
+ | fam1 == fam2 && tcEqTypes args1 args2 &&
+ (isWantedRewriteInst eq2 || not (isWantedRewriteInst eq1))
+-- !!!TODO: tcEqTypes is insufficient as it does not look through type synonyms
+-- !!!Check whether anything breaks by making tcEqTypes look through synonyms.
+-- !!!Should be ok and we don't want three type equalities.
+ = do { co2' <- mkRightTransEqInstCo co2 co1 (lhs, rhs)
+ ; let eq2' = EqInst
+ { tci_left = lhs
+ , tci_right = rhs
+ , tci_co = co2'
+ , tci_loc = rwi_loc eq2
+ , tci_name = rwi_name eq2
+ }
+ ; liftM Just $ normEqInst eq2'
+ }
+ where
+ lhs = rwi_right eq1
+ rhs = rwi_right eq2
+ co1 = eqInstCoType (rwi_co eq1)
+ co2 = rwi_co eq2
+applySubstFam _ _ = return Nothing
+\end{code}
+
+Attempt to apply the SubstVarVar rule. The rule is
+
+ co1 :: x ~ t & co2 :: x ~ s
+ =(SubstVarVar)=>
+ co1 :: x ~ t & co2' :: t ~ s with co2 = co1 |> co2'
+
+where co1 may be a wanted only if co2 is a wanted, too.
+
+Returns Nothing if the rule could not be applied. Otherwise, the equality
+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 eq1@(RewriteVar {rwi_var = tv1})
+ eq2@(RewriteVar {rwi_var = tv2})
+ | tv1 == tv2 &&
+ (isWantedRewriteInst eq2 || not (isWantedRewriteInst eq1))
+ = do { co2' <- mkRightTransEqInstCo co2 co1 (lhs, rhs)
+ ; let eq2' = EqInst
+ { tci_left = lhs
+ , tci_right = rhs
+ , tci_co = co2'
+ , tci_loc = rwi_loc eq2
+ , tci_name = rwi_name eq2
+ }
+ ; liftM Just $ normEqInst eq2'
+ }
+ where
+ lhs = rwi_right eq1
+ rhs = rwi_right eq2
+ co1 = eqInstCoType (rwi_co eq1)
+ co2 = rwi_co eq2
+applySubstVarVar _ _ = return Nothing
+\end{code}
+
+Attempt to apply the SubstVarFam rule. The rule is
+
+ co1 :: x ~ t & co2 :: F s1..sn ~ s
+ =(SubstVarFam)=>
+ co1 :: x ~ t & co2' :: [t/x](F s1..sn) ~ s
+ with co2 = [co1/x](F s1..sn) |> co2'
+
+where x occurs in F s1..sn. (co1 may be local or wanted.)
+
+Returns Nothing if the rule could not be applied. Otherwise, the equality
+co2' is returned. (The equality co1 is not returned as it remain unaltered.)
+
+\begin{code}
+applySubstVarFam :: RewriteInst -> RewriteInst -> TcM (Maybe RewriteInst)
+applySubstVarFam eq1@(RewriteVar {rwi_var = tv1})
+ eq2@(RewriteFam {rwi_fam = fam2, rwi_args = args2})
+ | tv1 `elemVarSet` tyVarsOfTypes args2
+ = do { let co1Subst = substTyWith [tv1] [co1] (mkTyConApp fam2 args2)
+ args2' = substTysWith [tv1] [rhs1] args2
+ lhs2 = mkTyConApp fam2 args2'
+ ; co2' <- mkRightTransEqInstCo co2 co1Subst (lhs2, rhs2)
+ ; return $ Just (eq2 {rwi_args = args2', rwi_co = co2'})
+ }
+ where
+ rhs1 = rwi_right eq1
+ rhs2 = rwi_right eq2
+ co1 = eqInstCoType (rwi_co eq1)
+ co2 = rwi_co eq2
+applySubstVarFam _ _ = return Nothing
+\end{code}
+
+
+%************************************************************************
+%* *
+ Finalisation of equalities
+%* *
+%************************************************************************
+
+Exhaustive substitution of all variable equalities of the form co :: x ~ t
+(both local and wanted) into the left-hand sides 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.
+
+NB: Gievn that we apply the substitution corresponding to a single equality
+exhaustively, before turning to the next, and because we eliminate recursive
+eqaulities, all opportunities for subtitution will have been exhausted after
+we have considered each equality once.
+
+\begin{code}
+substitute :: [RewriteInst] -> TcM [RewriteInst]
+substitute eqs = subst eqs []
+ where
+ subst [] res = return res
+ subst (eq:eqs) res
+ = do { eqs' <- mapM (substOne eq) eqs
+ ; res' <- mapM (substOne eq) res
+ ; subst eqs' (eq:res')
+ }
+
+ -- apply [ty/tv] to left-hand side of eq2
+ substOne (RewriteVar {rwi_var = tv, rwi_right = ty, rwi_co = co}) eq2
+ = do { let co1Subst = mkSymCoercion $
+ substTyWith [tv] [eqInstCoType co] (rwi_right eq2)
+ right2' = substTyWith [tv] [ty] (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} | tv2 `elemVarSet` tyVarsOfType ty
+ -> occurCheckErr left2 right2'
+ _ -> return $ eq2 {rwi_right = right2', rwi_co = co2'}
+ }
+
+ -- changed
+ substOne _ eq2
+ = return eq2
+\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 was performed.
+
+\begin{code}
+instantiateAndExtract :: [RewriteInst] -> TyVarSet -> TcM ([Inst], Bool)
+instantiateAndExtract eqs _skolems
+ = do { let wanteds = filter (isWantedCo . rwi_co) eqs
+ ; wanteds' <- mapM inst wanteds
+ ; let residuals = catMaybes wanteds'
+ improved = length wanteds /= length residuals
+ ; return (map rewriteInstToInst residuals, improved)
+ }
+ where
+ inst eq@(RewriteVar {rwi_var = tv1, rwi_right = ty2, rwi_co = co})
+
+ -- co :: alpha ~ t
+ | isMetaTyVar tv1
+ = doInst tv1 ty2 co eq
+
+ -- co :: a ~ alpha
+ | Just tv2 <- tcGetTyVar_maybe ty2
+ , isMetaTyVar tv2
+ = doInst tv2 (mkTyVarTy tv1) co eq
+
+ inst eq = return $ Just eq
+
+ doInst _ _ (Right ty) _eq = pprPanic "TcTyFuns.doInst: local eq: "
+ (ppr ty)
+ doInst tv ty (Left cotv) eq = do { lookupTV <- lookupTcTyVar tv
+ ; uMeta False tv lookupTV ty cotv
+ }
+ where
+ -- meta variable has been filled already
+ -- => panic (all equalities should have been zonked on normalisation)
+ uMeta _swapped _tv (IndirectTv _) _ty _cotv
+ = panic "TcTyFuns.uMeta: expected zonked equalities"
+
+ -- type variable meets type variable
+ -- => check that tv2 hasn't been updated yet and choose which to update
+ uMeta swapped tv1 (DoneTv details1) (TyVarTy tv2) cotv
+ | tv1 == tv2
+ = panic "TcTyFuns.uMeta: normalisation shouldn't allow x ~ x"
+
+ | otherwise
+ = do { lookupTV2 <- lookupTcTyVar tv2
+ ; case lookupTV2 of
+ IndirectTv ty ->
+ uMeta swapped tv1 (DoneTv details1) ty cotv
+ DoneTv details2 ->
+ uMetaVar swapped tv1 details1 tv2 details2 cotv
+ }
+
+ ------ Beyond this point we know that ty2 is not a type variable
+
+ -- signature skolem meets non-variable type
+ -- => cannot update (retain the equality)!
+ uMeta _swapped _tv (DoneTv (MetaTv (SigTv _) _)) _non_tv_ty _cotv
+ = return $ Just eq
+
+ -- 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
+ = do { -- occurs + monotype check
+ ; mb_ty' <- checkTauTvUpdate tv non_tv_ty
+
+ ; case mb_ty' of
+ Nothing ->
+ -- normalisation shouldn't leave families in non_tv_ty
+ panic "TcTyFuns.uMeta: unexpected synonym family"
+ Just ty' ->
+ do { checkUpdateMeta swapped tv ref ty' -- update meta var
+ ; writeMetaTyVar cotv ty' -- update co var
+ ; return Nothing
+ }
+ }
+
+ uMeta _ _ _ _ _ = panic "TcTyFuns.uMeta"
+
+ -- uMetaVar: unify two type variables
+ -- meta variable meets skolem
+ -- => just update
+ uMetaVar swapped tv1 (MetaTv _ ref) tv2 (SkolemTv _) cotv
+ = do { checkUpdateMeta swapped tv1 ref (mkTyVarTy tv2)
+ ; writeMetaTyVar cotv (mkTyVarTy tv2)
+ ; return Nothing
+ }
+
+ -- meta variable meets meta variable
+ -- => be clever about which of the two to update
+ -- (from TcUnify.uUnfilledVars minus boxy stuff)
+ uMetaVar swapped tv1 (MetaTv info1 ref1) tv2 (MetaTv info2 ref2) cotv
+ = do { case (info1, info2) of
+ -- Avoid SigTvs if poss
+ (SigTv _, _ ) | k1_sub_k2 -> update_tv2
+ (_, SigTv _) | k2_sub_k1 -> update_tv1
+
+ (_, _) | k1_sub_k2 -> if k2_sub_k1 && nicer_to_update_tv1
+ then update_tv1 -- Same kinds
+ else update_tv2
+ | k2_sub_k1 -> update_tv1
+ | otherwise -> kind_err
+ -- Update the variable with least kind info
+ -- See notes on type inference in Kind.lhs
+ -- The "nicer to" part only applies if the two kinds are the same,
+ -- so we can choose which to do.
+
+ ; writeMetaTyVar cotv (mkTyVarTy tv2)
+ ; return Nothing
+ }
+ where
+ -- Kinds should be guaranteed ok at this point
+ update_tv1 = updateMeta tv1 ref1 (mkTyVarTy tv2)
+ update_tv2 = updateMeta tv2 ref2 (mkTyVarTy tv1)
+
+ kind_err = addErrCtxtM (unifyKindCtxt swapped tv1 (mkTyVarTy tv2)) $
+ unifyKindMisMatch k1 k2
+
+ k1 = tyVarKind tv1
+ k2 = tyVarKind tv2
+ k1_sub_k2 = k1 `isSubKind` k2
+ k2_sub_k1 = k2 `isSubKind` k1
+
+ nicer_to_update_tv1 = isSystemName (Var.varName tv1)
+ -- Try to update sys-y type variables in preference to ones
+ -- gotten (say) by instantiating a polymorphic function with
+ -- a user-written type sig
+
+ uMetaVar _ _ _ _ _ _ = panic "uMetaVar"
+\end{code}
+
+
+
+==================== CODE FOR THE OLD ICFP'08 ALGORITHM ======================
+
An elementary rewrite is a properly oriented equality with associated coercion
that has one of the following two forms: