Remove unnecessary uses of typeKind/tcTypeKind where possible
While perusing parts of the codebase related to coercions recently, I discovered this chunk of code in Inst
:
get_eq_tys_maybe ty
-- Lifted heterogeneous equality (~~)
| Just (tc, [_, _, k1, k2]) <- splitTyConApp_maybe ty
, tc `hasKey` heqTyConKey
= Just (\co -> mkHEqBoxTy co k1 k2, k1, k2)
-- ...
mkHEqBoxTy :: TcCoercion -> Type -> Type -> TcM Type
mkHEqBoxTy co ty1 ty2
= return $
mkTyConApp (promoteDataCon heqDataCon) [k1, k2, ty1, ty2, mkCoercionTy co]
where k1 = tcTypeKind ty1
k2 = tcTypeKind ty2
There's something smelly going on in this code. in get_eq_tys_maybe
, we call splitTyConApp_maybe
to decompose an application of (~~)
, throwing the kind arguments away in the process. We then pass the type arguments k1
and k2
into mkHEqBoxTy
. That function, in turn, constructs an application of HEq#
using the arguments. But in the process of doing this, mkHEqBoxTy
reconstructs the kinds of its arguments using tcTypeKind
. This is incredibly wasteful, since we already have access to the kinds in get_eq_tys_maybe
—we just ignore them at the moment. In general, tcTypeKind
can be expensive to calculate, so it would be nice to avoid unnecessary uses of this function.
Luckily, it's simple to get rid of the uses of tcTypeKind
in mkHEqBoxTy
. get_eq_tys
is the only place in GHC where mkHEqBoxTy
is used, so we can simply change this code to the following:
get_eq_tys_maybe ty
-- Lifted heterogeneous equality (~~)
| Just (tc, [kk1, kk2, k1, k2]) <- splitTyConApp_maybe ty
, tc `hasKey` heqTyConKey
= Just (\co -> mkHEqBoxTy co kk1 kk2 k1 k2, k1, k2)
-- ...
mkHEqBoxTy :: TcCoercion -> Kind -> Kind -> Type -> Type -> TcM Type
mkHEqBoxTy co k1 k2 ty1 ty2
= return $
mkTyConApp (promoteDataCon heqDataCon) [k1, k2, ty1, ty2, mkCoercionTy co]
There are other places in GHC that call typeKind
/tcTypeKind
unnecessarily, but this was the most obvious one. I have a patch on the way which removes other unnecessary uses.