[GHC] #14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: GHC rejects Unknown/Multiple | valid program Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Consider this program, {{{#!hs {-# LANGUAGE GADTs #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeInType #-} module Test where import GHC.Exts import Data.Kind data TypeRep (a :: k) where Con :: TypeRep (a :: k) TrFun :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) (a :: TYPE r1) (b :: TYPE r2). TypeRep a -> TypeRep b -> TypeRep (a -> b) pattern Fun :: forall k (fun :: k). () => forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) (arg :: TYPE r1) (res :: TYPE r2). (k ~ Type, fun ~~ (arg -> res)) => TypeRep arg -> TypeRep res -> TypeRep fun pattern Fun arg res <- TrFun arg res where Fun arg res = undefined data Dynamic where Dynamic :: forall a. TypeRep a -> a -> Dynamic -- Removing this allows compilation to proceed {-# COMPLETE Con #-} dynApply :: Dynamic -> Dynamic -> Maybe Dynamic -- Changing Fun to TrFun allows compilation to proceed dynApply (Dynamic (Fun ta tr) f) (Dynamic ta' x) = undefined dynApply _ _ = Nothing }}} As written the program fails with, {{{ test.hs:34:1: warning: [-Woverlapping-patterns] Pattern match has inaccessible right hand side In an equation for ‘dynApply’: dynApply (Dynamic (Fun ta tr) f) (Dynamic ta' x) = ... | 34 | dynApply (Dynamic (Fun ta tr) f) (Dynamic ta' x) = undefined | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }}} This can be worked around by doing one of the following, 1. Removing the `COMPLETE` pragma 2. Changing the use of the `Fun` pattern synonym into a use of the `TrFun` constructor. Something is quite wrong here. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * cc: gkaracha, dfeuer (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * cc: RyanGlScott (added) * keywords: => PatternSynonyms, PatternMatchWarnings Comment: Here is a much simpler way to trigger the issue: {{{#!hs {-# LANGUAGE PatternSynonyms #-} module Test where data T = MkT1 | MkT2 pattern MkT2' = MkT2 {-# COMPLETE MkT1 #-} newtype S = MkS T u :: S -> Bool u (MkS MkT2') = True u _ = False }}} The fact that `MkT2'` occurs inside of another constructor `MkS` seems to be important, since changing `u` to be of type `T -> Bool` and matching directly on `MkT2'` in the first case resolves the issue. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): I'm puzzled though. The `{-# COMPLETE MkT1 #-}` pragma seems like a manifest lie. It claims that any matching on `MkT2` is inaccessible doesn't it? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:3 simonpj]:
I'm puzzled though. The `{-# COMPLETE MkT1 #-}` pragma seems like a manifest lie. It claims that any matching on `MkT2` is inaccessible doesn't it?
`COMPLETE` pragmas are allowed to be lies. Perhaps values built from `MkT1` are never visible outside this module. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): OK, but then lies might give rise to error messages or warnings that lie, mightn't they. As here. We need a specification of the expected behaviour of lying COMPLETE pragmas before we can discuss what programs like these "should" do. Or we could say "if the pragma lies, the compiler can do what it likes". -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Ah, I think Ryan's simplification goes a bit too far, perhaps. I think you'll find Ben's original version convincing. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): I'm not sure why the original program would be any more honest, since it claims that matching on `TrFun` is inaccessible, right? That is, `Con` is to `MkT1` as `TrFun` is to `MkT2` as `Fun` is to `MkT2'` as `Dynamic` is to `S` as `dynApply` is to `u`. Or am I missing something? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:7 RyanGlScott]:
I'm not sure why the original program would be any more honest, since it claims that matching on `TrFun` is inaccessible, right? That is, `Con` is to `MkT1` as `TrFun` is to `MkT2` as `Fun` is to `MkT2'` as `Dynamic` is to `S` as `dynApply` is to `u`. Or am I missing something?
Ah, simply because I didn't read it correctly. Ben came to this dishonest reduction from a perfectly honest example! -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

