MonadFail proposal, phase 1
authorDavid Luposchainsky <dluposchainsky@gmail.com>
Tue, 17 Nov 2015 16:10:02 +0000 (17:10 +0100)
committerBen Gamari <bgamari.foss@gmail.com>
Tue, 17 Nov 2015 17:29:09 +0000 (12:29 -0500)
This implements phase 1 of the MonadFail proposal (MFP, #10751).

- MonadFail warnings are all issued as desired, tunable with two new flags
- GHC was *not* made warning-free with `-fwarn-missing-monadfail-warnings`
  (but it's disabled by default right now)

Credits/thanks to
- Franz Thoma, whose help was crucial to implementing this
- My employer TNG Technology Consulting GmbH for partially funding us
  for this work

Reviewers: goldfire, austin, #core_libraries_committee, hvr, bgamari, fmthoma

Reviewed By: hvr, bgamari, fmthoma

Subscribers: thomie

Projects: #ghc

Differential Revision: https://phabricator.haskell.org/D1248

GHC Trac Issues: #10751

35 files changed:
compiler/coreSyn/CoreLint.hs
compiler/hsSyn/HsExpr.hs
compiler/main/DynFlags.hs
compiler/parser/Lexer.x
compiler/prelude/PrelNames.hs
compiler/prelude/PrelRules.hs
compiler/rename/RnEnv.hs
compiler/rename/RnExpr.hs
compiler/specialise/Specialise.hs
compiler/typecheck/TcArrows.hs
compiler/typecheck/TcErrors.hs
compiler/typecheck/TcMatches.hs
compiler/typecheck/TcRnDriver.hs
compiler/typecheck/TcRnTypes.hs
compiler/typecheck/TcSMonad.hs
compiler/types/Unify.hs
compiler/utils/IOEnv.hs
compiler/utils/Maybes.hs
docs/users_guide/glasgow_exts.rst
docs/users_guide/using-warnings.rst
libraries/base/Control/Monad.hs
libraries/base/Text/ParserCombinators/ReadP.hs
libraries/base/Text/ParserCombinators/ReadPrec.hs
testsuite/tests/driver/T4437.hs
testsuite/tests/monadfail/MonadFailErrors.hs [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailErrors.stderr [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailWarnings.hs [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailWarnings.stderr [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailWarningsDisabled.hs [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.hs [new file with mode: 0644]
testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.stderr [new file with mode: 0644]
testsuite/tests/monadfail/all.T [new file with mode: 0644]
testsuite/tests/rebindable/rebindable1.hs
testsuite/tests/rebindable/rebindable6.hs
testsuite/tests/rebindable/rebindable6.stderr

index da08c21..00a7fd0 100644 (file)
@@ -64,6 +64,9 @@ import Demand ( splitStrictSig, isBotRes )
 import HscTypes
 import DynFlags
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 import MonadUtils
 import Data.Maybe
 import Pair
@@ -1503,6 +1506,11 @@ instance Monad LintM where
                            Just r -> unLintM (k r) env errs'
                            Nothing -> (Nothing, errs'))
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail LintM where
+    fail err = failWithL (text err)
+#endif
+
 instance HasDynFlags LintM where
   getDynFlags = LintM (\ e errs -> (Just (le_dynflags e), errs))
 
index 8a733ad..09717b7 100644 (file)
@@ -1336,7 +1336,7 @@ data StmtLR idL idR body -- body should always be (LHs**** idR)
   -- For details on above see note [Api annotations] in ApiAnnotation
   | BindStmt (LPat idL)
              body
-             (SyntaxExpr idR) -- The (>>=) operator; see Note [The type of bind]
+             (SyntaxExpr idR) -- The (>>=) operator; see Note [The type of bind in Stmts]
              (SyntaxExpr idR) -- The fail operator
              -- The fail operator is noSyntaxExpr
              -- if the pattern match can't fail
index 5f63b10..45fb72e 100644 (file)
@@ -505,6 +505,7 @@ data WarningFlag =
    | Opt_WarnWarningsDeprecations
    | Opt_WarnDeprecatedFlags
    | Opt_WarnAMP
+   | Opt_WarnMissingMonadFailInstance
    | Opt_WarnDodgyExports
    | Opt_WarnDodgyImports
    | Opt_WarnOrphans
@@ -656,6 +657,7 @@ data ExtensionFlag
    | Opt_StaticPointers
    | Opt_Strict
    | Opt_StrictData
+   | Opt_MonadFailDesugaring
    deriving (Eq, Enum, Show)
 
 type SigOf = Map ModuleName Module
@@ -2898,6 +2900,7 @@ fWarningFlags = [
   flagSpec "warn-missing-import-lists"        Opt_WarnMissingImportList,
   flagSpec "warn-missing-local-sigs"          Opt_WarnMissingLocalSigs,
   flagSpec "warn-missing-methods"             Opt_WarnMissingMethods,
+  flagSpec "warn-missing-monadfail-instance"  Opt_WarnMissingMonadFailInstance,
   flagSpec "warn-missing-signatures"          Opt_WarnMissingSigs,
   flagSpec "warn-missing-exported-sigs"       Opt_WarnMissingExportedSigs,
   flagSpec "warn-monomorphism-restriction"    Opt_WarnMonomorphism,
@@ -3168,6 +3171,7 @@ xFlags = [
   flagSpec "LiberalTypeSynonyms"              Opt_LiberalTypeSynonyms,
   flagSpec "MagicHash"                        Opt_MagicHash,
   flagSpec "MonadComprehensions"              Opt_MonadComprehensions,
+  flagSpec "MonadFailDesugaring"              Opt_MonadFailDesugaring,
   flagSpec "MonoLocalBinds"                   Opt_MonoLocalBinds,
   flagSpec' "MonoPatBinds"                    Opt_MonoPatBinds
     (\ turn_on -> when turn_on $
index 8f29a27..da9424d 100644 (file)
@@ -78,6 +78,9 @@ module Lexer (
 import Control.Applicative
 #endif
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import Control.Monad.Fail
+#endif
 import Data.Bits
 import Data.Char
 import Data.List
@@ -1755,6 +1758,11 @@ instance Monad P where
   (>>=) = thenP
   fail = failP
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail P where
+  fail = failP
+#endif
+
 returnP :: a -> P a
 returnP a = a `seq` (P $ \s -> POk s a)
 
index 346f3a3..1b1ffaa 100644 (file)
@@ -239,10 +239,11 @@ basicKnownKeyNames
         apAName,
 
         -- Monad stuff
-        thenIOName, bindIOName, returnIOName, failIOName,
-        failMName, bindMName, thenMName, returnMName,
-        fmapName,
-        joinMName,
+        thenIOName, bindIOName, returnIOName, failIOName, bindMName, thenMName,
+        returnMName, fmapName, joinMName,
+
+        -- MonadFail
+        monadFailClassName, failMName, failMName_preMFP,
 
         -- MonadFix
         monadFixClassName, mfixName,
@@ -408,7 +409,7 @@ gHC_PRIM, gHC_TYPES, gHC_GENERICS, gHC_MAGIC,
     gHC_ST, gHC_ARR, gHC_STABLE, gHC_PTR, gHC_ERR, gHC_REAL,
     gHC_FLOAT, gHC_TOP_HANDLER, sYSTEM_IO, dYNAMIC,
     tYPEABLE, tYPEABLE_INTERNAL, gENERICS,
-    rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_ZIP,
+    rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_ZIP, mONAD_FAIL,
     aRROW, cONTROL_APPLICATIVE, gHC_DESUGAR, rANDOM, gHC_EXTS,
     cONTROL_EXCEPTION_BASE, gHC_TYPELITS :: Module
 
@@ -456,6 +457,7 @@ gHC_WORD        = mkBaseModule (fsLit "GHC.Word")
 mONAD           = mkBaseModule (fsLit "Control.Monad")
 mONAD_FIX       = mkBaseModule (fsLit "Control.Monad.Fix")
 mONAD_ZIP       = mkBaseModule (fsLit "Control.Monad.Zip")
+mONAD_FAIL      = mkBaseModule (fsLit "Control.Monad.Fail")
 aRROW           = mkBaseModule (fsLit "Control.Arrow")
 cONTROL_APPLICATIVE = mkBaseModule (fsLit "Control.Applicative")
 gHC_DESUGAR = mkBaseModule (fsLit "GHC.Desugar")
@@ -566,11 +568,12 @@ map_RDR, append_RDR :: RdrName
 map_RDR                 = varQual_RDR gHC_BASE (fsLit "map")
 append_RDR              = varQual_RDR gHC_BASE (fsLit "++")
 
-foldr_RDR, build_RDR, returnM_RDR, bindM_RDR, failM_RDR :: RdrName
+foldr_RDR, build_RDR, returnM_RDR, bindM_RDR, failM_RDR_preMFP, failM_RDR:: RdrName
 foldr_RDR               = nameRdrName foldrName
 build_RDR               = nameRdrName buildName
 returnM_RDR             = nameRdrName returnMName
 bindM_RDR               = nameRdrName bindMName
+failM_RDR_preMFP        = nameRdrName failMName_preMFP
 failM_RDR               = nameRdrName failMName
 
 left_RDR, right_RDR :: RdrName
@@ -912,12 +915,17 @@ functorClassName  = clsQual gHC_BASE    (fsLit "Functor") functorClassKey
 fmapName          = varQual gHC_BASE    (fsLit "fmap")    fmapClassOpKey
 
 -- Class Monad
-monadClassName, thenMName, bindMName, returnMName, failMName :: Name
+monadClassName, thenMName, bindMName, returnMName, failMName_preMFP :: Name
 monadClassName     = clsQual gHC_BASE (fsLit "Monad")  monadClassKey
 thenMName          = varQual gHC_BASE (fsLit ">>")     thenMClassOpKey
 bindMName          = varQual gHC_BASE (fsLit ">>=")    bindMClassOpKey
 returnMName        = varQual gHC_BASE (fsLit "return") returnMClassOpKey
-failMName          = varQual gHC_BASE (fsLit "fail")   failMClassOpKey
+failMName_preMFP   = varQual gHC_BASE (fsLit "fail")   failMClassOpKey_preMFP
+
+-- Class MonadFail
+monadFailClassName, failMName :: Name
+monadFailClassName = clsQual mONAD_FAIL (fsLit "MonadFail") monadFailClassKey
+failMName          = varQual mONAD_FAIL (fsLit "fail")      failMClassOpKey
 
 -- Classes (Applicative, Foldable, Traversable)
 applicativeClassName, foldableClassName, traversableClassName :: Name
@@ -1385,6 +1393,9 @@ typeable7ClassKey       = mkPreludeClassUnique 27
 monadFixClassKey :: Unique
 monadFixClassKey        = mkPreludeClassUnique 28
 
+monadFailClassKey :: Unique
+monadFailClassKey       = mkPreludeClassUnique 29
+
 monadPlusClassKey, randomClassKey, randomGenClassKey :: Unique
 monadPlusClassKey       = mkPreludeClassUnique 30
 randomClassKey          = mkPreludeClassUnique 31
@@ -1951,14 +1962,14 @@ uniques so we can look them up easily when we want to conjure them up
 during type checking.
 -}
 
-        -- Just a place holder for  unbound variables  produced by the renamer:
+-- Just a placeholder for unbound variables produced by the renamer:
 unboundKey :: Unique
 unboundKey                    = mkPreludeMiscIdUnique 158
 
 fromIntegerClassOpKey, minusClassOpKey, fromRationalClassOpKey,
     enumFromClassOpKey, enumFromThenClassOpKey, enumFromToClassOpKey,
     enumFromThenToClassOpKey, eqClassOpKey, geClassOpKey, negateClassOpKey,
-    failMClassOpKey, bindMClassOpKey, thenMClassOpKey, returnMClassOpKey,
+    failMClassOpKey_preMFP, bindMClassOpKey, thenMClassOpKey, returnMClassOpKey,
     fmapClassOpKey
     :: Unique
 fromIntegerClassOpKey         = mkPreludeMiscIdUnique 160
@@ -1971,7 +1982,7 @@ enumFromThenToClassOpKey      = mkPreludeMiscIdUnique 166
 eqClassOpKey                  = mkPreludeMiscIdUnique 167
 geClassOpKey                  = mkPreludeMiscIdUnique 168
 negateClassOpKey              = mkPreludeMiscIdUnique 169
-failMClassOpKey               = mkPreludeMiscIdUnique 170
+failMClassOpKey_preMFP        = mkPreludeMiscIdUnique 170
 bindMClassOpKey               = mkPreludeMiscIdUnique 171 -- (>>=)
 thenMClassOpKey               = mkPreludeMiscIdUnique 172 -- (>>)
 fmapClassOpKey                = mkPreludeMiscIdUnique 173
@@ -1981,6 +1992,10 @@ returnMClassOpKey             = mkPreludeMiscIdUnique 174
 mfixIdKey :: Unique
 mfixIdKey       = mkPreludeMiscIdUnique 175
 
+-- MonadFail operations
+failMClassOpKey :: Unique
+failMClassOpKey = mkPreludeMiscIdUnique 176
+
 -- Arrow notation
 arrAIdKey, composeAIdKey, firstAIdKey, appAIdKey, choiceAIdKey,
     loopAIdKey :: Unique
@@ -2086,7 +2101,7 @@ standardClassKeys :: [Unique]
 standardClassKeys = derivableClassKeys ++ numericClassKeys
                   ++ [randomClassKey, randomGenClassKey,
                       functorClassKey,
-                      monadClassKey, monadPlusClassKey,
+                      monadClassKey, monadPlusClassKey, monadFailClassKey,
                       isStringClassKey,
                       applicativeClassKey, foldableClassKey,
                       traversableClassKey, alternativeClassKey
index 919a1d5..68140f7 100644 (file)
@@ -55,6 +55,9 @@ import Control.Applicative ( Applicative(..), Alternative(..) )
 #endif
 
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 import Data.Bits as Bits
 import qualified Data.ByteString as BS
 import Data.Int
@@ -653,6 +656,11 @@ instance Monad RuleM where
     Just r -> runRuleM (g r) dflags iu e
   fail _ = mzero
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail RuleM where
+    fail _ = mzero
+#endif
+
 instance Alternative RuleM where
     empty = mzero
     (<|>) = mplus
index 1e8eb27..c0d88e9 100644 (file)
@@ -1441,8 +1441,8 @@ lookupIfThenElse :: RnM (Maybe (SyntaxExpr Name), FreeVars)
 -- case we desugar directly rather than calling an existing function
 -- Hence the (Maybe (SyntaxExpr Name)) return type
 lookupIfThenElse
-  = do { rebind <- xoptM Opt_RebindableSyntax
-       ; if not rebind
+  = do { rebindable_on <- xoptM Opt_RebindableSyntax
+       ; if not rebindable_on
          then return (Nothing, emptyFVs)
          else do { ite <- lookupOccRn (mkVarUnqual (fsLit "ifThenElse"))
                  ; return (Just (HsVar ite), unitFV ite) } }
index d748bf0..a8b1d2e 100644 (file)
@@ -10,7 +10,8 @@ general, all of these functions return a renamed thing, and a set of
 free variables.
 -}
 
-{-# LANGUAGE CPP, ScopedTypeVariables, RecordWildCards #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
 module RnExpr (
         rnLExpr, rnExpr, rnStmts
@@ -787,7 +788,12 @@ rnStmt ctxt rnBody (L loc (BindStmt pat body _ _)) thing_inside
   = do  { (body', fv_expr) <- rnBody body
                 -- The binders do not scope over the expression
         ; (bind_op, fvs1) <- lookupStmtName ctxt bindMName
-        ; (fail_op, fvs2) <- lookupStmtName ctxt failMName
+
+        ; xMonadFailEnabled <- fmap (xopt Opt_MonadFailDesugaring) getDynFlags
+        ; let failFunction | xMonadFailEnabled = failMName
+                           | otherwise         = failMName_preMFP
+        ; (fail_op, fvs2) <- lookupSyntaxName failFunction
+
         ; rnPat (StmtCtxt ctxt) pat $ \ pat' -> do
         { (thing, fvs3) <- thing_inside (collectPatBinders pat')
         ; return (( [(L loc (BindStmt pat' body' bind_op fail_op), fv_expr)]
@@ -1091,7 +1097,12 @@ rn_rec_stmt rnBody _ (L loc (BodyStmt body _ _ _), _)
 rn_rec_stmt rnBody _ (L loc (BindStmt pat' body _ _), fv_pat)
   = do { (body', fv_expr) <- rnBody body
        ; (bind_op, fvs1) <- lookupSyntaxName bindMName
-       ; (fail_op, fvs2) <- lookupSyntaxName failMName
+
+       ; xMonadFailEnabled <- fmap (xopt Opt_MonadFailDesugaring) getDynFlags
+       ; let failFunction | xMonadFailEnabled = failMName
+                          | otherwise         = failMName_preMFP
+       ; (fail_op, fvs2) <- lookupSyntaxName failFunction
+
        ; let bndrs = mkNameSet (collectPatBinders pat')
              fvs   = fv_expr `plusFV` fv_pat `plusFV` fvs1 `plusFV` fvs2
        ; return [(bndrs, fvs, bndrs `intersectNameSet` fvs,
index 31d8212..cb671be 100644 (file)
@@ -40,6 +40,9 @@ import State
 import Control.Applicative (Applicative(..))
 #endif
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 import Data.Map (Map)
 import qualified Data.Map as Map
 import qualified FiniteMap as Map
@@ -2088,6 +2091,11 @@ instance Monad SpecM where
     return = pure
     fail str = SpecM $ fail str
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail SpecM where
+    fail str = SpecM $ fail str
+#endif
+
 instance MonadUnique SpecM where
     getUniqueSupplyM
         = SpecM $ do st <- get
index bb7a374..0d6e185 100644 (file)
@@ -354,7 +354,7 @@ tcArrDoStmt env ctxt (BindStmt pat rhs _ _) res_ty thing_inside
   = do  { (rhs', pat_ty) <- tc_arr_rhs env rhs
         ; (pat', thing)  <- tcPat (StmtCtxt ctxt) pat pat_ty $
                             thing_inside res_ty
-        ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+        ; return (mkBindStmt pat' rhs', thing) }
 
 tcArrDoStmt env ctxt (RecStmt { recS_stmts = stmts, recS_later_ids = later_names
                             , recS_rec_ids = rec_names }) res_ty thing_inside
index 5fdd7de..011b702 100644 (file)
@@ -463,12 +463,23 @@ mkGroupReporter mk_err ctxt cts
 
 reportGroup :: (ReportErrCtxt -> [Ct] -> TcM ErrMsg) -> ReportErrCtxt
             -> [Ct] -> TcM ()
-reportGroup mk_err ctxt cts
-  = do { err <- mk_err ctxt cts
-       ; maybeReportError ctxt err
-       ; mapM_ (maybeAddDeferredBinding ctxt err) cts }
-               -- Add deferred bindings for all
-               -- But see Note [Always warn with -fdefer-type-errors]
+reportGroup mk_err ctxt cts =
+  case partition isMonadFailInstanceMissing cts of
+        -- Only warn about missing MonadFail constraint when
+        -- there are no other missing contstraints!
+        (monadFailCts, []) -> do { err <- mk_err ctxt monadFailCts
+                                 ; reportWarning err }
+
+        (_, cts') -> do { err <- mk_err ctxt cts'
+                        ; maybeReportError ctxt err
+                        ; mapM_ (maybeAddDeferredBinding ctxt err) cts' }
+                                -- Add deferred bindings for all
+                                -- But see Note [Always warn with -fdefer-type-errors]
+  where
+    isMonadFailInstanceMissing ct =
+        case ctLocOrigin (ctLoc ct) of
+            FailablePattern _pat -> True
+            _otherwise           -> False
 
 maybeReportHoleError :: ReportErrCtxt -> Ct -> ErrMsg -> TcM ()
 maybeReportHoleError ctxt ct err
index d7dbddf..b504206 100644 (file)
@@ -6,7 +6,9 @@
 TcMatches: Typecheck some @Matches@
 -}
 
-{-# LANGUAGE CPP, RankNTypes #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE MultiWayIf #-}
 
 module TcMatches ( tcMatchesFun, tcGRHS, tcGRHSsPat, tcMatchesCase, tcMatchLambda,
                    TcMatchCtxt(..), TcStmtChecker, TcExprStmtChecker, TcCmdStmtChecker,
@@ -36,6 +38,10 @@ import Outputable
 import Util
 import SrcLoc
 import FastString
+import DynFlags
+import PrelNames (monadFailClassName)
+import Type
+import Inst
 
 -- Create chunkified tuple tybes for monad comprehensions
 import MkCore
@@ -517,15 +523,18 @@ tcMcStmt ctxt (BindStmt pat rhs bind_op fail_op) res_ty thing_inside
         ; bind_op'   <- tcSyntaxOp MCompOrigin bind_op
                              (mkFunTys [rhs_ty, mkFunTy pat_ty new_res_ty] res_ty)
 
-           -- If (but only if) the pattern can fail, typecheck the 'fail' operator
+        -- If (but only if) the pattern can fail, typecheck the 'fail' operator
         ; fail_op' <- if isIrrefutableHsPat pat
-                      then return noSyntaxExpr
-                      else tcSyntaxOp MCompOrigin fail_op (mkFunTy stringTy new_res_ty)
+            then return noSyntaxExpr
+            else tcSyntaxOp MCompOrigin fail_op (mkFunTy stringTy new_res_ty)
 
         ; rhs' <- tcMonoExprNC rhs rhs_ty
+
         ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat pat_ty $
                            thing_inside new_res_ty
 
+        ; monadFailWarnings pat' new_res_ty
+
         ; return (BindStmt pat' rhs' bind_op' fail_op', thing) }
 
 -- Boolean expressions.
@@ -764,16 +773,18 @@ tcDoStmt ctxt (BindStmt pat rhs bind_op fail_op) res_ty thing_inside
         ; bind_op'   <- tcSyntaxOp DoOrigin bind_op
                              (mkFunTys [rhs_ty, mkFunTy pat_ty new_res_ty] res_ty)
 
-                -- If (but only if) the pattern can fail,
-                -- typecheck the 'fail' operator
+        -- If (but only if) the pattern can fail, typecheck the 'fail' operator
         ; fail_op' <- if isIrrefutableHsPat pat
-                      then return noSyntaxExpr
-                      else tcSyntaxOp DoOrigin fail_op (mkFunTy stringTy new_res_ty)
+            then return noSyntaxExpr
+            else tcSyntaxOp DoOrigin fail_op (mkFunTy stringTy new_res_ty)
 
         ; rhs' <- tcMonoExprNC rhs rhs_ty
+
         ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat pat_ty $
                            thing_inside new_res_ty
 
+        ; monadFailWarnings pat' new_res_ty
+
         ; return (BindStmt pat' rhs' bind_op' fail_op', thing) }
 
 tcDoStmt ctxt (ApplicativeStmt pairs mb_join _) res_ty thing_inside
@@ -847,6 +858,8 @@ tcDoStmt ctxt (RecStmt { recS_stmts = stmts, recS_later_ids = later_names
 tcDoStmt _ stmt _ _
   = pprPanic "tcDoStmt: unexpected Stmt" (ppr stmt)
 
+
+
 {-
 Note [Treat rebindable syntax first]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -859,6 +872,64 @@ Otherwise the error shows up when cheking the rebindable syntax, and
 the expected/inferred stuff is back to front (see Trac #3613).
 -}
 
+
+
+---------------------------------------------------
+-- MonadFail Proposal warnings
+---------------------------------------------------
+
+-- The idea behind issuing MonadFail warnings is that we add them whenever a
+-- failable pattern is encountered. However, instead of throwing a type error
+-- when the constraint cannot be satisfied, we only issue a warning in
+-- TcErrors.hs.
+
+monadFailWarnings :: LPat TcId -> TcType -> TcRn ()
+monadFailWarnings pat doExprType = unless (isIrrefutableHsPat pat) $ do
+    rebindableSyntax <- xoptM Opt_RebindableSyntax
+    desugarFlag      <- xoptM Opt_MonadFailDesugaring
+    missingWarning   <- woptM Opt_WarnMissingMonadFailInstance
+    if | rebindableSyntax && (desugarFlag || missingWarning)
+           -> warnRebindableClash pat
+       | not desugarFlag && missingWarning
+           -> addMonadFailConstraint pat doExprType
+       | otherwise        -> pure ()
+
+addMonadFailConstraint :: LPat TcId -> TcType -> TcRn ()
+addMonadFailConstraint pat doExprType = do
+    doExprTypeHead <- tyHead <$> zonkType doExprType
+    monadFailClass <- tcLookupClass monadFailClassName
+    let predType = mkClassPred monadFailClass [doExprTypeHead]
+    _ <- emitWanted (FailablePattern pat) predType
+    pure ()
+
+warnRebindableClash :: LPat TcId -> TcRn ()
+warnRebindableClash pattern = addWarnAt (getLoc pattern)
+    (text "The failable pattern" <+> quotes (ppr pattern)
+     $$
+     nest 2 (text "is used together with -XRebindableSyntax."
+             <+> text "If this is intentional,"
+             $$
+             text "compile with -fno-warn-missing-monadfail-instance."))
+
+zonkType :: TcType -> TcRn TcType
+zonkType ty = do
+    tidyEnv <- tcInitTidyEnv
+    (_, zonkedType) <- zonkTidyTcType tidyEnv ty
+    pure zonkedType
+
+
+tyHead :: TcType -> TcType
+tyHead ty
+    | Just (con, _) <- splitAppTy_maybe ty = con
+    | Just _ <- splitFunTy_maybe ty        = panicFor "FunTy"
+    | Just _ <- splitTyConApp_maybe ty     = panicFor "TyConApp"
+    | Just _ <- splitForAllTy_maybe ty     = panicFor "ForAllTy"
+    | otherwise                            = panicFor "<some other>"
+
+    where panicFor x = panic ("MonadFail check applied to " ++ x ++ " type")
+
+
+
 {-
 Note [typechecking ApplicativeStmt]
 
index 1b2a8d9..a15fa7c 100644 (file)
@@ -76,7 +76,7 @@ import RnEnv
 import RnSource
 import ErrUtils
 import Id
-import IdInfo( IdDetails( VanillaId ) )
+import IdInfo
 import VarEnv
 import Module
 import UniqFM
@@ -103,7 +103,6 @@ import FastString
 import Maybes
 import Util
 import Bag
-import IdInfo
 
 import Control.Monad
 
index 66635a0..18ba7ce 100644 (file)
@@ -147,6 +147,9 @@ import FastString
 import GHC.Fingerprint
 
 import Control.Monad (ap, liftM, msum)
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 
 #ifdef GHCI
 import Data.Map      ( Map )
@@ -2263,6 +2266,8 @@ data CtOrigin
   | UnboundOccurrenceOf RdrName
   | ListOrigin          -- An overloaded list
   | StaticOrigin        -- A static form
+  | FailablePattern (LPat TcId) -- A failable pattern in do-notation for the
+                                -- MonadFail Proposal (MFP)
 
 ctoHerald :: SDoc
 ctoHerald = ptext (sLit "arising from")
@@ -2352,6 +2357,8 @@ pprCtO AnnOrigin             = ptext (sLit "an annotation")
 pprCtO HoleOrigin            = ptext (sLit "a use of") <+> quotes (ptext $ sLit "_")
 pprCtO ListOrigin            = ptext (sLit "an overloaded list")
 pprCtO StaticOrigin          = ptext (sLit "a static form")
+pprCtO (FailablePattern pat) = text "the failable pattern" <+> quotes (ppr pat)
+                               $$ text "(this will become an error a future GHC release)"
 pprCtO _                     = panic "pprCtOrigin"
 
 {-
@@ -2380,6 +2387,11 @@ instance Monad TcPluginM where
     TcPluginM (\ ev -> do a <- m ev
                           runTcPluginM (k a) ev)
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail TcPluginM where
+  fail x   = TcPluginM (const $ fail x)
+#endif
+
 runTcPluginM :: TcPluginM a -> Maybe EvBindsVar -> TcM a
 runTcPluginM (TcPluginM m) = m
 
index ec1ef18..7f2dd66 100644 (file)
@@ -144,6 +144,9 @@ import Maybes ( orElse, firstJusts )
 import TrieMap
 import Control.Arrow ( first )
 import Control.Monad( ap, when, unless, MonadPlus(..) )
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 import MonadUtils
 import Data.IORef
 import Data.List ( foldl', partition )
@@ -2166,6 +2169,11 @@ instance Monad TcS where
   fail err  = TcS (\_ -> fail err)
   m >>= k   = TcS (\ebs -> unTcS m ebs >>= \r -> unTcS (k r) ebs)
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail TcS where
+  fail err  = TcS (\_ -> fail err)
+#endif
+
 instance MonadUnique TcS where
    getUniqueSupplyM = wrapTcS getUniqueSupplyM
 
index 87681e0..a29c85f 100644 (file)
@@ -34,6 +34,9 @@ import Outputable
 import FastString (sLit)
 
 import Control.Monad (liftM, foldM, ap)
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 #if __GLASGOW_HASKELL__ < 709
 import Control.Applicative (Applicative(..))
 #endif
@@ -729,6 +732,11 @@ instance Monad UM where
                                other                   -> other
                            SurelyApart -> SurelyApart)
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail UM where
+    fail _   = UM (\_tvs _subst -> SurelyApart) -- failed pattern match
+#endif
+
 -- returns an idempotent substitution
 initUM :: (TyVar -> BindFlag) -> UM () -> UnifyResult
 initUM badtvs um = fmap (niFixTvSubst . snd) $ unUM um badtvs emptyTvSubstEnv
index 31ac2b3..804ddd8 100644 (file)
@@ -43,6 +43,9 @@ import Data.Typeable
 import System.IO.Unsafe ( unsafeInterleaveIO )
 import System.IO        ( fixIO )
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
 import MonadUtils
 import Control.Applicative (Alternative(..))
 
@@ -62,6 +65,12 @@ instance Monad (IOEnv m) where
     return = pure
     fail _ = failM -- Ignore the string
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail (IOEnv m) where
+    fail _ = failM -- Ignore the string
+#endif
+
+
 instance Applicative (IOEnv m) where
     pure = returnM
     IOEnv f <*> IOEnv x = IOEnv (\ env -> f env <*> x env )
index 56b6dab..656f40a 100644 (file)
@@ -20,6 +20,9 @@ module Maybes (
 
 import Control.Applicative
 import Control.Monad
+#if __GLASGOW_HASKELL__ > 710
+import Control.Monad.Fail
+#endif
 import Data.Maybe
 
 infixr 4 `orElse`
@@ -85,6 +88,12 @@ instance (Monad m) => Monad (MaybeT m) where
   x >>= f = MaybeT $ runMaybeT x >>= maybe (pure Nothing) (runMaybeT . f)
   fail _ = MaybeT $ pure Nothing
 
+
+#if __GLASGOW_HASKELL__ > 710
+instance Monad m => MonadFail (MaybeT m) where
+  fail _ = MaybeT $ return Nothing
+#endif
+
 #if __GLASGOW_HASKELL__ < 710
 -- Pre-AMP change
 instance (Monad m, Applicative m) => Alternative (MaybeT m) where
index ed47dae..70879b1 100644 (file)
@@ -1681,6 +1681,22 @@ In the case of transform comprehensions, notice that the groups are
 parameterised over some arbitrary type ``n`` (provided it has an
 ``fmap``, as well as the comprehension being over an arbitrary monad.
 
+.. _monadfail-desugaring
+
+New monadic failure desugaring mechanism
+----------------------------------------
+
+.. index::
+    single: -XMonadFailDesugaring option
+
+Switch desugaring of ``do``-blocks to use ``MonadFail.fail`` instead of
+``Monad.fail``. This will be the default behaviour in a future GHC release,
+under the MonadFail Proposal (MFP).
+
+This extension is temporary, and will be deprecated in a future release. It is
+included so that library authors have a hard check for whether their code
+will work with future GHC versions.
+
 .. _rebindable-syntax:
 
 Rebindable syntax and the implicit Prelude import
index c3271d0..8cf329c 100644 (file)
@@ -188,12 +188,22 @@ command line.
        single: AMP
        single: Applicative-Monad Proposal
 
-    Causes a warning to be emitted when a definition is in conflict with
-    the AMP (Applicative-Monad proosal), namely: 1. Instance of Monad
-    without Applicative; 2. Instance of MonadPlus without Alternative;
-    3. Custom definitions of join/pure/<\*>
+    This option is deprecated.
 
-    This option is on by default.
+    Caused a warning to be emitted when a definition was in conflict with
+    the AMP (Applicative-Monad proosal).
+
+``-fwarn-missing-monadfail-instance``
+    .. index::
+       single: -fwarn-missing-monadfail-instance
+       single: MFP
+       single: MonadFail Proposal
+
+    Warn when a failable pattern is used in a do-block that does not have a
+    ``MonadFail`` instance.
+
+    This option is off by default, but will be switched on in a future GHC
+    release, as part of the MFP (MonadFail Proposal).
 
 ``-fwarn-deprecated-flags``
     .. index::
index 7de41ba..6957ad4 100644 (file)
@@ -75,8 +75,8 @@ module Control.Monad
     , (<$!>)
     ) where
 
-import Data.Functor ( void, (<$>) )
 import Data.Foldable ( Foldable, sequence_, sequenceA_, msum, mapM_, foldlM, forM_ )
+import Data.Functor ( void, (<$>) )
 import Data.Traversable ( forM, mapM, traverse, sequence, sequenceA )
 
 import GHC.Base hiding ( mapM, sequence )
index bae2abc..3908b24 100644 (file)
@@ -1,5 +1,6 @@
 {-# LANGUAGE Trustworthy #-}
 {-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE MagicHash #-}
 {-# LANGUAGE DeriveFunctor #-}
@@ -76,6 +77,10 @@ import GHC.Unicode ( isSpace )
 import GHC.List ( replicate, null )
 import GHC.Base hiding ( many )
 
+#if __GLASGOW_HASKELL__ > 710
+import Control.Monad.Fail
+#endif
+
 infixr 5 +++, <++
 
 ------------------------------------------------------------------------
@@ -119,6 +124,11 @@ instance Monad P where
 
   fail _ = Fail
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail P where
+  fail _ = Fail
+#endif
+
 instance Alternative P where
   empty = Fail
 
@@ -166,6 +176,11 @@ instance Monad ReadP where
   fail _    = R (\_ -> Fail)
   R m >>= f = R (\k -> m (\a -> let R m' = f a in m' k))
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail ReadP where
+  fail _    = R (\_ -> Fail)
+#endif
+
 instance Alternative ReadP where
     empty = mzero
     (<|>) = mplus
index 0226836..a1ce920 100644 (file)
@@ -1,5 +1,6 @@
 {-# LANGUAGE Trustworthy #-}
 {-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -64,6 +65,10 @@ import qualified Text.ParserCombinators.ReadP as ReadP
 import GHC.Num( Num(..) )
 import GHC.Base
 
+#if __GLASGOW_HASKELL__ > 710
+import qualified Control.Monad.Fail as MonadFail
+#endif
+
 -- ---------------------------------------------------------------------------
 -- The readPrec type
 
@@ -82,6 +87,11 @@ instance Monad ReadPrec where
   fail s    = P (\_ -> fail s)
   P f >>= k = P (\n -> do a <- f n; let P f' = k a in f' n)
 
+#if __GLASGOW_HASKELL__ > 710
+instance MonadFail.MonadFail ReadPrec where
+  fail s    = P (\_ -> fail s)
+#endif
+
 instance MonadPlus ReadPrec where
   mzero = pfail
   mplus = (+++)
index f76dc34..d3bee2a 100644 (file)
@@ -33,7 +33,9 @@ expectedGhcOnlyExtensions :: [String]
 expectedGhcOnlyExtensions = ["RelaxedLayout",
                              "AlternativeLayoutRule",
                              "AlternativeLayoutRuleTransitional",
-                             "OverloadedLabels"]
+                             "OverloadedLabels",
+                             "Strict",
+                             "MonadFailDesugaring"]
 
 expectedCabalOnlyExtensions :: [String]
 expectedCabalOnlyExtensions = ["Generics",
diff --git a/testsuite/tests/monadfail/MonadFailErrors.hs b/testsuite/tests/monadfail/MonadFailErrors.hs
new file mode 100644 (file)
index 0000000..f9db31e
--- /dev/null
@@ -0,0 +1,95 @@
+-- Test purpose:
+-- Break properly if MonadFail is live
+
+{-# LANGUAGE MonadFailDesugaring #-}
+
+module MonadFailWarnings where
+
+import Control.Monad.Fail
+import Control.Monad.ST
+import Data.Functor.Identity
+
+
+
+general :: Monad m => m a
+general = do
+    Just x <- undefined
+    undefined
+
+
+
+general' :: MonadFail m => m a
+general' = do
+    Just x <- undefined
+    undefined
+
+
+
+identity :: Identity a
+identity = do
+    Just x <- undefined
+    undefined
+
+
+
+io :: IO a
+io = do
+    Just x <- undefined
+    undefined
+
+
+
+st :: ST s a
+st = do
+    Just x <- undefined
+    undefined
+
+
+
+reader :: r -> a
+reader = do
+    Just x <- undefined
+    undefined
+
+
+
+newtype Newtype a = Newtype a
+newtypeMatch :: Identity a
+newtypeMatch = do
+    Newtype x <- undefined
+    undefined
+
+
+
+data Data a = Data a
+singleConMatch :: Identity a
+singleConMatch = do
+    Data x <- undefined
+    undefined
+
+
+
+data Maybe' a = Nothing' | Just' a
+instance Functor Maybe' where fmap = undefined
+instance Applicative Maybe' where pure = undefined; (<*>) = undefined
+instance Monad Maybe' where (>>=) = undefined
+instance MonadFail Maybe' where fail = undefined
+customFailable :: Maybe' a
+customFailable = do
+    Just x <- undefined
+    undefined
+
+
+wildcardx, explicitlyIrrefutable, wildcard_, tuple :: Monad m => m a
+wildcardx = do
+    x <- undefined
+    undefined
+explicitlyIrrefutable = do
+    ~(x:y) <- undefined
+    undefined
+wildcard_ = do
+    _ <- undefined
+    undefined
+tuple = do
+    (a,b) <- undefined
+    undefined
diff --git a/testsuite/tests/monadfail/MonadFailErrors.stderr b/testsuite/tests/monadfail/MonadFailErrors.stderr
new file mode 100644 (file)
index 0000000..ad66177
--- /dev/null
@@ -0,0 +1,74 @@
+
+MonadFailErrors.hs:16:5: error:
+    Could not deduce (MonadFail m) arising from a do statement
+    from the context: Monad m
+      bound by the type signature for:
+                 general :: Monad m => m a
+      at MonadFailErrors.hs:14:12-25
+    Possible fix:
+      add (MonadFail m) to the context of
+        the type signature for:
+          general :: Monad m => m a
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘general’:
+        general
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailErrors.hs:30:5: error:
+    No instance for (MonadFail Identity) arising from a do statement
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘identity’:
+        identity
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailErrors.hs:44:5: error:
+    No instance for (MonadFail (ST s)) arising from a do statement
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘st’:
+        st
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailErrors.hs:51:5: error:
+    No instance for (MonadFail ((->) r)) arising from a do statement
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘reader’:
+        reader
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailErrors.hs:59:5: error:
+    No instance for (MonadFail Identity) arising from a do statement
+    In a stmt of a 'do' block: Newtype x <- undefined
+    In the expression:
+      do { Newtype x <- undefined;
+           undefined }
+    In an equation for ‘newtypeMatch’:
+        newtypeMatch
+          = do { Newtype x <- undefined;
+                 undefined }
+
+MonadFailErrors.hs:67:5: error:
+    No instance for (MonadFail Identity) arising from a do statement
+    In a stmt of a 'do' block: Data x <- undefined
+    In the expression:
+      do { Data x <- undefined;
+           undefined }
+    In an equation for ‘singleConMatch’:
+        singleConMatch
+          = do { Data x <- undefined;
+                 undefined }
diff --git a/testsuite/tests/monadfail/MonadFailWarnings.hs b/testsuite/tests/monadfail/MonadFailWarnings.hs
new file mode 100644 (file)
index 0000000..3b786cc
--- /dev/null
@@ -0,0 +1,107 @@
+-- Test purpose:
+-- Ensure that MonadFail warnings are issued correctly if the warning flag
+-- is enabled
+
+{-# OPTIONS_GHC -fwarn-missing-monadfail-instance #-}
+
+module MonadFailWarnings where
+
+import Control.Monad.Fail
+import Control.Monad.ST
+import Data.Functor.Identity
+
+
+
+-- should warn, because the do-block gets a general Monad constraint,
+-- but should have MonadFail
+general :: Monad m => m a
+general = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should NOT warn, because the constraint is correct
+general' :: MonadFail m => m a
+general' = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should warn, because Identity isn't MonadFail
+identity :: Identity a
+identity = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should NOT warn, because IO is MonadFail
+io :: IO a
+io = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should warn, because (ST s) is not MonadFail
+st :: ST s a
+st = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should warn, because (r ->) is not MonadFail
+reader :: r -> a
+reader = do
+    Just x <- undefined
+    undefined
+
+
+
+-- should NOT warn, because matching against newtype
+newtype Newtype a = Newtype a
+newtypeMatch :: Identity a
+newtypeMatch = do
+    Newtype x <- undefined
+    undefined
+
+
+
+-- should NOT warn, because Data has only one constructor
+data Data a = Data a
+singleConMatch :: Identity a
+singleConMatch = do
+    Data x <- undefined
+    undefined
+
+
+
+-- should NOT warn, because Maybe' has a MonadFail instance
+data Maybe' a = Nothing' | Just' a
+instance Functor Maybe' where fmap = undefined
+instance Applicative Maybe' where pure = undefined; (<*>) = undefined
+instance Monad Maybe' where (>>=) = undefined
+instance MonadFail Maybe' where fail = undefined
+customFailable :: Maybe' a
+customFailable = do
+    Just x <- undefined
+    undefined
+
+
+-- should NOT warn, because patterns always match
+wildcardx, explicitlyIrrefutable, wildcard_, tuple :: Monad m => m a
+wildcardx = do
+    x <- undefined
+    undefined
+explicitlyIrrefutable = do
+    ~(x:y) <- undefined
+    undefined
+wildcard_ = do
+    _ <- undefined
+    undefined
+tuple = do
+    (a,b) <- undefined
+    undefined
diff --git a/testsuite/tests/monadfail/MonadFailWarnings.stderr b/testsuite/tests/monadfail/MonadFailWarnings.stderr
new file mode 100644 (file)
index 0000000..94858c1
--- /dev/null
@@ -0,0 +1,60 @@
+
+MonadFailWarnings.hs:19:5: warning:
+    Could not deduce (MonadFail m)
+      arising from the failable pattern ‘Just x’
+                   (this will become an error a future GHC release)
+    from the context: Monad m
+      bound by the type signature for:
+                 general :: Monad m => m a
+      at MonadFailWarnings.hs:17:12-25
+    Possible fix:
+      add (MonadFail m) to the context of
+        the type signature for:
+          general :: Monad m => m a
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘general’:
+        general
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailWarnings.hs:35:5: warning:
+    No instance for (MonadFail Identity)
+      arising from the failable pattern ‘Just x’
+                   (this will become an error a future GHC release)
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘identity’:
+        identity
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailWarnings.hs:51:5: warning:
+    No instance for (MonadFail (ST s))
+      arising from the failable pattern ‘Just x’
+                   (this will become an error a future GHC release)
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘st’:
+        st
+          = do { Just x <- undefined;
+                 undefined }
+
+MonadFailWarnings.hs:59:5: warning:
+    No instance for (MonadFail ((->) r))
+      arising from the failable pattern ‘Just x’
+                   (this will become an error a future GHC release)
+    In a stmt of a 'do' block: Just x <- undefined
+    In the expression:
+      do { Just x <- undefined;
+           undefined }
+    In an equation for ‘reader’:
+        reader
+          = do { Just x <- undefined;
+                 undefined }
diff --git a/testsuite/tests/monadfail/MonadFailWarningsDisabled.hs b/testsuite/tests/monadfail/MonadFailWarningsDisabled.hs
new file mode 100644 (file)
index 0000000..d3df107
--- /dev/null
@@ -0,0 +1,94 @@
+-- Test purpose:
+-- Make sure that not enabling MonadFail warnings makes code compile just
+-- as it did in < 8.0
+
+module MonadFailWarnings where
+
+import Control.Monad.Fail
+import Control.Monad.ST
+import Data.Functor.Identity
+
+
+
+general :: Monad m => m a
+general = do
+    Just x <- undefined
+    undefined
+
+
+
+general' :: MonadFail m => m a
+general' = do
+    Just x <- undefined
+    undefined
+
+
+
+identity :: Identity a
+identity = do
+    Just x <- undefined
+    undefined
+
+
+
+io :: IO a
+io = do
+    Just x <- undefined
+    undefined
+
+
+
+st :: ST s a
+st = do
+    Just x <- undefined
+    undefined
+
+
+
+reader :: r -> a
+reader = do
+    Just x <- undefined
+    undefined
+
+
+
+newtype Newtype a = Newtype a
+newtypeMatch :: Identity a
+newtypeMatch = do
+    Newtype x <- undefined
+    undefined
+
+
+
+data Data a = Data a
+singleConMatch :: Identity a
+singleConMatch = do
+    Data x <- undefined
+    undefined
+
+
+
+data Maybe' a = Nothing' | Just' a
+instance Functor Maybe' where fmap = undefined
+instance Applicative Maybe' where pure = undefined; (<*>) = undefined
+instance Monad Maybe' where (>>=) = undefined
+instance MonadFail Maybe' where fail = undefined
+customFailable :: Maybe' a
+customFailable = do
+    Just x <- undefined
+    undefined
+
+
+wildcardx, explicitlyIrrefutable, wildcard_, tuple :: Monad m => m a
+wildcardx = do
+    x <- undefined
+    undefined
+explicitlyIrrefutable = do
+    ~(x:y) <- undefined
+    undefined
+wildcard_ = do
+    _ <- undefined
+    undefined
+tuple = do
+    (a,b) <- undefined
+    undefined
diff --git a/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.hs b/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.hs
new file mode 100644 (file)
index 0000000..c9f2502
--- /dev/null
@@ -0,0 +1,14 @@
+-- Test purpose:
+-- RebindableSyntax does not play that well with MonadFail, so here we ensure
+-- that when both settings are enabled we get the proper warning.
+
+{-# OPTIONS_GHC -fwarn-missing-monadfail-instance #-}
+{-# LANGUAGE RebindableSyntax #-}
+
+module MonadFailWarningsWithRebindableSyntax where
+
+import Prelude
+
+test1 f g = do
+    Just x <- f
+    g
diff --git a/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.stderr b/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.stderr
new file mode 100644 (file)
index 0000000..819c878
--- /dev/null
@@ -0,0 +1,5 @@
+
+MonadFailWarningsWithRebindableSyntax.hs:13:5: warning:
+    The failable pattern ‘Just x’
+      is used together with -XRebindableSyntax. If this is intentional,
+      compile with -fno-warn-missing-monadfail-instance.
diff --git a/testsuite/tests/monadfail/all.T b/testsuite/tests/monadfail/all.T
new file mode 100644 (file)
index 0000000..32eddb9
--- /dev/null
@@ -0,0 +1,4 @@
+test('MonadFailWarnings', normal, compile, [''])
+test('MonadFailErrors', normal, compile_fail, [''])
+test('MonadFailWarningsDisabled', normal, compile, [''])
+test('MonadFailWarningsWithRebindableSyntax', normal, compile, [''])
index 1fb0b59..7bf3e23 100644 (file)
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-missing-monadfail-instance #-}
 {-# LANGUAGE RebindableSyntax, NPlusKPatterns #-}
 
 module RebindableCase1 where
@@ -11,7 +12,7 @@ module RebindableCase1 where
        infixl 1 >>=;
        (>>=) :: a;
        (>>=) = undefined;
-       
+
        infixl 1 >>;
        (>>) :: a;
        (>>) = undefined;
@@ -38,9 +39,9 @@ module RebindableCase1 where
                Just a <- g;
                return a;
                };
-       
+
        test_fromInteger = 1;
-       
+
        test_fromRational = 0.5;
 
        test_negate a = - a;
index ffd69f9..ec975e7 100644 (file)
@@ -1,15 +1,18 @@
-{-# LANGUAGE RebindableSyntax, NPlusKPatterns, RankNTypes,
-             ScopedTypeVariables, FlexibleInstances #-}
+{-# LANGUAGE RebindableSyntax #-}
+{-# LANGUAGE NPlusKPatterns #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleInstances #-}
+
 module Main where
        {
---     import Prelude;
        import qualified Prelude;
        import Prelude(String,undefined,Maybe(..),IO,putStrLn,
                Integer,(++),Rational, (==), (>=) );
 
        debugFunc :: String -> IO a -> IO a;
        debugFunc s ioa = (putStrLn ("++ " ++ s)) Prelude.>>
-               (ioa Prelude.>>= (\a -> 
+               (ioa Prelude.>>= (\a ->
                        (putStrLn ("-- " ++ s)) Prelude.>> (Prelude.return a)
                ));
 
@@ -18,7 +21,7 @@ module Main where
 
        returnIO :: a -> IO a;
         returnIO = Prelude.return;
-       
+
        class HasReturn a where
                {
                return :: a;
@@ -107,10 +110,10 @@ module Main where
                Just (b::b) <- g;       -- >>= (and fail if g returns Nothing)
                return b;               -- return
                };
-       
+
        test_fromInteger :: Integer;
        test_fromInteger = 27;
-       
+
        test_fromRational :: Rational;
        test_fromRational = 31.5;
 
@@ -129,7 +132,7 @@ module Main where
 
 
        doTest :: String -> IO a -> IO ();
-       doTest s ioa = 
+       doTest s ioa =
                (putStrLn ("start test " ++ s))
                        Prelude.>>
                ioa
@@ -137,7 +140,7 @@ module Main where
                (putStrLn ("end test " ++ s));
 
        main :: IO ();
-       main = 
+       main =
                (doTest "test_do failure"
                        (test_do (Prelude.return ()) (Prelude.return Nothing))
                )
index cf280a9..269ea8f 100644 (file)
@@ -1,18 +1,18 @@
 
-rebindable6.hs:106:17: error:
+rebindable6.hs:109:17: error:
     Ambiguous type variable ‘t0’ arising from a do statement
     prevents the constraint ‘(HasSeq
                                 (IO a -> t0 -> IO b))’ from being solved.
       (maybe you haven't applied a function to enough arguments?)
     Relevant bindings include
-      g :: IO (Maybe b) (bound at rebindable6.hs:104:19)
-      f :: IO a (bound at rebindable6.hs:104:17)
+      g :: IO (Maybe b) (bound at rebindable6.hs:107:19)
+      f :: IO a (bound at rebindable6.hs:107:17)
       test_do :: IO a -> IO (Maybe b) -> IO b
-        (bound at rebindable6.hs:104:9)
+        (bound at rebindable6.hs:107:9)
     Probable fix: use a type annotation to specify what ‘t0’ should be.
     These potential instance exist:
       instance HasSeq (IO a -> IO b -> IO b)
-        -- Defined at rebindable6.hs:52:18
+        -- Defined at rebindable6.hs:55:18
     In a stmt of a 'do' block: f
     In the expression:
       do { f;
@@ -24,7 +24,7 @@ rebindable6.hs:106:17: error:
                  Just (b :: b) <- g;
                  return b }
 
-rebindable6.hs:107:17: error:
+rebindable6.hs:110:17: error:
     Ambiguous type variable ‘t1’ arising from a do statement
     prevents the constraint ‘(HasFail
                                 ([Char] -> t1))’ from being solved.
@@ -32,7 +32,7 @@ rebindable6.hs:107:17: error:
     Probable fix: use a type annotation to specify what ‘t1’ should be.
     These potential instance exist:
       instance HasFail (String -> IO a)
-        -- Defined at rebindable6.hs:57:18
+        -- Defined at rebindable6.hs:60:18
     In a stmt of a 'do' block: Just (b :: b) <- g
     In the expression:
       do { f;
@@ -44,18 +44,18 @@ rebindable6.hs:107:17: error:
                  Just (b :: b) <- g;
                  return b }
 
-rebindable6.hs:108:17: error:
+rebindable6.hs:111:17: error:
     Ambiguous type variable ‘t1’ arising from a use of ‘return’
     prevents the constraint ‘(HasReturn (b -> t1))’ from being solved.
       (maybe you haven't applied a function to enough arguments?)
     Relevant bindings include
-      b :: b (bound at rebindable6.hs:107:23)
-      g :: IO (Maybe b) (bound at rebindable6.hs:104:19)
+      b :: b (bound at rebindable6.hs:110:23)
+      g :: IO (Maybe b) (bound at rebindable6.hs:107:19)
       test_do :: IO a -> IO (Maybe b) -> IO b
-        (bound at rebindable6.hs:104:9)
+        (bound at rebindable6.hs:107:9)
     Probable fix: use a type annotation to specify what ‘t1’ should be.
     These potential instance exist:
-      instance HasReturn (a -> IO a) -- Defined at rebindable6.hs:42:18
+      instance HasReturn (a -> IO a) -- Defined at rebindable6.hs:45:18
     In a stmt of a 'do' block: return b
     In the expression:
       do { f;