Open BinderDavid opened 2 years ago
Thanks for posting this! And thanks for including a concrete suggestion for improvement.
I agree that the new output is correct. Why do you think the new output is better? That is, I can't come up with a reason that applying the substitution leads to a better message than not applying it. Maybe thinking in terms of a
is easier. Maybe the problem is that the error message is mixed? We have _ :: Bool
at the top, but references to a
elsewhere.
On the other hand, we might be able to do better in stating the constraint. Specifically, instead of
Constraints include a ~ Bool (from example.hs:10:3-12)
we could have
In this context, 'a' is known to be 'Bool' (from a GADT pattern match at example.hs:10:3-12)
I agree that the new output is correct. Why do you think the new output is better? That is, I can't come up with a reason that applying the substitution leads to a better message than not applying it
Maybe it comes down to a question of preferences, but I will try to give my pseudo-objective reasons for prefering my suggested error message.
f :: Int -> Bool
to f :: (a ~ Int, b ~ Bool) => a -> b
. The unsolved constraints should only appear whenever it is not possible to solve/substitute them.a ~ Bool
applies only to the binding x :: Expr a
, but not to the binding foo :: Expr a -> Bool
. (Btw, does this qualify as a bug? The typed hole seems to suggest that foo
can only be used at type Expr Bool -> Bool
, while it can actually be used at type forall a. Expr a -> Bool
.)Hm, this does seem like a bug since the type signature of foo
makes polymorphic recursion possible in the hole; foo
should be shown with either a renamed type variable or an explicit forall. Contrariwise, x
can only be used at type Expr Bool
or Expr a
for the inherited a
which is equal to Bool
...
The error messages when using typed holes on the RHS of a pattern match on GADT constructors are not optimal, since type equality constraints are left unresolved and not applied as substitutions. (Tested with GHC 8.6, 8.10 and 9.2.1). Understanding the error message requires understanding both GADTs and the implementation of GADTs with the help of type equality constraints.
Example
Consider the following snippet:
The error message I get (shortened):
This error message correctly identifies the constraint
a ~ Bool
which came into context by pattern matching on the GADT constructorExprBool
. But understanding this error message requires understanding how GADT constructors are desugared internally (intoExprBool :: forall a. a ~ Bool => Bool -> Expr a
)The error message I would ideally expect would turn this constraint into a substitution and apply it:
I am not very familiar with GHC internals, in particular how closely GHC follows the implementation described in the OutsideIn paper, but the problem is probably that
a
is considered an untouchable unification variable within the implication constraint generated for the RHS of the pattern match. But for the typed hole, the unification variablea
should probably be allowed to unify with Bool. (Except for the occurrence infoo
, of course).