Improve defaulting of representational equalities
!13834 (closed) implements defaulting of representational equality, fixing #21003 (closed).
However, @simonpj points out that the current approach of "promote to nominal; try the eager unifier; if it defers then give up" doesn't handle the following case:
type family F a = r | r -> a
type instance F Int = Bool
[W] F beta ~R Bool
Here, if we promote that representational equality to a nominal equality and feed it to the eager unifier, it will defer without solving it, whereas the main constraint solver would be able to solve it using the injectivity annotation to the type family.
The implementation plan is as follows:
- Change the "constraint defaulting" functions in
GHC.Tc.Solver.Default
to return a collection of new constraints, e.g. changetype CtDefaultingStrategy = Ct -> TcS Bool
totype CtDefaultingStrategy = Ct -> TcS Cts
. This is a straightforward refactoring. - Update the representational case of
defaultEquality
to simply promote the constraint to Nominal and keep going. -
Error messages The main problem with only implementing (1) and (2) is that error messages regress, because now essentially every unsolved representational equality turns to nominal, which suppresses pretty much any mention of "Coercible" or representational equality from error messages. The plan to address that is to use a similar mechanism as
KindEqOrigin
.KindEqOrigin
allows us to report the original type equality instead of a confusingCould not match LiftedRep with WordRep
message. It would make sense to either add a newCtOrigin
constructor for this case (of equalities that started off representational but were promoted to nominal), or even to makeKindEqOrigin
slightly more generic to accommodate this use case.