Pattern match checker should suggest constructors in the range of view pattern instead of the domain
Consider
data D = InternalConstructorIDon'tWannaHearAbout Int Bool Char
predicate :: D -> Bool
predicate (InternalConstructorIDon'tWannaHearAbout i b c) = i >= 0 && b
foo :: D -> Int
foo (predicate -> False) = 3
Today, we'll report
test.hs:12:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘foo’: Patterns of type ‘D’ not matched: _
|
12 | foo (predicate -> False) = 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
and that is rather unhelpful. GHC 9.0 (and I'd expect 9.2 to do so, too) even repported
test.hs:12:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘foo’:
Patterns not matched: InternalConstructorIDon'tWannaHearAbout _ _ _
|
12 | foo (predicate -> False) = 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
mentioning the unhelpful constructor of D
.
Proposal
If there's a view pattern involved, try to report missed patterns in the range of that pattern instead:
test.hs:12:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘foo’:
Patterns not matched: predicate -> True
|
12 | foo (predicate -> False) = 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Open question: What should happen if both view patterns and regular patterns are used? Should we report patterns in the range or the domain? Not sure. In effect, we are trying to decide from which COMPLETE set to report: Either the one from the range (Bool
) or the one from the domain (D
).
(In that way, this ticket is related to #20311 where @sheaf first reported this example. We probably never want to report patterns from the domain if it's comprised of non-exported constructors.)
Challenges
We'd have to identify which pattern variable is associated with the range of a view pat, to be able to "un-desugar" in our reporting mechanism later on.
I don't have time to work on this, but I'd be happy to advise.