... | ... | @@ -59,44 +59,47 @@ This would replace the existing calls to `typePrimRep`, which panic when encount |
|
|
Firstly, evidence from solving `FixedRuntimeRep` constraints in the typechecker will be stored in TTG extension fields at `GhcTc` pass (e.g. in `XApp` for `HsExpr`, in `XWildPat`, `XVarPat`, ... in `Pat`, etc).
|
|
|
Secondly, this information needs to persist in some fashion through desugaring, so that the code generator has enough information. Here are some of the ideas considered so far:
|
|
|
|
|
|
### Alternative 1: Evidence = [PrimRep]
|
|
|
### Alternative 1: Evidence = `[PrimRep]`
|
|
|
|
|
|
The solver generates `[PrimRep]` as evidence:
|
|
|
A `[PrimRep]` (that is, a list of `PrimRep`s) describes the representation of a value, as it will be used after unarisation. It must be a list to account for the possibility of unboxed tuples. Note that `PrimRep` includes a constructor `VoidRep`, but we will always assume that we will not use this constructor. See `Note [VoidRep]` in `GHC.Types.RepType` for details.
|
|
|
|
|
|
The solver can thus use `[PrimRep]` as evidence:
|
|
|
|
|
|
```haskell
|
|
|
newtype CodeGenRep = MkCodeGenRep [PrimRep]
|
|
|
newtype CodeGenRep = MkCodeGenRep [PrimRep] -- no VoidReps here
|
|
|
newtype TcCodeGenRep = MkTcCodeGenRep (TcRef (Maybe CodeGenRep))
|
|
|
```
|
|
|
|
|
|
A new `TcEvDest` corresponding to `TcCodeGenRep` will also need to be added, to be used by `FixedRuntimeRep`.
|
|
|
|
|
|
To pass this on after desugaring, we modify Core so that arguments and binders have associated `[PrimRep]`:
|
|
|
To pass this on after desugaring, we modify Core so that arguments and binders have associated `CodeGenRep`:
|
|
|
|
|
|
```haskell
|
|
|
data Expr b
|
|
|
= Var Id
|
|
|
| Lit Literal
|
|
|
| App (Expr b) (Arg b)
|
|
|
| Lam PrimRep b (Expr b)
|
|
|
| Lam CodeGenRep b (Expr b) -- this is different
|
|
|
| Let (Bind b) (Expr b)
|
|
|
| Case PrimRep (Expr b) b Type [Alt b]
|
|
|
| Case CodeGenRep (Expr b) b Type [Alt b] -- this is different
|
|
|
| Cast (Expr b) CoercionR
|
|
|
| Tick CoreTickish (Expr b)
|
|
|
|
|
|
data Arg b
|
|
|
= ExprArg PrimRep (Expr b)
|
|
|
= ExprArg CodeGenRep (Expr b)
|
|
|
| TypeArg Type
|
|
|
| CoercionArg Coercion
|
|
|
```
|
|
|
Note that we don't change `Bind` as only the `BoxedRep Lifted` representation is allowed there.
|
|
|
|
|
|
**Advantage**: the primreps are exactly what the code generator needs; it doesn't need to go inspecting types to determine the runtime representation.
|
|
|
Note that we don't change `Bind` as only the `BoxedRep Lifted` representation is allowed there. We have also refactored `Expr` to move the `Type` and `Coercion` constructors out to `Arg`. Otherwise, we could have something like `type Arg b = (Maybe CodeGenRep, Expr b)` with an invariant that the first element is `Nothing` iff the second element is `Type` or `Coercion`, but that seems more error-prone.
|
|
|
|
|
|
**Advantage**: the `CodeGenRep`s are exactly what the code generator needs; it doesn't need to go inspecting types to determine the runtime representation.
|
|
|
**Disadvantage**: we are potentially storing a lot of `PrimRep`s, which might bloat `Core` programs (e.g. `1+2+3+4+5+6+7+8` would store many `LiftedRep` `PrimRep`s).
|
|
|
**Disadvantage**: we don't have a good way of linting the `PrimRep`s.
|
|
|
|
|
|
### Alternative 2: Evidence is a coercion
|
|
|
|
|
|
The evidence for a `FixedRuntimeRep k` constraint is a coercion whose LHS is k and whose RHS is `TYPE rep` where `rep` is a tree of constructors and applications like `mkTyConApp intRepTyCon []` or `mkTyConApp tupleRepTyCon [mkTyConApp nilTyCon [runtimeRepTy]]`. No variables, type synonyms or type families, etc.
|
|
|
The evidence for a `FixedRuntimeRep k` constraint is a (nominal) coercion whose LHS type is `k` and whose RHS type is `TYPE rep` where `rep` is a tree of constructors and applications like `mkTyConApp intRepTyCon []` or `mkTyConApp tupleRepTyCon [mkTyConApp nilTyCon [runtimeRepTy]]`. No variables, type synonyms or type families, etc.
|
|
|
|
|
|
We can re-use `HoleDest` at the typechecker stage to store a mutable hole to be filled by the evidence.
|
|
|
|
... | ... | @@ -107,24 +110,26 @@ data Expr b |
|
|
= Var Id
|
|
|
| Lit Literal
|
|
|
| App (Expr b) (Arg b)
|
|
|
| Lam Coercion b (Expr b)
|
|
|
| Lam CoercionN b (Expr b) -- this is different
|
|
|
| Let (Bind b) (Expr b)
|
|
|
| Case Coercion (Expr b) b Type [Alt b]
|
|
|
| Case CoercionN (Expr b) b Type [Alt b] -- this is different
|
|
|
| Cast (Expr b) CoercionR
|
|
|
| Tick CoreTickish (Expr b)
|
|
|
| Type Type
|
|
|
| Coercion Coercion
|
|
|
```
|
|
|
|
|
|
That is, we add coercions that prove that binders have a fixed runtime representation. We don't do this for arguments, which we instead directly cast by such a coercion.
|
|
|
That is, we add coercions that prove that binders have a fixed runtime representation. We don't do this for arguments, which we instead directly cast by such a coercion. Then, when we need to know the representation for the argument, we can always look at the argument's type's kind, which will always be a constructor/application tree.
|
|
|
|
|
|
**Advantage**: we can lint the coercions.
|
|
|
**Advantage**: We can lint the coercions.
|
|
|
**Advantage**: We can re-use some infrastructure around `CoercionHole`s.
|
|
|
**Advantage**: The changes to Core are fewer.
|
|
|
**Disadvantage**: the code generator will need to inspect the coercions to obtain the relevant `PrimRep`s.
|
|
|
|
|
|
### Alternative 3 = 1 + 2
|
|
|
|
|
|
Store both the coercion and `[PrimRep]` in `Core`.
|
|
|
|
|
|
**Advantage**: the code-generator has the `PrimRep`s it needs.
|
|
|
**Advantage**: the code-generator has the `PrimRep`s it needs -- no need to recalculate the representation from the coercion.
|
|
|
**Advantage**: we can lint everything nicely.
|
|
|
**Disadvantage**: we are potentially storing a lot of `PrimRep`s. |
|
|
\ No newline at end of file |