[commit: ghc] master: Fix substitution but in liftCoSubst (Trac #7973) (8c846f7)
Simon Peyton Jones
simonpj at microsoft.com
Mon Jun 10 12:05:20 CEST 2013
Repository : http://darcs.haskell.org/ghc.git/
On branch : master
https://github.com/ghc/ghc/commit/8c846f714223c33adef76e6072ba94d3e33b7e97
>---------------------------------------------------------------
commit 8c846f714223c33adef76e6072ba94d3e33b7e97
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date: Mon Jun 10 11:04:09 2013 +0100
Fix substitution but in liftCoSubst (Trac #7973)
Iavor uncovered this subtle omission in liftCoSubst. The problem and its
solution are desribed in
Note [Substituting kinds in liftCoSubst]
>---------------------------------------------------------------
compiler/types/Coercion.lhs | 82 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 79 insertions(+), 3 deletions(-)
diff --git a/compiler/types/Coercion.lhs b/compiler/types/Coercion.lhs
index 02e2783..59b0102 100644
--- a/compiler/types/Coercion.lhs
+++ b/compiler/types/Coercion.lhs
@@ -1115,7 +1115,53 @@ lookupCoVar (CvSubst _ _ cenv) v = lookupVarEnv cenv v
%* *
%************************************************************************
+Note [Lifting coercions over types: liftCoSubst]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The KPUSH rule deals with this situation
+ data T a = MkK (a -> Maybe a)
+ g :: T t1 ~ K t2
+ x :: t1 -> Maybe t1
+
+ case (K @t1 x) |> g of
+ K (y:t2 -> Maybe t2) -> rhs
+
+We want to push the coercion inside the constructor application.
+So we do this
+
+ g' :: t1~t2 = Nth 0 g
+
+ case K @t2 (x |> g' -> Maybe g') of
+ K (y:t2 -> Maybe t2) -> rhs
+
+The crucial operation is that we
+ * take the type of K's argument: a -> Maybe a
+ * and substitute g' for a
+thus giving *coercion*. This is what liftCoSubst does.
+
+Note [Substituting kinds in liftCoSubst]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We need to take care with kind polymorphism. Suppose
+ K :: forall k (a:k). (forall b:k. a -> b) -> T k a
+
+Now given (K @kk1 @ty1 v) |> g) where
+ g :: T kk1 ty1 ~ T kk2 ty2
+we want to compute
+ (forall b:k a->b) [ Nth 0 g/k, Nth 1 g/a ]
+Notice that we MUST substitute for 'k'; this happens in
+liftCoSubstTyVarBndr. But what should we substitute?
+We need to take b's kind 'k' and return a Kind, not a Coercion!
+
+Happily we can do this because we know that all kind coercions
+((Nth 0 g) in this case) are Refl. So we need a special purpose
+ subst_kind: LiftCoSubst -> Kind -> Kind
+that expects a Refl coercion (or something equivalent to Refl)
+when it looks up a kind variable.
+
\begin{code}
+-- ----------------------------------------------------
+-- See Note [Lifting coercions over types: liftCoSubst]
+-- ----------------------------------------------------
+
data LiftCoSubst = LCS InScopeSet LiftCoEnv
type LiftCoEnv = VarEnv Coercion
@@ -1158,14 +1204,44 @@ liftCoSubstTyVar :: LiftCoSubst -> TyVar -> Maybe Coercion
liftCoSubstTyVar (LCS _ cenv) tv = lookupVarEnv cenv tv
liftCoSubstTyVarBndr :: LiftCoSubst -> TyVar -> (LiftCoSubst, TyVar)
-liftCoSubstTyVarBndr (LCS in_scope cenv) old_var
+liftCoSubstTyVarBndr subst@(LCS in_scope cenv) old_var
= (LCS (in_scope `extendInScopeSet` new_var) new_cenv, new_var)
where
new_cenv | no_change = delVarEnv cenv old_var
| otherwise = extendVarEnv cenv old_var (Refl (TyVarTy new_var))
- no_change = new_var == old_var
- new_var = uniqAway in_scope old_var
+ no_change = no_kind_change && (new_var == old_var)
+
+ new_var1 = uniqAway in_scope old_var
+
+ old_ki = tyVarKind old_var
+ no_kind_change = isEmptyVarSet (tyVarsOfType old_ki)
+ new_var | no_kind_change = new_var1
+ | otherwise = setTyVarKind new_var1 (subst_kind subst old_ki)
+
+subst_kind :: LiftCoSubst -> Kind -> Kind
+-- See Note [Substituting kinds in liftCoSubst]
+subst_kind subst@(LCS _ cenv) kind
+ = go kind
+ where
+ go (LitTy n) = n `seq` LitTy n
+ go (TyVarTy kv) = subst_kv kv
+ go (TyConApp tc tys) = let args = map go tys
+ in args `seqList` TyConApp tc args
+
+ go (FunTy arg res) = (FunTy $! (go arg)) $! (go res)
+ go (AppTy fun arg) = mkAppTy (go fun) $! (go arg)
+ go (ForAllTy tv ty) = case liftCoSubstTyVarBndr subst tv of
+ (subst', tv') ->
+ ForAllTy tv' $! (subst_kind subst' ty)
+
+ subst_kv kv
+ | Just co <- lookupVarEnv cenv kv
+ , let co_kind = coercionKind co
+ = ASSERT2( pFst co_kind `eqKind` pSnd co_kind, ppr kv $$ ppr co )
+ pFst co_kind
+ | otherwise
+ = TyVarTy kv
\end{code}
\begin{code}
More information about the ghc-commits
mailing list