summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/typecheck/TcTyClsDecls.lhs16
-rw-r--r--compiler/typecheck/TcTyDecls.lhs22
2 files changed, 28 insertions, 10 deletions
diff --git a/compiler/typecheck/TcTyClsDecls.lhs b/compiler/typecheck/TcTyClsDecls.lhs
index 70e72f593f..f4e4dabd1b 100644
--- a/compiler/typecheck/TcTyClsDecls.lhs
+++ b/compiler/typecheck/TcTyClsDecls.lhs
@@ -1524,14 +1524,16 @@ checkValidRoles tc
= return ()
where
check_dc_roles datacon
- = let univ_tvs = dataConUnivTyVars datacon
- ex_tvs = dataConExTyVars datacon
- args = dataConRepArgTys datacon
- univ_roles = zipVarEnv univ_tvs (tyConRoles tc)
+ = do { traceTc "check_dc_roles" (ppr datacon <+> ppr (tyConRoles tc))
+ ; mapM_ (check_ty_roles role_env Representational) $
+ eqSpecPreds eq_spec ++ theta ++ arg_tys }
+ -- See Note [Role-checking data constructor arguments] in TcTyDecls
+ where
+ (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty) = dataConFullSig datacon
+ univ_roles = zipVarEnv univ_tvs (tyConRoles tc)
-- zipVarEnv uses zipEqual, but we don't want that for ex_tvs
- ex_roles = mkVarEnv (zip ex_tvs (repeat Nominal))
- role_env = univ_roles `plusVarEnv` ex_roles in
- mapM_ (check_ty_roles role_env Representational) args
+ ex_roles = mkVarEnv (zip ex_tvs (repeat Nominal))
+ role_env = univ_roles `plusVarEnv` ex_roles
check_ty_roles env role (TyVarTy tv)
= case lookupVarEnv env tv of
diff --git a/compiler/typecheck/TcTyDecls.lhs b/compiler/typecheck/TcTyDecls.lhs
index bea2cd19be..5091cab802 100644
--- a/compiler/typecheck/TcTyDecls.lhs
+++ b/compiler/typecheck/TcTyDecls.lhs
@@ -615,6 +615,19 @@ roles(~#) = N, N
With -dcore-lint on, the output of this algorithm is checked in checkValidRoles,
called from checkValidTycon.
+Note [Role-checking data constructor arguments]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ data T a where
+ MkT :: Eq b => F a -> (a->a) -> T (G a)
+
+Then we want to check the roles at which 'a' is used
+in MkT's type. We want to work on the user-written type,
+so we need to take into account
+ * the arguments: (F a) and (a->a)
+ * the context: C a b
+ * the result type: (G a) -- this is in the eq_spec
+
\begin{code}
type RoleEnv = NameEnv [Role] -- from tycon names to roles
type RoleAnnots = NameEnv [Maybe Role] -- from tycon names to role annotations,
@@ -695,9 +708,12 @@ irClass tc_name cls
-- See Note [Role inference]
irDataCon :: Name -> DataCon -> RoleM ()
irDataCon tc_name datacon
- = addRoleInferenceInfo tc_name (dataConUnivTyVars datacon) $
- let ex_var_set = mkVarSet $ dataConExTyVars datacon in
- mapM_ (irType ex_var_set) (dataConRepArgTys datacon)
+ = addRoleInferenceInfo tc_name univ_tvs $
+ mapM_ (irType ex_var_set) (eqSpecPreds eq_spec ++ theta ++ arg_tys)
+ -- See Note [Role-checking data constructor arguments]
+ where
+ (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty) = dataConFullSig datacon
+ ex_var_set = mkVarSet ex_tvs
irType :: VarSet -> Type -> RoleM ()
irType = go