
#15681: Take {-# COMPLETE #-} pragma into consideration when using MonadFailDesugaring -------------------------------------+------------------------------------- Reporter: chshersh | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.6.1 Resolution: | Keywords: pattern- | matching,monadfail,desugaring Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): Ah. This is because `isIrrefutableHsPat`, which determines is a pattern warrants a `MonadFail` constraint when matched upon in `do`-notation, [http://git.haskell.org/ghc.git/blob/1d7b61f97f9ec3780a1b7b5bf95a880d56224f4f... treats pattern synonyms quite conservatively]: {{{#!hs isIrrefutableHsPat pat = go pat where go (L _ pat) = go1 pat ... go1 (ConPatOut{ pat_con = L _ (PatSynCon _pat) }) = False -- Conservative ... }}} Compare the [http://git.haskell.org/ghc.git/blob/1d7b61f97f9ec3780a1b7b5bf95a880d56224f4f... treatment] for plain old data constructors: {{{#!hs go1 (ConPatOut{ pat_con = L _ (RealDataCon con), pat_args = details }) = isJust (tyConSingleDataCon_maybe (dataConTyCon con)) && all go (hsConPatArgs details) }}} This essentially says that a plain old data-constructor pattern match is irrefutable if its corresponding data type is inhabited by only one constructor. Could we do the same for pattern synonyms? We certainly could adapt the code for the `RealDataCon` case and reuse it for `PatSynCon`: {{{#!diff diff --git a/compiler/hsSyn/HsPat.hs b/compiler/hsSyn/HsPat.hs index 6f65487..c23c479 100644 --- a/compiler/hsSyn/HsPat.hs +++ b/compiler/hsSyn/HsPat.hs @@ -57,6 +57,7 @@ import Var import RdrName ( RdrName ) import ConLike import DataCon +import PatSyn import TyCon import Outputable import Type @@ -691,8 +692,13 @@ isIrrefutableHsPat pat -- NB: tyConSingleDataCon_maybe, *not* isProductTyCon, because -- the latter is false of existentials. See Trac #4439 && all go (hsConPatArgs details) - go1 (ConPatOut{ pat_con = L _ (PatSynCon _pat) }) - = False -- Conservative + go1 (ConPatOut{ pat_con = L _ (PatSynCon pat), pat_args = details }) + | (_, _, _, _, _, res_ty) <- patSynSig pat + , Just tc <- tyConAppTyCon_maybe res_ty + = isJust (tyConSingleDataCon_maybe tc) + && all go (hsConPatArgs details) + | otherwise + = False -- Conservative go1 (LitPat {}) = False go1 (NPat {}) = False }}} While this fixes the particular example in this ticket, it's a bit dodgy. That's because it's determining if a pattern synonym is irrefutable by consulting the plain old data constructors that correspond to the type constructor that heads its return type. This is a bit of an impedance mismatch since exhaustiveness checking for pattern synonyms can only ever really be done in the context of one or more user-defined `COMPLETE` sets. It's not clear to me if `isIrrefutableHsPat` could be changed to take `COMPLETE` sets into account. The code to look up `COMPLETE` sets, [http://git.haskell.org/ghc.git/blob/d00c308633fe7d216d31a1087e00e63532d87d6d... dsGetCompleteMatches], lives in the `DsM` monad, while `isIrrefutableHsPat` is pure. Moreover, `isIrrefutableHsPat` has call sites that are outside of `DsM`, so it's unclear to me if we could factor out the monadic parts of `dsGetCompleteMatches`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15681#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler