Skip to content

-Wincomplete-patterns gets confused when combining GADTs and pattern guards

Consider the following code:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wincomplete-patterns #-}
module Bug where

import Data.Kind

data family Sing :: forall k. k -> Type
newtype Id a = MkId a
data So :: Bool -> Type where
  Oh :: So True

data instance Sing :: Bool -> Type where
  SFalse :: Sing False
  STrue  :: Sing True
data instance Sing :: Ordering -> Type where
  SLT :: Sing LT
  SEQ :: Sing EQ
  SGT :: Sing GT
data instance Sing :: forall a. Id a -> Type where
  SMkId :: Sing x -> Sing (MkId x)

class POrd a where
  type (x :: a) `Compare` (y :: a) :: Ordering

class SOrd a where
  sCompare :: forall (x :: a) (y :: a).
              Sing x -> Sing y -> Sing (x `Compare` y)

type family (x :: a) <= (y :: a) :: Bool where
  x <= y = LeqCase (x `Compare` y)
type family LeqCase (o :: Ordering) :: Bool where
  LeqCase LT = True
  LeqCase EQ = True
  LeqCase GT = False

(%<=) :: forall a (x :: a) (y :: a). SOrd a
      => Sing x -> Sing y -> Sing (x <= y)
sx %<= sy =
  case sx `sCompare` sy of
    SLT -> STrue
    SEQ -> STrue
    SGT -> SFalse

class (POrd a, SOrd a) => VOrd a where
  leqReflexive :: forall (x :: a). Sing x -> So (x <= x)

instance POrd a => POrd (Id a) where
  type MkId x `Compare` MkId y = x `Compare` y

instance SOrd a => SOrd (Id a) where
  SMkId sx `sCompare` SMkId sy = sx `sCompare` sy

-----

instance VOrd a => VOrd (Id a) where
  leqReflexive (SMkId sa)
    | Oh <- leqReflexive sa
    = case sa `sCompare` sa of
        SLT -> Oh
        SEQ -> Oh
        -- SGT -> undefined

What exactly this code does isn't terribly important. The important bit is that last instance (VOrd (Id a)). That //should// be total, but GHC disagrees:

GHCi, version 8.6.0.20180627: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling Bug              ( Bug.hs, interpreted )

Bug.hs:63:7: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In a case alternative: Patterns not matched: SGT
   |
63 |     = case sa `sCompare` sa of
   |       ^^^^^^^^^^^^^^^^^^^^^^^^...

As evidence that this warning is bogus, if you uncomment the last line, then GHC correctly observes that that line is inaccessible:

GHCi, version 8.6.0.20180627: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling Bug              ( Bug.hs, interpreted )

Bug.hs:66:9: warning: [-Winaccessible-code]
    • Couldn't match type ‘'True’ with ‘'False’
      Inaccessible code in
        a pattern with constructor: SGT :: Sing 'GT, in a case alternative
    • In the pattern: SGT
      In a case alternative: SGT -> undefined
      In the expression:
        case sa `sCompare` sa of
          SLT -> Oh
          SEQ -> Oh
          SGT -> undefined
   |
66 |         SGT -> undefined
   |         ^^^

Clearly, something is afoot in the coverage checker.

Trac metadata
Trac field Value
Version 8.5
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information