summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc/TyCl/Build.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Tc/TyCl/Build.hs')
-rw-r--r--compiler/GHC/Tc/TyCl/Build.hs53
1 files changed, 47 insertions, 6 deletions
diff --git a/compiler/GHC/Tc/TyCl/Build.hs b/compiler/GHC/Tc/TyCl/Build.hs
index 588f209377..1dba4093f1 100644
--- a/compiler/GHC/Tc/TyCl/Build.hs
+++ b/compiler/GHC/Tc/TyCl/Build.hs
@@ -79,6 +79,8 @@ mkNewTyConRhs tycon_name tycon con
-- has a single argument (Foo a) that is a *type class*, so
-- dataConInstOrigArgTys returns [].
+ -- Eta-reduce the newtype
+ -- See Note [Newtype eta] in GHC.Core.TyCon
etad_tvs :: [TyVar] -- Matched lazily, so that mkNewTypeCo can
etad_roles :: [Role] -- return a TyCon without pulling on rhs_ty
etad_rhs :: Type -- See Note [Tricky iface loop] in GHC.Iface.Load
@@ -89,12 +91,51 @@ mkNewTyConRhs tycon_name tycon con
-> Type -- Rhs type
-> ([TyVar], [Role], Type) -- Eta-reduced version
-- (tyvars in normal order)
- eta_reduce (a:as) (_:rs) ty | Just (fun, arg) <- splitAppTy_maybe ty,
- Just tv <- getTyVar_maybe arg,
- tv == a,
- not (a `elemVarSet` tyCoVarsOfType fun)
- = eta_reduce as rs fun
- eta_reduce tvs rs ty = (reverse tvs, reverse rs, ty)
+ eta_reduce (a:as) (_:rs) ty
+ | Just (fun, arg) <- splitAppTy_maybe ty
+ , Just tv <- getTyVar_maybe arg
+ , tv == a
+ , not (a `elemVarSet` tyCoVarsOfType fun)
+ , typeKind fun `eqType` typeKind (mkTyConApp tycon (mkTyVarTys $ reverse as))
+ -- Why this kind-check? See Note [Newtype eta and homogeneous axioms]
+ = eta_reduce as rs fun
+ eta_reduce as rs ty = (reverse as, reverse rs, ty)
+
+{- Note [Newtype eta and homogeneous axioms]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When eta-reducing a newtype, we must be careful to make sure the axiom
+is homogeneous. (That is, the two types related by the axiom must
+have the same kind.) All known proofs of type safety for Core rely on
+the homogeneity of axioms, so let's not monkey with that.
+
+It is easy to mistakenly make an inhomogeneous axiom (#19739):
+ type T :: forall (a :: Type) -> Type
+ newtype T a = MkT (Proxy a)
+
+Can we eta-reduce, thus?
+ axT :: T ~ Proxy
+
+No! Because
+ T :: forall a -> Type
+ Proxy :: Type -> Type
+
+This is inhomogeneous. Hence, we have an extra kind-check in eta_reduce,
+to make sure the reducts have the same kind. This is simple, although
+perhaps quadratic in complexity, if we eta-reduce many arguments (which
+seems vanishingly unlikely in practice). But NB that the free-variable
+check, which immediately precedes the kind check, is also potentially
+quadratic.
+
+There are other ways we could do the check (discussion on #19739):
+
+* We could look at the sequence of binders on the newtype and on the
+ head of the representation type, and make sure the visibilities on
+ the binders match up. This is quite a bit more code, and the reasoning
+ is subtler.
+
+* We could, say, do the kind-check at the end and then backtrack until the
+ kinds match up. Hard to know whether that's more performant or not.
+-}
------------------------------------------------------
buildDataCon :: FamInstEnvs