When the pattern match checker requests a set of constructors for a type constructor `T`, we now return a list of sets which include the normal data constructor set and also any `COMPLETE` pragmas of type `T`. We then
#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): Regardless of the example's moral integrity, I posit that it exhibits buggy behavior. First, let's try to hammer out what //should// happen here. There's something of a specification buried in the annals of the GHC wiki [https://ghc.haskell.org/trac/ghc/wiki/PatternSynonyms/CompleteSigs#ErrorMess... here]. (Why is this not in the users' guide?) The relevant bit is: try each of these sets, not warning if any of them are a perfect match. In the case the match isn't perfect, we select one of the branches of the search depending on how good the result is.
The results are prioritised in this order.
1. Fewest uncovered clauses 2. Fewest redundant clauses 3. Fewest inaccessible clauses 4. Whether the match comes from a `COMPLETE` pragma or the built-in set
of data constructors for a type constructor. In the example above, we're matching on something of type `T`, so we have the built-in constructor set `{MkT1, MkT2}` as well as the `COMPLETE` set `{MkT1}`. Since `u` only matches on `MkT2'`, the latter set `{MkT1}` (the `COMPLETE` set) has the fewest number of uncovered clauses, so we use that for reporting warnings. Therefore, the error that we would //expect// to get (but don't, due to this bug) is: {{{ Pattern match(es) are non-exhaustive In a case alternative: Patterns not matched: MkT1 }}} Does that sound agreeable? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj):
Does that sound agreeable?
OK with me. * Do add those rules to the documentation of COMPLETE in the user guide * See also #14135 comment:6, which is in the same territory -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: #11984, #14098 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * related: => #11984, #14098 Comment: Phab:D4005 adds the rules to the GHC users' guide (proofreaders wanted). As for why this bug happens in the first place, I have a strong hunch that there's a symptom in common with #11984 (and #14098). The reason is because while this give a warning: {{{#!hs u :: S -> Bool u (MkS MkT2') = True }}} {{{ Pattern match has inaccessible right hand side In an equation for ‘u’: u (MkS MkT2') = ... }}} You can work around the issue using the same trick in https://ghc.haskell.org/trac/ghc/ticket/11984#comment:7 : {{{#!hs u :: S -> Bool u (MkS x) = case x of MkT2' -> True }}} After this, instead of emitting the garbage inaccessible right-hand-side warning from before, GHC will warn: {{{ Pattern match(es) are non-exhaustive In a case alternative: Patterns not matched: MkT1 }}} As we would expect. So now we need to figure out why there is a discrepancy between the pattern match checker's coverage of `case` and nested constructors. (I'm hoping I gain some insight after talking to SPJ about this part of the codebase tomorrow.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym
is unreachable
-------------------------------------+-------------------------------------
Reporter: bgamari | Owner: (none)
Type: bug | Status: new
Priority: high | Milestone: 8.4.1
Component: Compiler | Version: 8.2.1
Resolution: | Keywords:
| PatternSynonyms,
| PatternMatchWarnings
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC rejects | Unknown/Multiple
valid program | Test Case:
Blocked By: | Blocking:
Related Tickets: #11984, #14098 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by Ben Gamari

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym
is unreachable
-------------------------------------+-------------------------------------
Reporter: bgamari | Owner: (none)
Type: bug | Status: new
Priority: high | Milestone: 8.4.1
Component: Compiler | Version: 8.2.1
Resolution: | Keywords:
| PatternSynonyms,
| PatternMatchWarnings
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC rejects | Unknown/Multiple
valid program | Test Case:
Blocked By: | Blocking:
Related Tickets: #11984, #14098 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by Ryan Scott

#14253: Pattern match checker mistakenly concludes pattern match on pattern synonym is unreachable -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1 Resolution: | Keywords: | PatternSynonyms, | PatternMatchWarnings Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: #11984, #14098 | Differential Rev(s): Phab:D4005 Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * differential: => Phab:D4005 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14253#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC