Skip to content

WIP: Experiment with a boxing data family

sheaf requested to merge sheaf/ghc:boxing into master

I am attempting to add boxing data constructors that work for all representations. See #21165 (closed), as well as #22336, #20269, #17521.

This hacky and experimental MR defines a wired-in data family

type Box :: forall {r :: RuntimeRep}. TYPE r -> Type
data family Box @r a

together with two wired-in Ids

box :: forall {r :: RuntimeRep} (a :: TYPE r). a -> Box a
unbox :: forall {r :: RuntimeRep} (a :: TYPE r). Box a -> a

These are defined in GHC.Types and re-exported in GHC.Exts.

This data family behaves as if there are instances for each concrete RuntimeRep Rep:

data instance Box @Rep b = MkBox[Rep] b

In desugaring (see GHC.HsToCore.Utils.mkCoreAppDs), we eliminate occurrences of box/unbox:

box @{Rep} @ty x
-- turns into -->
MkBox[Rep] @ty x |> sym co

unbox @{Rep} @ty x
-- turns into -->
case (x |> co) of
  MkBox[Rep] y -> y

Here, we create a data family instance on the fly, at representation Rep. The representation TyCon is R:Box[Rep], with a single data constructor MkBox[Rep] :: forall (a :: TYPE Rep). a -> R:Box[Rep] and coercion co = D:R:Box[Rep] <ty>_N :: Box @Rep ty ~R# R:Box[Rep] ty. (Side note: this data family has roles [Nominal, Representational], whereas usually only Nominal roles are allowed in data families. This allows coercing between Box a and Box b when a and b are representationally equal.)

Note that the representation-polymorphism checks ensure that box always appears applied to an argument with a concrete runtime representation (although this doesn't happen right now, just because of how I'm wiring box in). This isn't the case for unbox; fixing that would be a part of #21906 (closed).

For code generation, I hook into GHC.StgToCmm.DataCon to add constructor info tables on the fly to modules which use box or unbox. There's a very hacky IORef there to make sure I don't define duplicate info tables.

To reiterate: this MR consists of a bunch of hacks piled on top of each other, but I hope it can be a good first step to solving this problem. Test case T21165 demonstrates how this is all working in practice.

Edited by sheaf

Merge request reports