Skip to content

Better trace of failed type equalities

Motivation

When type-class instances contain type-equalities, they can be checked much later, in a completely different context, when the instances are being used. Sometimes, they're used very very indirectly, far from the code that invoked the instance.

The error is about a type mismatch, and it is attributed to the code that caused the instance resolution to reach the instance, with no mention of where the type equality was, or the chain of instances that were used to reach it.

Proposal

When a type equality causes a unification failure, the error should include where the type equality was invoked, and the chain of instances used to reach it.

Example

{-# LANGUAGE TypeFamilies #-}
class Example e where
    example :: e -> ()
    example = const ()

instance a ~ Int => Example [a] where

data Bar a = Bar a
instance Example a => Example (Bar a)

bar :: Bar String
bar = Bar "Hello"

f :: ()
f = example bar -- the error complains here only

The error on the "example bar" line is Couldn't match type ‘Char’ with ‘Int’. No mention of how or why it tried to unify Char with Int. Of course in this small example it is easy to figure out. But in a large code-base, with much larger types, it is very difficult to understand why it is complaining - in a position completely unrelated to the real error.

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