[GHC] #14273: Typed holes' "valid substitutions" suggestions are oblivious to type class constraints
GHC
ghc-devs at haskell.org
Tue Sep 26 14:45:38 UTC 2017
#14273: Typed holes' "valid substitutions" suggestions are oblivious to type class
constraints
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner: Tritlo
Type: bug | Status: new
Priority: normal | Milestone: 8.4.1
Component: Compiler (Type | Version: 8.3
checker) |
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
Type of failure: Poor/confusing | Unknown/Multiple
error message | Test Case:
Blocked By: | Blocking:
Related Tickets: #9091, #9479 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by simonpj):
It's easy to get confused here. First consider
{{{
foo :: [a] -> String
foo xs = show (_h ++ [])
}}}
We end up with this residual constraint
{{{
forall a.
[W] Show alpha
[Hole] _h :: [alpha]
}}}
where `alpha` is a unification variable, standing for an as-yet-unknown
type. The
two unsolved constraints are
* The `[Hole]` constraint feeds the error-report mechanism, reporting that
`_h` must be filled vith a value of type `[alpha]`.
* The `Show alpha` constraint arises from the call of `show`. Initially
we'd get a `Show [alpha]` constraint, but we use the instance declaration
`instance Show x => Show [x]` to reduce it to `Show alpha`.
Now, what can we fill the hole with? Clearly something of form `[ty]`.
But once we know what we fill it with, we can set `alpha := ty`, and then
we want for the rest of the constraints to be soluble, in this case `Show
alpha`. So filling with `[Int]` would be fine, but filling with `[Int ->
Int]` would not.
Filling with `[a]` would not work either, since we have no way to solve
`Show a`.
However, if the original definition had been
{{{
foo :: Show a => [a] -> String
foo xs = show (_h ++ [])
}}}
we'd end up with the residual constraint
{{{
forall a. Show a =>
[W] Show alpha
[Hole] _h :: [alpha]
}}}
then we ''could'' fill `_h` with `xs :: [a]`, because we now do have a
`Show a` in scope
from the type signature.
TL;DR: the real question is this:
* After filling the hole, can we solve the '''rest of the constraint'''?
Sadly, that's not a very easy question to answer.
* The current architecture focuses on the `[Hole]` constraint all by
itself, but this example shows that it's really all about that
constraint's peers.
* There may be many unsolved constraints; filling one hole will not
nail all of them, so we might erroneously reject a filler. For example
{{{
[W] C alpha beta
[Hole] _h1 :: alpha
[Hole] _h2 :: beta
}}}
Here we'll never succeed in solving `C alpha beta` until we have
simultaneously
filled both holes with compatible types.
* Operationally, constraint solving may perform unification. And
unification
is (currently) done by side-effect, and not easily undone. So trying
successive
candidates for hole-filling risks prematurely fixing the unification
variables.
In full generality this looks too hard. But I think you might be able to
do
a reasonable job for common cases. For example
* Given a contraint
{{{
forall as1. G1 => ...
(forall as2. G2 =>
[Hole] _h :: ty
C1, ..., Cn
)...
}}}
pick the subset of Ci whose free unification variables are all mentioned
in `ty`, say D1..Dm
* Pick a candidate `cand :: cand_ty` to fill `_h`.
* Clone any free unification variables
* Try to solve the constraint
{{{
forall as1. G1 =>
(forall as2. G2 =>
cand_ty <= ty -- subsumes
D1, ..., Dm
)
}}}
This isn't perfect, but it'd work in common cases I think.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14273#comment:11>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list