Structured diagnostics usecase: hole fix messages
This is output of a brainstorming session with me and David Christiansen.
Take the following error message for a hole:
• Found hole: _ :: Int -> Int -> [a]
Where: ‘a’ is a rigid type variable bound by
the type signature for:
foo :: forall a. Int -> Int -> [a]
at /home/davidc/tmp/Foo.hs3️⃣1-24
• In the expression: let bar = id in _
In an equation for ‘foo’: foo = let bar = id in _
• Relevant bindings include
bar :: forall {a}. a -> a (bound at /home/davidc/tmp/Foo.hs5️⃣7)
foo :: Int -> Int -> [a] (bound at /home/davidc/tmp/Foo.hs4️⃣1)
Valid hole fits include
foo
mempty
Valid refinement hole fits include
curry _
($) _
($!) _
const _
flip _
pure _
return _
bar _
id _
mconcat _
(Some refinement hole fits suppressed; use -fmax-refinement-hole-fits=N or -fno-max-refinement-hole-fits) (lsp)
There is a lot of information here, which makes it difficult for David to find the most relevant bits of the message. David would like something like this:
Hole:
bar :: forall {a}. a -> a
foo :: Int -> Int -> [a]
⊢ _ :: Int -> Int -> [a]
First thing: maybe we could rewrite the core message of the hole fit error to look more like this.
But also we'd like to not include the additional information in the text, since it makes it very long. But we don't want to lose it. Fortunately in e.g. LSP we can provide that information as part of the actual structure of the diagnostic.
Relevant LSP diagnostic fields:
- Location
- Related locations
This would let us get rid of
In the expression: let bar = id in _
In an equation for ‘foo’: foo = let bar = id in _
(location)
Where: ‘a’ is a rigid type variable bound by
the type signature for:
foo :: forall a. Int -> Int -> [a]
at /home/davidc/tmp/Foo.hs3️⃣1-24
(related location)
Relevant bindings include
bar :: forall {a}. a -> a (bound at /home/davidc/tmp/Foo.hs5️⃣7)
foo :: Int -> Int -> [a] (bound at /home/davidc/tmp/Foo.hs4️⃣1)
(related location)
Additionally, the valid hole fit information really conveys possible quickfixes. I think the structured diagnostics infrastructure already has a field for possible fixes, but we should add some for these fixes. So that lets us get rid of:
Valid hole fits include
foo
mempty
Valid refinement hole fits include
curry _
($) _
($!) _
const _
flip _
pure _
return _
bar _
id _
mconcat _
(Some refinement hole fits suppressed; use -fmax-refinement-hole-fits=N or -fno-max-refinement-hole-fits) (lsp)
(quickfixes)
Finally, if we want to render the main error message in HLS, we'd still like to use a function from GHC to do so, but we'd want some way to tell it to omit some or all of these pieces from the message text itself, since we're going to handle them via specific fields.