diff options
| author | Ryan Scott <ryan.gl.scott@gmail.com> | 2018-04-19 12:36:42 -0400 |
|---|---|---|
| committer | Ben Gamari <ben@smart-cactus.org> | 2018-04-19 13:18:14 -0400 |
| commit | b08a6d75e0440f33260bea5319b8c3f871b42f6e (patch) | |
| tree | eeae0a52bc64aac7a1a9e2d83e25053f0b87e243 /compiler | |
| parent | cac8be611e7e80ed80e24b15faac9e1ac0a07247 (diff) | |
| download | haskell-b08a6d75e0440f33260bea5319b8c3f871b42f6e.tar.gz | |
Fix #15012 with a well-placed use of Any
Previously, derived `Generic1` instances could have associated `Rep1`
type family instances with unbound variables, such as in the following
example:
```lang=haskell
data T a = MkT (FakeOut a) deriving Generic1
type FakeOut a = Int
==>
instance Generic1 T where
type Rep1 T = ... (Rec0 (FakeOut a))
```
Yikes! To avoid this, we simply map the last type variable in a
derived `Generic1` instance to `Any`.
Test Plan: make test TEST=T15012
Reviewers: bgamari
Reviewed By: bgamari
Subscribers: simonpj, thomie, carter
GHC Trac Issues: #15012
Differential Revision: https://phabricator.haskell.org/D4602
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/typecheck/TcGenGenerics.hs | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/compiler/typecheck/TcGenGenerics.hs b/compiler/typecheck/TcGenGenerics.hs index 61a432e9dc..9da94280ce 100644 --- a/compiler/typecheck/TcGenGenerics.hs +++ b/compiler/typecheck/TcGenGenerics.hs @@ -420,7 +420,15 @@ tc_mkRepFamInsts gk tycon inst_tys = -- type arguments before generating the Rep/Rep1 instance, since some -- of the tyvars might have been instantiated when deriving. -- See Note [Generating a correctly typed Rep instance]. - ; let env = zipTyEnv tyvars inst_args + ; let (env_tyvars, env_inst_args) + = case gk_ of + Gen0_ -> (tyvars, inst_args) + Gen1_ last_tv + -- See the "wrinkle" in + -- Note [Generating a correctly typed Rep instance] + -> ( last_tv : tyvars + , anyTypeOfKind (tyVarKind last_tv) : inst_args ) + env = zipTyEnv env_tyvars env_inst_args in_scope = mkInScopeSet (tyCoVarsOfTypes inst_tys) subst = mkTvSubst in_scope env repTy' = substTy subst repTy @@ -923,6 +931,32 @@ the tyConTyVars of the TyCon to their counterparts in the fully instantiated type. (For example, using T above as example, you'd map a :-> Int.) We then apply the substitution to the RHS before generating the instance. +A wrinkle in all of this: when forming the type variable substitution for +Generic1 instances, we map the last type variable of the tycon to Any. Why? +It's because of wily data types like this one (#15012): + + data T a = MkT (FakeOut a) + type FakeOut a = Int + +If we ignore a, then we'll produce the following Rep1 instance: + + instance Generic1 T where + type Rep1 T = ... (Rec0 (FakeOut a)) + ... + +Oh no! Now we have `a` on the RHS, but it's completely unbound. Instead, we +ensure that `a` is mapped to Any: + + instance Generic1 T where + type Rep1 T = ... (Rec0 (FakeOut Any)) + ... + +And now all is good. + +Alternatively, we could have avoided this problem by expanding all type +synonyms on the RHSes of Rep1 instances. But we might blow up the size of +these types even further by doing this, so we choose not to do so. + Note [Handling kinds in a Rep instance] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Because Generic1 is poly-kinded, the representation types were generalized to |
