[GHC] #14101: Type synonyms can make roles too conservative
GHC
ghc-devs at haskell.org
Wed Aug 9 13:27:23 UTC 2017
#14101: Type synonyms can make roles too conservative
-------------------------------------+-------------------------------------
Reporter: dfeuer | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone: 8.4.1
Component: Compiler (Type | Version: 8.2.1
checker) |
Resolution: | Keywords: roles
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC rejects | Unknown/Multiple
valid program | Test Case:
Blocked By: | Blocking:
Related Tickets: #8234 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Changes (by RyanGlScott):
* cc: goldfire, RyanGlScott (added)
Comment:
At the very least, I know why that program is currently rejected. When
role inference occurs, GHC uses the `tyConRolesX` function to look up the
roles of a `TyCon`. The implementation of `tyConRolesX` is
[http://git.haskell.org/ghc.git/blob/14457cf6a50f708eecece8f286f08687791d51f7:/compiler/typecheck/TcTyDecls.hs#l636
simply]:
{{{#!hs
lookupRolesX :: TyCon -> RoleM [Role]
lookupRolesX tc
= do { roles <- lookupRoles tc
; return $ roles ++ repeat Nominal }
}}}
In other words, if a `TyCon` is applied to more arguments than it was
originally supplied in its definition, then the roles of these additional
arguments will all be inferred as nominal. This is why the reported
behavior only manifests when you define `Arr#` as `type Arr# = Array#`,
and not `type Arr# a = Array# a`.
Upon realizing this, my inclination to fix this bug is to simply expand
all type synonyms during role inference. Indeed, if you apply this patch:
{{{#!diff
diff --git a/compiler/typecheck/TcTyClsDecls.hs
b/compiler/typecheck/TcTyClsDecls.hs
index 17da32f..512601f 100644
--- a/compiler/typecheck/TcTyClsDecls.hs
+++ b/compiler/typecheck/TcTyClsDecls.hs
@@ -2994,6 +2994,10 @@ checkValidRoles tc
ex_roles = mkVarEnv (map (, Nominal) ex_tvs)
role_env = univ_roles `plusVarEnv` ex_roles
+ check_ty_roles env role ty
+ | Just ty' <- coreView ty
+ = check_ty_roles env role ty'
+
check_ty_roles env role (TyVarTy tv)
= case lookupVarEnv env tv of
Just role' -> unless (role' `ltRole` role || role' == role) $
diff --git a/compiler/typecheck/TcTyDecls.hs
b/compiler/typecheck/TcTyDecls.hs
index 41482cc..6d70077 100644
--- a/compiler/typecheck/TcTyDecls.hs
+++ b/compiler/typecheck/TcTyDecls.hs
@@ -580,6 +580,8 @@ irDataCon datacon
irType :: VarSet -> Type -> RoleM ()
irType = go
where
+ go lcls ty | Just ty' <- coreView ty
+ = go lcls ty'
go lcls (TyVarTy tv) = unless (tv `elemVarSet` lcls) $
updateRole Representational tv
go lcls (AppTy t1 t2) = go lcls t1 >> markNominal lcls t2
diff --git a/compiler/types/Coercion.hs b/compiler/types/Coercion.hs
index b0b13b8..214fe2d 100644
--- a/compiler/types/Coercion.hs
+++ b/compiler/types/Coercion.hs
@@ -1513,6 +1513,8 @@ ty_co_subst lc role ty
= go role ty
where
go :: Role -> Type -> Coercion
+ go r ty | Just ty' <- coreView ty
+ = go r ty'
go Phantom ty = lift_phantom ty
go r (TyVarTy tv) = expectJust "ty_co_subst bad roles" $
liftCoSubstTyVar lc r tv
}}}
Then the program reported in this ticket compiles, and all tests pass.
The more difficult question to answer, however, is if this is the correct
way to go about things. At one point in time, it used to be possible to
annotate type synonyms with role annotations, which would make the idea of
eagerly expanding all type synonyms during role inference quite unsound.
But post-#8234, role-annotating type synonyms isn't possible, so all
(inferred) type synonym roles are as general as possible. This leads me to
believe that expanding type synonyms eagerly would be sound.
In any case, it'd be helpful to hear from Richard before we proceed
further.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14101#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list