Skip to content

Make `wrapBox` work for AddrRep, TupleRep, SumRep, VecRep

!8750 (merged) beefed up our ability to allocate a box for many different representations.

Notable exceptions are AddrRep, TupleRep, SumRep and VecRep.

#22336 suggests to give up with a good error message when encountering these representations. This ticket is more ambitious: It asks for boxes for all these representations. This would be tremendously helpful for #17521 and #20269.

But since TupleRep and SumRep are recursive, there are an inifinite number of different representations to cover. Hence we can never catch all of them with a finite number of *Box data types as has been begun in ghc-prim:GHC.Types.

Proposal

  1. Define a wired-in type or data family

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

    Some instances of this family could be defined to delegate to the existing *Box data types in ghc-prim:GHC.Types, but the hard problem remains with unboxed tuples. This is the tricky part! We'll discuss the design below.

    !9353 proposes to 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.) (Kindly stole this explanation from @sheaf.)

    I want to add that we already have matching heap objects, if I understand CONSTR correctly. Maybe we could also pick CONSTR_STATIC when applicable. And of course we can optimise to CONSTR_p_n if we have a fitting combination for the given r (which will be 99% of cases). So I think we might not even need to generate an excessive amount of info tables for the special MkBox DataCons.

    Having Box would resolve #20269.

  2. #17521 also wants to offer an API to the user so that unlifted bindings at the top-level are possible (and memoised). One could imagine special, wired-in functions

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

    which basically desugar to something that GHC could resolve with GHC.Core.wrapBox. It might be possible to put them in a type class Boxing, but I don't yet see the added value of doing so.

Note that (1) can be done independently of (2), but I think it makes sense to do them together.

The instances for Box might re-use many of the existing *Box types in ghc-prim:GHC.Types or might not. Not sure. But upon further reflection, I don't think !8750 (merged) brought us any closer to a satisfying resolution of either #20269 or #17521.

Edited by Sebastian Graf
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information