summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/iface/MkIface.hs2
-rw-r--r--compiler/typecheck/FamInst.hs4
-rw-r--r--compiler/typecheck/TcInteract.hs6
-rw-r--r--compiler/typecheck/TcRnDriver.hs4
-rw-r--r--compiler/typecheck/TcSplice.hs128
-rw-r--r--compiler/typecheck/TcValidity.hs2
-rw-r--r--compiler/types/TyCon.hs18
-rw-r--r--compiler/types/Unify.hs2
8 files changed, 132 insertions, 34 deletions
diff --git a/compiler/iface/MkIface.hs b/compiler/iface/MkIface.hs
index 78787c9827..94ace18545 100644
--- a/compiler/iface/MkIface.hs
+++ b/compiler/iface/MkIface.hs
@@ -1565,7 +1565,7 @@ tyConToIfaceDecl env tycon
ifFamFlav = to_if_fam_flav fam_flav,
ifBinders = if_binders,
ifResKind = if_res_kind,
- ifFamInj = familyTyConInjectivityInfo tycon
+ ifFamInj = tyConInjectivityInfo tycon
})
| isAlgTyCon tycon
diff --git a/compiler/typecheck/FamInst.hs b/compiler/typecheck/FamInst.hs
index 87a602c783..a869ff4e4a 100644
--- a/compiler/typecheck/FamInst.hs
+++ b/compiler/typecheck/FamInst.hs
@@ -720,7 +720,7 @@ checkForInjectivityConflicts :: FamInstEnvs -> FamInst -> TcM Bool
checkForInjectivityConflicts instEnvs famInst
| isTypeFamilyTyCon tycon
-- type family is injective in at least one argument
- , Injective inj <- familyTyConInjectivityInfo tycon = do
+ , Injective inj <- tyConInjectivityInfo tycon = do
{ let axiom = coAxiomSingleBranch fi_ax
conflicts = lookupFamInstEnvInjectivityConflicts inj instEnvs famInst
-- see Note [Verifying injectivity annotation] in FamInstEnv
@@ -808,7 +808,7 @@ injTyVarsOfType (TyVarTy v)
= unitVarSet v `unionVarSet` injTyVarsOfType (tyVarKind v)
injTyVarsOfType (TyConApp tc tys)
| isTypeFamilyTyCon tc
- = case familyTyConInjectivityInfo tc of
+ = case tyConInjectivityInfo tc of
NotInjective -> emptyVarSet
Injective inj -> injTyVarsOfTypes (filterByList inj tys)
| otherwise
diff --git a/compiler/typecheck/TcInteract.hs b/compiler/typecheck/TcInteract.hs
index 69e84a42ca..cbe24ca0ef 100644
--- a/compiler/typecheck/TcInteract.hs
+++ b/compiler/typecheck/TcInteract.hs
@@ -1174,7 +1174,7 @@ improveLocalFunEqs work_ev inerts fam_tc args fsk
rhs = lookupFlattenTyVar ieqs fsk
work_loc = ctEvLoc work_ev
work_pred = ctEvPred work_ev
- fam_inj_info = familyTyConInjectivityInfo fam_tc
+ fam_inj_info = tyConInjectivityInfo fam_tc
--------------------
improvement_eqns :: [FunDepEqn CtLoc]
@@ -1743,7 +1743,7 @@ improve_top_fun_eqs fam_envs fam_tc args rhs_ty
-- see Note [Type inference for type families with injectivity]
| isOpenTypeFamilyTyCon fam_tc
- , Injective injective_args <- familyTyConInjectivityInfo fam_tc
+ , Injective injective_args <- tyConInjectivityInfo fam_tc
, let fam_insts = lookupFamInstEnvByTyCon fam_envs fam_tc
= -- it is possible to have several compatible equations in an open type
-- family but we only want to derive equalities from one such equation.
@@ -1755,7 +1755,7 @@ improve_top_fun_eqs fam_envs fam_tc args rhs_ty
take 1 improvs }
| Just ax <- isClosedSynFamilyTyConWithAxiom_maybe fam_tc
- , Injective injective_args <- familyTyConInjectivityInfo fam_tc
+ , Injective injective_args <- tyConInjectivityInfo fam_tc
= concatMapM (injImproveEqns injective_args) $
buildImprovementData (fromBranches (co_ax_branches ax))
cab_tvs cab_lhs cab_rhs Just
diff --git a/compiler/typecheck/TcRnDriver.hs b/compiler/typecheck/TcRnDriver.hs
index ff20e30abb..8189a7833c 100644
--- a/compiler/typecheck/TcRnDriver.hs
+++ b/compiler/typecheck/TcRnDriver.hs
@@ -1028,8 +1028,8 @@ checkBootTyCon is_boot tc1 tc2
= eqClosedFamilyAx ax1 ax2
eqFamFlav (BuiltInSynFamTyCon {}) (BuiltInSynFamTyCon {}) = tc1 == tc2
eqFamFlav _ _ = False
- injInfo1 = familyTyConInjectivityInfo tc1
- injInfo2 = familyTyConInjectivityInfo tc2
+ injInfo1 = tyConInjectivityInfo tc1
+ injInfo2 = tyConInjectivityInfo tc2
in
-- check equality of roles, family flavours and injectivity annotations
-- (NB: Type family roles are always nominal. But the check is
diff --git a/compiler/typecheck/TcSplice.hs b/compiler/typecheck/TcSplice.hs
index 77c97f70df..6df78f8a85 100644
--- a/compiler/typecheck/TcSplice.hs
+++ b/compiler/typecheck/TcSplice.hs
@@ -52,6 +52,7 @@ import GHCi
import HscMain
-- These imports are the reason that TcSplice
-- is very high up the module hierarchy
+import FV
import RnSplice( traceSplice, SpliceInfo(..) )
import RdrName
import HscTypes
@@ -97,7 +98,7 @@ import GHC.Serialized
import ErrUtils
import Util
import Unique
-import VarSet ( isEmptyVarSet, filterVarSet, mkVarSet, elemVarSet )
+import VarSet
import Data.List ( find )
import Data.Maybe
import FastString
@@ -1380,7 +1381,7 @@ reifyTyCon tc
Nothing -> (TH.KindSig kind', Nothing)
Just name ->
let thName = reifyName name
- injAnnot = familyTyConInjectivityInfo tc
+ injAnnot = tyConInjectivityInfo tc
sig = TH.TyVarSig (TH.KindedTV thName kind')
inj = case injAnnot of
NotInjective -> Nothing
@@ -1682,7 +1683,7 @@ reifyType (AppTy t1 t2) = do { [r1,r2] <- reifyTypes [t1,t2] ; return (r1 `T
reifyType ty@(FunTy t1 t2)
| isPredTy t1 = reify_for_all ty -- Types like ((?x::Int) => Char -> Char)
| otherwise = do { [r1,r2] <- reifyTypes [t1,t2] ; return (TH.ArrowT `TH.AppT` r1 `TH.AppT` r2) }
-reifyType ty@(CastTy {}) = noTH (sLit "kind casts") (ppr ty)
+reifyType (CastTy t _) = reifyType t -- Casts are ignored in TH
reifyType ty@(CoercionTy {})= noTH (sLit "coercions in types") (ppr ty)
reify_for_all :: TyCoRep.Type -> TcM TH.Type
@@ -1779,13 +1780,67 @@ For example:
type instance F Bool = (Proxy :: (* -> *) -> *)
It's hard to figure out where these annotations should appear, so we do this:
-Suppose the tycon is applied to n arguments. We strip off the first n
-arguments of the tycon's kind. If there are any variables left in the result
-kind, we put on a kind annotation. But we must be slightly careful: it's
-possible that the tycon's kind will have fewer than n arguments, in the case
-that the concrete application instantiates a result kind variable with an
-arrow kind. So, if we run out of arguments, we conservatively put on a kind
-annotation anyway. This should be a rare case, indeed. Here is an example:
+Suppose we have a tycon application (T ty1 ... tyn). Assuming that T is not
+oversatured (more on this later), we can assume T's declaration is of the form
+T (tvb1 :: s1) ... (tvbn :: sn) :: p. If any kind variable that
+is free in p is not free in an injective position in tvb1 ... tvbn,
+then we put on a kind annotation, since we would not otherwise be able to infer
+the kind of the whole tycon application.
+
+The injective positions in a tyvar binder are the injective positions in the
+kind of its tyvar, provided the tyvar binder is either:
+
+* Anonymous. For example, in the promoted data constructor '(:):
+
+ '(:) :: forall a. a -> [a] -> [a]
+
+ The second and third tyvar binders (of kinds `a` and `[a]`) are both
+ anonymous, so if we had '(:) 'True '[], then the inferred kinds of 'True and
+ '[] would contribute to the inferred kind of '(:) 'True '[].
+* Has required visibility. For example, in the type family:
+
+ type family Wurble k (a :: k) :: k
+ Wurble :: forall k -> k -> k
+
+ The first tyvar binder (of kind `forall k`) has required visibility, so if
+ we had Wurble (Maybe a) Nothing, then the inferred kind of Maybe a would
+ contribute to the inferred kind of Wurble (Maybe a) Nothing.
+
+An injective position in a type is one that does not occur as an argument to
+a non-injective type constructor (e.g., non-injective type families). See
+injectiveVarsOfType.
+
+How can be sure that this is correct? That is, how can we be sure that in the
+event that we leave off a kind annotation, that one could infer the kind of the
+tycon application from its arguments? It's essentially a proof by induction: if
+we can infer the kinds of every subtree of a type, then the whole tycon
+application will have an inferrable kind--unless, of course, the remainder of
+the tycon application's kind has uninstantiated kind variables.
+
+An earlier implementation of this algorithm only checked if p contained any
+free variables. But this was unsatisfactory, since a datatype like this:
+
+ data Foo = Foo (Proxy '[False, True])
+
+Would be reified like this:
+
+ data Foo = Foo (Proxy ('(:) False ('(:) True ('[] :: [Bool])
+ :: [Bool]) :: [Bool]))
+
+Which has a rather excessive amount of kind annotations. With the current
+algorithm, we instead reify Foo to this:
+
+ data Foo = Foo (Proxy ('(:) False ('(:) True ('[] :: [Bool]))))
+
+Since in the case of '[], the kind p is [a], and there are no arguments in the
+kind of '[]. On the other hand, in the case of '(:) True '[], the kind p is
+(forall a. [a]), but a occurs free in the first and second arguments of the
+full kind of '(:), which is (forall a. a -> [a] -> [a]). (See Trac #14060.)
+
+What happens if T is oversaturated? That is, if T's kind has fewer than n
+arguments, in the case that the concrete application instantiates a result
+kind variable with an arrow kind? If we run out of arguments, we do not attach
+a kind annotation. This should be a rare case, indeed. Here is an example:
data T1 :: k1 -> k2 -> *
data T2 :: k1 -> k2 -> *
@@ -1799,10 +1854,14 @@ Here G's kind is (forall k. k -> k), and the desugared RHS of that last
instance of F is (G (* -> (* -> *) -> *) (T1 * (* -> *)) Bool). According to
the algorithm above, there are 3 arguments to G so we should peel off 3
arguments in G's kind. But G's kind has only two arguments. This is the
-rare special case, and we conservatively choose to put the annotation
-in.
+rare special case, and we choose not to annotate the application of G with
+a kind signature. After all, we needn't do this, since that instance would
+be reified as:
-See #8953 and test th/T8953.
+ type instance F Char = G (T1 :: * -> (* -> *) -> *) Bool
+
+So the kind of G isn't ambiguous anymore due to the explicit kind annotation
+on its argument. See #8953 and test th/T8953.
-}
reify_tc_app :: TyCon -> [Type.Type] -> TcM TH.Type
@@ -1841,12 +1900,45 @@ reify_tc_app tc tys
needs_kind_sig
| GT <- compareLength tys tc_binders
- = tcIsTyVarTy tc_res_kind
+ = False
| otherwise
- = not . isEmptyVarSet $
- filterVarSet isTyVar $
- tyCoVarsOfType $
- mkTyConKind (dropList tys tc_binders) tc_res_kind
+ = let (dropped_binders, remaining_binders)
+ = splitAtList tys tc_binders
+ result_kind = mkTyConKind remaining_binders tc_res_kind
+ result_vars = tyCoVarsOfType result_kind
+ dropped_vars = fvVarSet $
+ mapUnionFV injectiveVarsOfBinder dropped_binders
+
+ in not (subVarSet result_vars dropped_vars)
+
+ injectiveVarsOfBinder :: TyConBinder -> FV
+ injectiveVarsOfBinder (TvBndr tv vis) =
+ case vis of
+ AnonTCB -> injectiveVarsOfType (tyVarKind tv)
+ NamedTCB Required -> FV.unitFV tv `unionFV`
+ injectiveVarsOfType (tyVarKind tv)
+ NamedTCB _ -> emptyFV
+
+ injectiveVarsOfType :: Type -> FV
+ injectiveVarsOfType = go
+ where
+ go ty | Just ty' <- coreView ty
+ = go ty'
+ go (TyVarTy v) = FV.unitFV v `unionFV` go (tyVarKind v)
+ go (AppTy f a) = go f `unionFV` go a
+ go (FunTy ty1 ty2) = go ty1 `unionFV` go ty2
+ go (TyConApp tc tys) =
+ case tyConInjectivityInfo tc of
+ NotInjective -> emptyFV
+ Injective inj -> mapUnionFV go $
+ filterByList (inj ++ repeat True) tys
+ -- Oversaturated arguments to a tycon are
+ -- always injective, hence the repeat True
+ go (ForAllTy tvb ty) = tyCoFVsBndr tvb $ go (tyVarKind (binderVar tvb))
+ `unionFV` go ty
+ go LitTy{} = emptyFV
+ go (CastTy ty _) = go ty
+ go CoercionTy{} = emptyFV
reifyPred :: TyCoRep.PredType -> TcM TH.Pred
reifyPred ty
diff --git a/compiler/typecheck/TcValidity.hs b/compiler/typecheck/TcValidity.hs
index d8e2519fed..bd4938eeaa 100644
--- a/compiler/typecheck/TcValidity.hs
+++ b/compiler/typecheck/TcValidity.hs
@@ -1614,7 +1614,7 @@ checkValidCoAxiom ax@(CoAxiom { co_ax_tc = fam_tc, co_ax_branches = branches })
; foldlM_ check_branch_compat [] branch_list }
where
branch_list = fromBranches branches
- injectivity = familyTyConInjectivityInfo fam_tc
+ injectivity = tyConInjectivityInfo fam_tc
check_branch_compat :: [CoAxBranch] -- previous branches in reverse order
-> CoAxBranch -- current branch
diff --git a/compiler/types/TyCon.hs b/compiler/types/TyCon.hs
index 95207c493b..63e199c93e 100644
--- a/compiler/types/TyCon.hs
+++ b/compiler/types/TyCon.hs
@@ -59,7 +59,7 @@ module TyCon(
isFamilyTyCon, isOpenFamilyTyCon,
isTypeFamilyTyCon, isDataFamilyTyCon,
isOpenTypeFamilyTyCon, isClosedSynFamilyTyConWithAxiom_maybe,
- familyTyConInjectivityInfo,
+ tyConInjectivityInfo,
isBuiltInSynFamTyCon_maybe,
isUnliftedTyCon,
isGadtSyntaxTyCon, isInjectiveTyCon, isGenerativeTyCon, isGenInjAlgRhs,
@@ -1925,11 +1925,17 @@ isClosedSynFamilyTyConWithAxiom_maybe
(FamilyTyCon {famTcFlav = ClosedSynFamilyTyCon mb}) = mb
isClosedSynFamilyTyConWithAxiom_maybe _ = Nothing
--- | Try to read the injectivity information from a FamilyTyCon.
--- For every other TyCon this function panics.
-familyTyConInjectivityInfo :: TyCon -> Injectivity
-familyTyConInjectivityInfo (FamilyTyCon { famTcInj = inj }) = inj
-familyTyConInjectivityInfo _ = panic "familyTyConInjectivityInfo"
+-- | @'tyConInjectivityInfo' tc@ returns @'Injective' is@ is @tc@ is an
+-- injective tycon (where @is@ states for which 'tyConBinders' @tc@ is
+-- injective), or 'NotInjective' otherwise.
+tyConInjectivityInfo :: TyCon -> Injectivity
+tyConInjectivityInfo tc
+ | FamilyTyCon { famTcInj = inj } <- tc
+ = inj
+ | isInjectiveTyCon tc Nominal
+ = Injective (replicate (tyConArity tc) True)
+ | otherwise
+ = NotInjective
isBuiltInSynFamTyCon_maybe :: TyCon -> Maybe BuiltInSynFamily
isBuiltInSynFamTyCon_maybe
diff --git a/compiler/types/Unify.hs b/compiler/types/Unify.hs
index c9c78f7d19..80cccb3c3c 100644
--- a/compiler/types/Unify.hs
+++ b/compiler/types/Unify.hs
@@ -804,7 +804,7 @@ unify_ty env ty1 ty2 _kco
= if isInjectiveTyCon tc1 Nominal
then unify_tys env tys1 tys2
else do { let inj | isTypeFamilyTyCon tc1
- = case familyTyConInjectivityInfo tc1 of
+ = case tyConInjectivityInfo tc1 of
NotInjective -> repeat False
Injective bs -> bs
| otherwise