|
|
# Overloaded record fields: implementation notes
|
|
|
|
|
|
|
|
|
Here be dragons. This page describes implementation details and progress on the implementation of [the overloaded record fields plan](records/overloaded-record-fields/plan). Development of the extension is taking place on forks of the [ ghc](https://github.com/adamgundry/ghc), [ packages-base](https://github.com/adamgundry/packages-base), [ haddock](https://github.com/adamgundry/haddock) and [ testsuite](https://github.com/adamgundry/testsuite) repositories (on branch 'overloaded-record-fields'). A [ prototype implementation](https://github.com/adamgundry/records-prototype/blob/master/RecordsPrototype.hs) is also available.
|
|
|
Here be dragons. This page describes implementation details and progress on the implementation of [the overloaded record fields plan](records/overloaded-record-fields/plan). Development of the extension is taking place on forks of the [ ghc](https://github.com/adamgundry/ghc), [ packages-base](https://github.com/adamgundry/packages-base) and [ haddock](https://github.com/adamgundry/haddock) repositories (on branch 'overloaded-record-fields'). A [ prototype implementation](https://github.com/adamgundry/records-prototype/blob/master/RecordsPrototype.hs) is also available.
|
|
|
|
|
|
## The basic idea
|
|
|
|
... | ... | @@ -22,7 +22,7 @@ generates |
|
|
$sel:x:T :: T -> Int -- record selector (used to be called `x`)
|
|
|
$sel:x:T (MkT x) = x
|
|
|
|
|
|
$dfHasTx :: Has T "x" -- corresponds to the Has instance decl
|
|
|
$dfHasTx :: forall a . a ~ Int => Has T "x" b -- corresponds to the Has instance decl
|
|
|
$dfHasTx = Has { getField _ = $sel_x_T }
|
|
|
|
|
|
$dfUpdTx :: forall a . a ~ Int => Upd T "x" a -- corresponds to the Upd instance decl
|
... | ... | @@ -244,8 +244,8 @@ data instance F Bool = MkF2 { foo :: Bool } |
|
|
This is perfectly sensible, and gives rise to two \*different\* record selectors `foo`, and corresponding `Has` instances:
|
|
|
|
|
|
```wiki
|
|
|
instance Has (F Int) "foo"
|
|
|
instance Has (F Bool) "foo"
|
|
|
instance b ~ Int => Has (F Int) "foo" b
|
|
|
instance b ~ Bool => Has (F Bool) "foo" b
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -274,21 +274,17 @@ We could mangle selector names (using `$sel:foo:T` instead of `foo`) even when t |
|
|
- The `minf_exports` field of `ModuleInfo` is now of type `[AvailInfo]` rather than `NameSet`, as this provides accurate export information. An extra function `modInfoExportsWithSelectors` gives a list of the exported names including overloaded record selectors (whereas `modInfoExports` includes only non-mangled selectors).
|
|
|
- The `HsExpr`, `hsRecField` and `ConDeclField` AST types have changed as described above.
|
|
|
|
|
|
## To do
|
|
|
|
|
|
- The definition of `tcFldInsts` is currently wrong, because with the new design, the constraint solver needs to generate evidence bindings. Where should these go? It should be possible to fuse `makeRecFldInstsFor` and `tcFldInsts`, or just generate and typecheck binds, using `tcValBinds` or similar for the typechecking.
|
|
|
|
|
|
- Where should `TcBuiltInSynFamily` live? Could it be a fixed enumeration?
|
|
|
## Outstanding issues
|
|
|
|
|
|
- The definition of `tcFldInsts` has a slightly fragile assertion that it does not obtain any evidence bindings when typechecking `Has`/`Upd` instances. Could these be returned somewhere instead? It should be possible to fuse `makeRecFldInstsFor` and `tcFldInsts`, or just generate and typecheck binds, using `tcValBinds` or similar for the typechecking.
|
|
|
- It should be possible to remove the `tcg_axioms`, `mg_axioms` and `ic_axioms` fields, and instead use `tcg_tcs` when we need to get hold of the axioms in `TidyPgm`. However, this requires `FieldLabel`s (stored in `TyCon`s) to contain the actual `CoAxiom`s, not just their `Name`s, which in turn requires more refactoring. Also note that universally quantified fields will not have axioms.
|
|
|
- Make record selector bindings in `TcFldInsts`?
|
|
|
- We contemplated making the `CoAxioms``implicitTyThings`, but I got stuck trying to do this because of the "Tricky iface loop" (see note in `LoadIface`).
|
|
|
- Perhaps we should make record selector bindings in `TcFldInsts`, along with the new code.
|
|
|
- We shouldn't need to mess with the `TypeEnv` in `tcRnHsBootDecls`. Instead:
|
|
|
|
|
|
1. `tcTyClsInstDecls` should populate it with the `dfun_ids`
|
|
|
1. `tcHsBootSigs` should populate it with `val_ids` and return an updated `TcGblEnv`
|
|
|
1. Add a new field `tcg_boot_ids :: Bag Id` to `TcGblEnv` and pass `val_ids` to `mkBootModDetailsTc` that way, so it doesn't need to use the `TypeEnv`
|
|
|
- Pretty-printing needs to be sorted out for the new design with a two-parameter Has class
|
|
|
|
|
|
- Consider defaulting `Accessor p r n` to `p = (->)`, and defaulting `Has r "x"` constraints where there is only one datatype with a field `x` in scope.
|
|
|
- We could add `HsVarOut RdrName id` instead of `HsSingleRecFld` (or perhaps rename `HsVar` to `HsVarIn`). This would also be useful to recall how the user referred to something.
|
|
|
- Add syntax for record projection, perhaps using \# since it shouldn't conflict with `MagicHash`? |