summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Luposchainsky <dluposchainsky@gmail.com>2015-11-17 17:10:02 +0100
committerBen Gamari <bgamari.foss@gmail.com>2015-11-17 12:29:09 -0500
commit233d1312bf15940fca5feca6884f965e7944b555 (patch)
tree0f787688562e65c1043626d8d03447ef2ab0b7a7
parent7b962bab384e2ae85b41d30f503c3d0295b0214f (diff)
downloadhaskell-233d1312bf15940fca5feca6884f965e7944b555.tar.gz
MonadFail proposal, phase 1
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
-rw-r--r--compiler/coreSyn/CoreLint.hs8
-rw-r--r--compiler/hsSyn/HsExpr.hs2
-rw-r--r--compiler/main/DynFlags.hs4
-rw-r--r--compiler/parser/Lexer.x8
-rw-r--r--compiler/prelude/PrelNames.hs39
-rw-r--r--compiler/prelude/PrelRules.hs8
-rw-r--r--compiler/rename/RnEnv.hs4
-rw-r--r--compiler/rename/RnExpr.hs17
-rw-r--r--compiler/specialise/Specialise.hs8
-rw-r--r--compiler/typecheck/TcArrows.hs2
-rw-r--r--compiler/typecheck/TcErrors.hs23
-rw-r--r--compiler/typecheck/TcMatches.hs87
-rw-r--r--compiler/typecheck/TcRnDriver.hs3
-rw-r--r--compiler/typecheck/TcRnTypes.hs12
-rw-r--r--compiler/typecheck/TcSMonad.hs8
-rw-r--r--compiler/types/Unify.hs8
-rw-r--r--compiler/utils/IOEnv.hs9
-rw-r--r--compiler/utils/Maybes.hs9
-rw-r--r--docs/users_guide/glasgow_exts.rst16
-rw-r--r--docs/users_guide/using-warnings.rst20
-rw-r--r--libraries/base/Control/Monad.hs2
-rw-r--r--libraries/base/Text/ParserCombinators/ReadP.hs15
-rw-r--r--libraries/base/Text/ParserCombinators/ReadPrec.hs10
-rw-r--r--testsuite/tests/driver/T4437.hs4
-rw-r--r--testsuite/tests/monadfail/MonadFailErrors.hs95
-rw-r--r--testsuite/tests/monadfail/MonadFailErrors.stderr74
-rw-r--r--testsuite/tests/monadfail/MonadFailWarnings.hs107
-rw-r--r--testsuite/tests/monadfail/MonadFailWarnings.stderr60
-rw-r--r--testsuite/tests/monadfail/MonadFailWarningsDisabled.hs94
-rw-r--r--testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.hs14
-rw-r--r--testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.stderr5
-rw-r--r--testsuite/tests/monadfail/all.T4
-rw-r--r--testsuite/tests/rebindable/rebindable1.hs7
-rw-r--r--testsuite/tests/rebindable/rebindable6.hs21
-rw-r--r--testsuite/tests/rebindable/rebindable6.stderr24
35 files changed, 765 insertions, 66 deletions
diff --git a/compiler/coreSyn/CoreLint.hs b/compiler/coreSyn/CoreLint.hs
index da08c21fca..00a7fd0b19 100644
--- a/compiler/coreSyn/CoreLint.hs
+++ b/compiler/coreSyn/CoreLint.hs
@@ -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))
diff --git a/compiler/hsSyn/HsExpr.hs b/compiler/hsSyn/HsExpr.hs
index 8a733adec4..09717b768a 100644
--- a/compiler/hsSyn/HsExpr.hs
+++ b/compiler/hsSyn/HsExpr.hs
@@ -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
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 5f63b1048e..45fb72e06d 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -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 $
diff --git a/compiler/parser/Lexer.x b/compiler/parser/Lexer.x
index 8f29a270e0..da9424d5bc 100644
--- a/compiler/parser/Lexer.x
+++ b/compiler/parser/Lexer.x
@@ -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)
diff --git a/compiler/prelude/PrelNames.hs b/compiler/prelude/PrelNames.hs
index 346f3a382d..1b1ffaabdf 100644
--- a/compiler/prelude/PrelNames.hs
+++ b/compiler/prelude/PrelNames.hs
@@ -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
diff --git a/compiler/prelude/PrelRules.hs b/compiler/prelude/PrelRules.hs
index 919a1d51fe..68140f73f3 100644
--- a/compiler/prelude/PrelRules.hs
+++ b/compiler/prelude/PrelRules.hs
@@ -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
diff --git a/compiler/rename/RnEnv.hs b/compiler/rename/RnEnv.hs
index 1e8eb27e9f..c0d88e9f35 100644
--- a/compiler/rename/RnEnv.hs
+++ b/compiler/rename/RnEnv.hs
@@ -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) } }
diff --git a/compiler/rename/RnExpr.hs b/compiler/rename/RnExpr.hs
index d748bf0bc0..a8b1d2e7c8 100644
--- a/compiler/rename/RnExpr.hs
+++ b/compiler/rename/RnExpr.hs
@@ -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,
diff --git a/compiler/specialise/Specialise.hs b/compiler/specialise/Specialise.hs
index 31d8212831..cb671be7a5 100644
--- a/compiler/specialise/Specialise.hs
+++ b/compiler/specialise/Specialise.hs
@@ -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
diff --git a/compiler/typecheck/TcArrows.hs b/compiler/typecheck/TcArrows.hs
index bb7a3744f0..0d6e185ab8 100644
--- a/compiler/typecheck/TcArrows.hs
+++ b/compiler/typecheck/TcArrows.hs
@@ -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
diff --git a/compiler/typecheck/TcErrors.hs b/compiler/typecheck/TcErrors.hs
index 5fdd7def0d..011b70299f 100644
--- a/compiler/typecheck/TcErrors.hs
+++ b/compiler/typecheck/TcErrors.hs
@@ -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
diff --git a/compiler/typecheck/TcMatches.hs b/compiler/typecheck/TcMatches.hs
index d7dbddf6ec..b504206a2a 100644
--- a/compiler/typecheck/TcMatches.hs
+++ b/compiler/typecheck/TcMatches.hs
@@ -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]
diff --git a/compiler/typecheck/TcRnDriver.hs b/compiler/typecheck/TcRnDriver.hs
index 1b2a8d993e..a15fa7c923 100644
--- a/compiler/typecheck/TcRnDriver.hs
+++ b/compiler/typecheck/TcRnDriver.hs
@@ -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
diff --git a/compiler/typecheck/TcRnTypes.hs b/compiler/typecheck/TcRnTypes.hs
index 66635a0e6c..18ba7cec63 100644
--- a/compiler/typecheck/TcRnTypes.hs
+++ b/compiler/typecheck/TcRnTypes.hs
@@ -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
diff --git a/compiler/typecheck/TcSMonad.hs b/compiler/typecheck/TcSMonad.hs
index ec1ef18890..7f2dd66228 100644
--- a/compiler/typecheck/TcSMonad.hs
+++ b/compiler/typecheck/TcSMonad.hs
@@ -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
diff --git a/compiler/types/Unify.hs b/compiler/types/Unify.hs
index 87681e0eb8..a29c85f2da 100644
--- a/compiler/types/Unify.hs
+++ b/compiler/types/Unify.hs
@@ -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
diff --git a/compiler/utils/IOEnv.hs b/compiler/utils/IOEnv.hs
index 31ac2b3731..804ddd8e70 100644
--- a/compiler/utils/IOEnv.hs
+++ b/compiler/utils/IOEnv.hs
@@ -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 )
diff --git a/compiler/utils/Maybes.hs b/compiler/utils/Maybes.hs
index 56b6dab5d9..656f40a372 100644
--- a/compiler/utils/Maybes.hs
+++ b/compiler/utils/Maybes.hs
@@ -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
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index ed47dae6a0..70879b12e8 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -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
diff --git a/docs/users_guide/using-warnings.rst b/docs/users_guide/using-warnings.rst
index c3271d0111..8cf329cdc7 100644
--- a/docs/users_guide/using-warnings.rst
+++ b/docs/users_guide/using-warnings.rst
@@ -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::
diff --git a/libraries/base/Control/Monad.hs b/libraries/base/Control/Monad.hs
index 7de41bacc6..6957ad464f 100644
--- a/libraries/base/Control/Monad.hs
+++ b/libraries/base/Control/Monad.hs
@@ -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 )
diff --git a/libraries/base/Text/ParserCombinators/ReadP.hs b/libraries/base/Text/ParserCombinators/ReadP.hs
index bae2abc90e..3908b24408 100644
--- a/libraries/base/Text/ParserCombinators/ReadP.hs
+++ b/libraries/base/Text/ParserCombinators/ReadP.hs
@@ -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
diff --git a/libraries/base/Text/ParserCombinators/ReadPrec.hs b/libraries/base/Text/ParserCombinators/ReadPrec.hs
index 02268364ca..a1ce920ce2 100644
--- a/libraries/base/Text/ParserCombinators/ReadPrec.hs
+++ b/libraries/base/Text/ParserCombinators/ReadPrec.hs
@@ -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 = (+++)
diff --git a/testsuite/tests/driver/T4437.hs b/testsuite/tests/driver/T4437.hs
index f76dc34354..d3bee2a61a 100644
--- a/testsuite/tests/driver/T4437.hs
+++ b/testsuite/tests/driver/T4437.hs
@@ -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
index 0000000000..f9db31e5a0
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailErrors.hs
@@ -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
index 0000000000..ad661772c7
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailErrors.stderr
@@ -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
index 0000000000..3b786cc8c7
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailWarnings.hs
@@ -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
index 0000000000..94858c1945
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailWarnings.stderr
@@ -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
index 0000000000..d3df107a4a
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailWarningsDisabled.hs
@@ -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
index 0000000000..c9f25027f9
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.hs
@@ -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
index 0000000000..819c878dc9
--- /dev/null
+++ b/testsuite/tests/monadfail/MonadFailWarningsWithRebindableSyntax.stderr
@@ -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
index 0000000000..32eddb9e98
--- /dev/null
+++ b/testsuite/tests/monadfail/all.T
@@ -0,0 +1,4 @@
+test('MonadFailWarnings', normal, compile, [''])
+test('MonadFailErrors', normal, compile_fail, [''])
+test('MonadFailWarningsDisabled', normal, compile, [''])
+test('MonadFailWarningsWithRebindableSyntax', normal, compile, [''])
diff --git a/testsuite/tests/rebindable/rebindable1.hs b/testsuite/tests/rebindable/rebindable1.hs
index 1fb0b596fb..7bf3e237a6 100644
--- a/testsuite/tests/rebindable/rebindable1.hs
+++ b/testsuite/tests/rebindable/rebindable1.hs
@@ -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;
diff --git a/testsuite/tests/rebindable/rebindable6.hs b/testsuite/tests/rebindable/rebindable6.hs
index ffd69f904b..ec975e7f37 100644
--- a/testsuite/tests/rebindable/rebindable6.hs
+++ b/testsuite/tests/rebindable/rebindable6.hs
@@ -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))
)
diff --git a/testsuite/tests/rebindable/rebindable6.stderr b/testsuite/tests/rebindable/rebindable6.stderr
index cf280a961d..269ea8ff05 100644
--- a/testsuite/tests/rebindable/rebindable6.stderr
+++ b/testsuite/tests/rebindable/rebindable6.stderr
@@ -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;