summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorsheaf <sam.derbyshire@gmail.com>2021-10-06 18:22:28 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-10-09 04:46:05 -0400
commit31983ab4c65204ad0fd14aac4c00648f5fa6ad6b (patch)
tree6bff70ce40f4d295ce084358ebe4b977e68bb43f /compiler
parenta76409c758d8c7bd837dcc6c0b58f8cce656b4f1 (diff)
downloadhaskell-31983ab4c65204ad0fd14aac4c00648f5fa6ad6b.tar.gz
Reject GADT pattern matches in arrow notation
Tickets #20469 and #20470 showed that the current implementation of arrows is not at all up to the task of supporting GADTs: GHC produces ill-scoped Core programs because it doesn't propagate the evidence introduced by a GADT pattern match. For the time being, we reject GADT pattern matches in arrow notation. Hopefully we are able to add proper support for GADTs in arrows in the future.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/GHC/Core/ConLike.hs7
-rw-r--r--compiler/GHC/Core/PatSyn.hs5
-rw-r--r--compiler/GHC/Hs/Expr.hs16
-rw-r--r--compiler/GHC/Hs/Instances.hs2
-rw-r--r--compiler/GHC/HsToCore/Arrows.hs8
-rw-r--r--compiler/GHC/HsToCore/Pmc/Utils.hs9
-rw-r--r--compiler/GHC/Rename/Bind.hs13
-rw-r--r--compiler/GHC/Rename/Expr.hs8
-rw-r--r--compiler/GHC/Tc/Errors/Ppr.hs17
-rw-r--r--compiler/GHC/Tc/Errors/Types.hs14
-rw-r--r--compiler/GHC/Tc/Gen/Arrow.hs12
-rw-r--r--compiler/GHC/Tc/Gen/Pat.hs68
-rw-r--r--compiler/Language/Haskell/Syntax/Expr.hs25
13 files changed, 146 insertions, 58 deletions
diff --git a/compiler/GHC/Core/ConLike.hs b/compiler/GHC/Core/ConLike.hs
index 868d4a6fed..b375b742f0 100644
--- a/compiler/GHC/Core/ConLike.hs
+++ b/compiler/GHC/Core/ConLike.hs
@@ -9,6 +9,7 @@
module GHC.Core.ConLike (
ConLike(..)
+ , isVanillaConLike
, conLikeArity
, conLikeFieldLabels
, conLikeInstOrigArgTys
@@ -54,6 +55,12 @@ import qualified Data.Data as Data
data ConLike = RealDataCon DataCon
| PatSynCon PatSyn
+-- | Is this a \'vanilla\' constructor-like thing
+-- (no existentials, no provided constraints)?
+isVanillaConLike :: ConLike -> Bool
+isVanillaConLike (RealDataCon con) = isVanillaDataCon con
+isVanillaConLike (PatSynCon ps ) = isVanillaPatSyn ps
+
{-
************************************************************************
* *
diff --git a/compiler/GHC/Core/PatSyn.hs b/compiler/GHC/Core/PatSyn.hs
index 34a019dce1..c3aeb87c27 100644
--- a/compiler/GHC/Core/PatSyn.hs
+++ b/compiler/GHC/Core/PatSyn.hs
@@ -13,6 +13,7 @@ module GHC.Core.PatSyn (
-- ** Type deconstruction
patSynName, patSynArity, patSynIsInfix, patSynResultType,
+ isVanillaPatSyn,
patSynArgs,
patSynMatcher, patSynBuilder,
patSynUnivTyVarBinders, patSynExTyVars, patSynExTyVarBinders,
@@ -419,6 +420,10 @@ patSynIsInfix = psInfix
patSynArity :: PatSyn -> Arity
patSynArity = psArity
+-- | Is this a \'vanilla\' pattern synonym (no existentials, no provided constraints)?
+isVanillaPatSyn :: PatSyn -> Bool
+isVanillaPatSyn ps = null (psExTyVars ps) && null (psProvTheta ps)
+
patSynArgs :: PatSyn -> [Type]
patSynArgs = psArgs
diff --git a/compiler/GHC/Hs/Expr.hs b/compiler/GHC/Hs/Expr.hs
index 83e36edf54..d6785c2a96 100644
--- a/compiler/GHC/Hs/Expr.hs
+++ b/compiler/GHC/Hs/Expr.hs
@@ -1857,7 +1857,7 @@ instance OutputableBndrId p => Outputable (HsMatchContext (GhcPass p)) where
ppr LambdaExpr = text "LambdaExpr"
ppr CaseAlt = text "CaseAlt"
ppr IfAlt = text "IfAlt"
- ppr ProcExpr = text "ProcExpr"
+ ppr (ArrowMatchCtxt c) = text "ArrowMatchCtxt" <+> ppr c
ppr PatBindRhs = text "PatBindRhs"
ppr PatBindGuards = text "PatBindGuards"
ppr RecUpd = text "RecUpd"
@@ -1866,6 +1866,11 @@ instance OutputableBndrId p => Outputable (HsMatchContext (GhcPass p)) where
ppr ThPatQuote = text "ThPatQuote"
ppr PatSyn = text "PatSyn"
+instance Outputable HsArrowMatchContext where
+ ppr ProcExpr = text "ProcExpr"
+ ppr ArrowCaseAlt = text "ArrowCaseAlt"
+ ppr KappaExpr = text "KappaExpr"
+
-----------------
instance OutputableBndrId p
@@ -1882,16 +1887,21 @@ matchContextErrString PatBindRhs = text "pattern binding"
matchContextErrString PatBindGuards = text "pattern binding guards"
matchContextErrString RecUpd = text "record update"
matchContextErrString LambdaExpr = text "lambda"
-matchContextErrString ProcExpr = text "proc"
+matchContextErrString (ArrowMatchCtxt c) = matchArrowContextErrString c
matchContextErrString ThPatSplice = panic "matchContextErrString" -- Not used at runtime
matchContextErrString ThPatQuote = panic "matchContextErrString" -- Not used at runtime
matchContextErrString PatSyn = panic "matchContextErrString" -- Not used at runtime
matchContextErrString (StmtCtxt (ParStmtCtxt c)) = matchContextErrString (StmtCtxt c)
matchContextErrString (StmtCtxt (TransStmtCtxt c)) = matchContextErrString (StmtCtxt c)
matchContextErrString (StmtCtxt (PatGuard _)) = text "pattern guard"
-matchContextErrString (StmtCtxt (ArrowExpr)) = text "'do' block"
+matchContextErrString (StmtCtxt (ArrowExpr)) = text "'do' block"
matchContextErrString (StmtCtxt (HsDoStmt flavour)) = matchDoContextErrString flavour
+matchArrowContextErrString :: HsArrowMatchContext -> SDoc
+matchArrowContextErrString ProcExpr = text "proc"
+matchArrowContextErrString ArrowCaseAlt = text "case"
+matchArrowContextErrString KappaExpr = text "kappa"
+
matchDoContextErrString :: HsDoFlavour -> SDoc
matchDoContextErrString GhciStmtCtxt = text "interactive GHCi command"
matchDoContextErrString (DoExpr m) = prependQualified m (text "'do' block")
diff --git a/compiler/GHC/Hs/Instances.hs b/compiler/GHC/Hs/Instances.hs
index 78a663d7fa..21cd9b5d76 100644
--- a/compiler/GHC/Hs/Instances.hs
+++ b/compiler/GHC/Hs/Instances.hs
@@ -366,6 +366,8 @@ deriving instance Data (HsStmtContext GhcPs)
deriving instance Data (HsStmtContext GhcRn)
deriving instance Data (HsStmtContext GhcTc)
+deriving instance Data HsArrowMatchContext
+
deriving instance Data HsDoFlavour
deriving instance Data (HsMatchContext GhcPs)
diff --git a/compiler/GHC/HsToCore/Arrows.hs b/compiler/GHC/HsToCore/Arrows.hs
index 5cfd057299..2338e2a451 100644
--- a/compiler/GHC/HsToCore/Arrows.hs
+++ b/compiler/GHC/HsToCore/Arrows.hs
@@ -319,9 +319,9 @@ dsProcExpr pat (L _ (HsCmdTop (CmdTopTc _unitTy cmd_ty ids) cmd)) = do
let env_ty = mkBigCoreVarTupTy env_ids
let env_stk_ty = mkCorePairTy env_ty unitTy
let env_stk_expr = mkCorePairExpr (mkBigCoreVarTup env_ids) mkCoreUnitExpr
- fail_expr <- mkFailExpr ProcExpr env_stk_ty
+ fail_expr <- mkFailExpr (ArrowMatchCtxt ProcExpr) env_stk_ty
var <- selectSimpleMatchVarL Many pat
- match_code <- matchSimply (Var var) ProcExpr pat env_stk_expr fail_expr
+ match_code <- matchSimply (Var var) (ArrowMatchCtxt ProcExpr) pat env_stk_expr fail_expr
let pat_ty = hsLPatType pat
let proc_code = do_premap meth_ids pat_ty env_stk_ty cmd_ty
(Lam var match_code)
@@ -755,9 +755,9 @@ dsCmdLam ids local_vars stack_ty res_ty pats body env_ids = do
in_ty = envStackType env_ids stack_ty
in_ty' = envStackType env_ids' stack_ty'
- fail_expr <- mkFailExpr LambdaExpr in_ty'
+ fail_expr <- mkFailExpr (ArrowMatchCtxt KappaExpr) in_ty'
-- match the patterns against the parameters
- match_code <- matchSimplys (map Var param_ids) LambdaExpr pats core_expr
+ match_code <- matchSimplys (map Var param_ids) (ArrowMatchCtxt KappaExpr) pats core_expr
fail_expr
-- match the parameters against the top of the old stack
(stack_id, param_code) <- matchVarStack param_ids stack_id' match_code
diff --git a/compiler/GHC/HsToCore/Pmc/Utils.hs b/compiler/GHC/HsToCore/Pmc/Utils.hs
index faced2f27c..c79c1025d6 100644
--- a/compiler/GHC/HsToCore/Pmc/Utils.hs
+++ b/compiler/GHC/HsToCore/Pmc/Utils.hs
@@ -1,4 +1,5 @@
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | Utility module for the pattern-match coverage checker.
@@ -87,7 +88,7 @@ exhaustiveWarningFlag IfAlt = Just Opt_WarnIncompletePatterns
exhaustiveWarningFlag LambdaExpr = Just Opt_WarnIncompleteUniPatterns
exhaustiveWarningFlag PatBindRhs = Just Opt_WarnIncompleteUniPatterns
exhaustiveWarningFlag PatBindGuards = Just Opt_WarnIncompletePatterns
-exhaustiveWarningFlag ProcExpr = Just Opt_WarnIncompleteUniPatterns
+exhaustiveWarningFlag (ArrowMatchCtxt c) = arrowMatchContextExhaustiveWarningFlag c
exhaustiveWarningFlag RecUpd = Just Opt_WarnIncompletePatternsRecUpd
exhaustiveWarningFlag ThPatSplice = Nothing
exhaustiveWarningFlag PatSyn = Nothing
@@ -96,6 +97,12 @@ exhaustiveWarningFlag ThPatQuote = Nothing
-- etc. They are often *supposed* to be incomplete
exhaustiveWarningFlag (StmtCtxt {}) = Nothing
+arrowMatchContextExhaustiveWarningFlag :: HsArrowMatchContext -> Maybe WarningFlag
+arrowMatchContextExhaustiveWarningFlag = \ case
+ ProcExpr -> Just Opt_WarnIncompleteUniPatterns
+ ArrowCaseAlt -> Just Opt_WarnIncompletePatterns
+ KappaExpr -> Just Opt_WarnIncompleteUniPatterns
+
-- | Check whether any part of pattern match checking is enabled for this
-- 'HsMatchContext' (does not matter whether it is the redundancy check or the
-- exhaustiveness check).
diff --git a/compiler/GHC/Rename/Bind.hs b/compiler/GHC/Rename/Bind.hs
index a4c3ab9865..1e4c43cf7d 100644
--- a/compiler/GHC/Rename/Bind.hs
+++ b/compiler/GHC/Rename/Bind.hs
@@ -1220,13 +1220,16 @@ rnMatch' ctxt rnBody (Match { m_ctxt = mf, m_pats = pats, m_grhss = grhss })
emptyCaseErr :: HsMatchContext GhcRn -> TcRnMessage
emptyCaseErr ctxt = TcRnUnknownMessage $ mkPlainError noHints $
- hang (text "Empty list of alternatives in" <+> pp_ctxt)
+ hang (text "Empty list of alternatives in" <+> pp_ctxt ctxt)
2 (text "Use EmptyCase to allow this")
where
- pp_ctxt = case ctxt of
- CaseAlt -> text "case expression"
- LambdaExpr -> text "\\case expression"
- _ -> text "(unexpected)" <+> pprMatchContextNoun ctxt
+ pp_ctxt :: HsMatchContext GhcRn -> SDoc
+ pp_ctxt c = case c of
+ CaseAlt -> text "case expression"
+ LambdaExpr -> text "\\case expression"
+ ArrowMatchCtxt ArrowCaseAlt -> text "case expression"
+ ArrowMatchCtxt KappaExpr -> text "kappa abstraction"
+ _ -> text "(unexpected)" <+> pprMatchContextNoun c
{-
************************************************************************
diff --git a/compiler/GHC/Rename/Expr.hs b/compiler/GHC/Rename/Expr.hs
index 93949c5d83..c7ef4dcfbd 100644
--- a/compiler/GHC/Rename/Expr.hs
+++ b/compiler/GHC/Rename/Expr.hs
@@ -553,7 +553,7 @@ rnExpr e@(HsStatic _ expr) = do
rnExpr (HsProc x pat body)
= newArrowScope $
- rnPat ProcExpr pat $ \ pat' -> do
+ rnPat (ArrowMatchCtxt ProcExpr) pat $ \ pat' -> do
{ (body',fvBody) <- rnCmdTop body
; return (HsProc x pat' body', fvBody) }
@@ -798,7 +798,7 @@ rnCmd (HsCmdApp x fun arg)
; return (HsCmdApp x fun' arg', fvFun `plusFV` fvArg) }
rnCmd (HsCmdLam _ matches)
- = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLCmd matches
+ = do { (matches', fvMatch) <- rnMatchGroup (ArrowMatchCtxt KappaExpr) rnLCmd matches
; return (HsCmdLam noExtField matches', fvMatch) }
rnCmd (HsCmdPar x lpar e rpar)
@@ -807,12 +807,12 @@ rnCmd (HsCmdPar x lpar e rpar)
rnCmd (HsCmdCase _ expr matches)
= do { (new_expr, e_fvs) <- rnLExpr expr
- ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches
+ ; (new_matches, ms_fvs) <- rnMatchGroup (ArrowMatchCtxt ArrowCaseAlt) rnLCmd matches
; return (HsCmdCase noExtField new_expr new_matches
, e_fvs `plusFV` ms_fvs) }
rnCmd (HsCmdLamCase x matches)
- = do { (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches
+ = do { (new_matches, ms_fvs) <- rnMatchGroup (ArrowMatchCtxt ArrowCaseAlt) rnLCmd matches
; return (HsCmdLamCase x new_matches, ms_fvs) }
rnCmd (HsCmdIf _ _ p b1 b2)
diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs
index bde384887a..1fa94e496a 100644
--- a/compiler/GHC/Tc/Errors/Ppr.hs
+++ b/compiler/GHC/Tc/Errors/Ppr.hs
@@ -500,7 +500,13 @@ instance Diagnostic TcRnMessage where
TcRnCannotDeriveInstance cls cls_tys mb_strat newtype_deriving reason
-> mkSimpleDecorated $
derivErrDiagnosticMessage cls cls_tys mb_strat newtype_deriving True reason
-
+ TcRnLazyGADTPattern
+ -> mkSimpleDecorated $
+ hang (text "An existential or GADT data constructor cannot be used")
+ 2 (text "inside a lazy (~) pattern")
+ TcRnArrowProcGADTPattern
+ -> mkSimpleDecorated $
+ text "Proc patterns cannot use existential or GADT data constructors"
diagnosticReason = \case
TcRnUnknownMessage m
@@ -711,6 +717,10 @@ instance Diagnostic TcRnMessage where
DerivErrBadConstructor{} -> ErrorWithoutFlag
DerivErrGenerics{} -> ErrorWithoutFlag
DerivErrEnumOrProduct{} -> ErrorWithoutFlag
+ TcRnLazyGADTPattern
+ -> ErrorWithoutFlag
+ TcRnArrowProcGADTPattern
+ -> ErrorWithoutFlag
diagnosticHints = \case
TcRnUnknownMessage m
@@ -915,7 +925,10 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnCannotDeriveInstance cls _ _ newtype_deriving rea
-> deriveInstanceErrReasonHints cls newtype_deriving rea
-
+ TcRnLazyGADTPattern
+ -> noHints
+ TcRnArrowProcGADTPattern
+ -> noHints
deriveInstanceErrReasonHints :: Class
-> UsingGeneralizedNewtypeDeriving
diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs
index a7418e7e58..db0a6b0c33 100644
--- a/compiler/GHC/Tc/Errors/Types.hs
+++ b/compiler/GHC/Tc/Errors/Types.hs
@@ -1373,6 +1373,20 @@ data TcRnMessage where
-- an instance for the class.
-> TcRnMessage
+ {-| TcRnLazyGADTPattern is an error that occurs when a user writes a nested
+ GADT pattern match inside a lazy (~) pattern.
+
+ Test case: gadt/lazypat
+ -}
+ TcRnLazyGADTPattern :: TcRnMessage
+
+ {-| TcRnArrowProcGADTPattern is an error that occurs when a user writes a
+ GADT pattern inside arrow proc notation.
+
+ Test case: arrows/should_fail/arrowfail004.
+ -}
+ TcRnArrowProcGADTPattern :: TcRnMessage
+
-- | Which parts of a record field are affected by a particular error or warning.
data RecordFieldPart
= RecordFieldConstructor !Name
diff --git a/compiler/GHC/Tc/Gen/Arrow.hs b/compiler/GHC/Tc/Gen/Arrow.hs
index 207f83cb51..0d0e482b35 100644
--- a/compiler/GHC/Tc/Gen/Arrow.hs
+++ b/compiler/GHC/Tc/Gen/Arrow.hs
@@ -100,7 +100,7 @@ tcProc pat cmd@(L _ (HsCmdTop names _)) exp_ty
; names' <- mapM (tcSyntaxName ProcOrigin arr_ty) names
; let cmd_env = CmdEnv { cmd_arr = arr_ty }
; (pat', cmd') <- newArrowScope
- $ tcCheckPat ProcExpr pat (unrestricted arg_ty)
+ $ tcCheckPat (ArrowMatchCtxt ProcExpr) pat (unrestricted arg_ty)
$ tcCmdTop cmd_env names' cmd (unitTy, res_ty)
; let res_co = mkTcTransCo co
(mkTcAppCo co1 (mkTcNomReflCo res_ty))
@@ -262,11 +262,13 @@ tc_cmd env
-- Check the patterns, and the GRHSs inside
; (pats', grhss') <- setSrcSpanA mtch_loc $
- tcPats LambdaExpr pats (map (unrestricted . mkCheckExpType) arg_tys) $
+ tcPats (ArrowMatchCtxt KappaExpr)
+ pats (map (unrestricted . mkCheckExpType) arg_tys) $
tc_grhss grhss cmd_stk' (mkCheckExpType res_ty)
; let match' = L mtch_loc (Match { m_ext = noAnn
- , m_ctxt = LambdaExpr, m_pats = pats'
+ , m_ctxt = ArrowMatchCtxt KappaExpr
+ , m_pats = pats'
, m_grhss = grhss' })
arg_tys = map (unrestricted . hsLPatType) pats'
cmd' = HsCmdLam x (MG { mg_alts = L l [match']
@@ -275,7 +277,7 @@ tc_cmd env
; return (mkHsCmdWrap (mkWpCastN co) cmd') }
where
n_pats = length pats
- match_ctxt = LambdaExpr -- Maybe KappaExpr?
+ match_ctxt = ArrowMatchCtxt KappaExpr
pg_ctxt = PatGuard match_ctxt
tc_grhss (GRHSs x grhss binds) stk_ty res_ty
@@ -350,7 +352,7 @@ tcCmdMatches :: CmdEnv
tcCmdMatches env scrut_ty matches (stk, res_ty)
= tcMatchesCase match_ctxt (unrestricted scrut_ty) matches (mkCheckExpType res_ty)
where
- match_ctxt = MC { mc_what = CaseAlt,
+ match_ctxt = MC { mc_what = ArrowMatchCtxt ArrowCaseAlt,
mc_body = mc_body }
mc_body body res_ty' = do { res_ty' <- expTypeToType res_ty'
; tcCmd env body (stk, res_ty') }
diff --git a/compiler/GHC/Tc/Gen/Pat.hs b/compiler/GHC/Tc/Gen/Pat.hs
index 82d707dd76..78a4e22901 100644
--- a/compiler/GHC/Tc/Gen/Pat.hs
+++ b/compiler/GHC/Tc/Gen/Pat.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
@@ -886,8 +887,10 @@ tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
-- Add the stupid theta
; setSrcSpanA con_span $ addDataConStupidTheta data_con ctxt_res_tys
+ -- Check that this isn't a GADT pattern match
+ -- in situations in which that isn't allowed.
; let all_arg_tys = eqSpecPreds eq_spec ++ theta ++ (map scaledThing arg_tys)
- ; checkExistentials ex_tvs all_arg_tys penv
+ ; checkGADT (RealDataCon data_con) ex_tvs all_arg_tys penv
; tenv1 <- instTyVarsWith PatOrigin univ_tvs ctxt_res_tys
-- NB: Do not use zipTvSubst! See #14154
@@ -979,8 +982,11 @@ tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
; (subst, univ_tvs') <- newMetaTyVars univ_tvs
+ -- Check that we aren't matching on a GADT-like pattern synonym
+ -- in situations in which that isn't allowed.
; let all_arg_tys = ty : prov_theta ++ (map scaledThing arg_tys)
- ; checkExistentials ex_tvs all_arg_tys penv
+ ; checkGADT (PatSynCon pat_syn) ex_tvs all_arg_tys penv
+
; (tenv, ex_tvs') <- tcInstSuperSkolTyVarsX subst ex_tvs
-- This freshens: Note [Freshen existentials]
@@ -1344,11 +1350,15 @@ these bindings scope over 'term'.
The Right Thing is not to confuse these constraints together. But for
now the Easy Thing is to ensure that we do not have existential or
-GADT constraints in a 'proc', and to short-cut the constraint
-simplification for such vanilla patterns so that it binds no
-constraints. Hence the 'fast path' in tcConPat; but it's also a good
-plan for ordinary vanilla patterns to bypass the constraint
-simplification step.
+GADT constraints in a 'proc', which we do by disallowing any
+non-vanilla pattern match (i.e. one that introduces existential
+variables or provided constraints), in tcDataConPat and tcPatSynPat.
+
+We also short-cut the constraint simplification for such vanilla patterns,
+so that we bind no constraints. Hence the 'fast path' in tcDataConPat;
+which applies more generally (not just within 'proc'), as it's a good
+plan in general to bypass the constraint simplification step entirely
+when it's not needed.
************************************************************************
* *
@@ -1442,28 +1452,30 @@ maybeWrapPatCtxt pat tcm thing_inside
msg = hang (text "In the pattern:") 2 (ppr pat)
-----------------------------------------------
-checkExistentials :: [TyVar] -- existentials
- -> [Type] -- argument types
- -> PatEnv -> TcM ()
- -- See Note [Existential check]]
- -- See Note [Arrows and patterns]
-checkExistentials ex_tvs tys _
- | all (not . (`elemVarSet` tyCoVarsOfTypes tys)) ex_tvs = return ()
-checkExistentials _ _ (PE { pe_ctxt = LetPat {}}) = return ()
-checkExistentials _ _ (PE { pe_ctxt = LamPat ProcExpr }) = failWithTc existentialProcPat
-checkExistentials _ _ (PE { pe_lazy = True }) = failWithTc existentialLazyPat
-checkExistentials _ _ _ = return ()
-
-existentialLazyPat :: TcRnMessage
-existentialLazyPat
- = TcRnUnknownMessage $ mkPlainError noHints $
- hang (text "An existential or GADT data constructor cannot be used")
- 2 (text "inside a lazy (~) pattern")
-existentialProcPat :: TcRnMessage
-existentialProcPat
- = TcRnUnknownMessage $ mkPlainError noHints $
- text "Proc patterns cannot use existential or GADT data constructors"
+-- | Check that a pattern isn't a GADT, or doesn't have existential variables,
+-- in a situation in which that is not permitted (inside a lazy pattern, or
+-- in arrow notation).
+checkGADT :: ConLike
+ -> [TyVar] -- ^ existentials
+ -> [Type] -- ^ argument types
+ -> PatEnv
+ -> TcM ()
+checkGADT conlike ex_tvs arg_tys = \case
+ PE { pe_ctxt = LetPat {} }
+ -> return ()
+ PE { pe_ctxt = LamPat (ArrowMatchCtxt {}) }
+ | not $ isVanillaConLike conlike
+ -- See Note [Arrows and patterns]
+ -> failWithTc TcRnArrowProcGADTPattern
+ PE { pe_lazy = True }
+ | has_existentials
+ -- See Note [Existential check]
+ -> failWithTc TcRnLazyGADTPattern
+ _ -> return ()
+ where
+ has_existentials :: Bool
+ has_existentials = any (`elemVarSet` tyCoVarsOfTypes arg_tys) ex_tvs
badFieldCon :: ConLike -> FieldLabelString -> TcRnMessage
badFieldCon con field
diff --git a/compiler/Language/Haskell/Syntax/Expr.hs b/compiler/Language/Haskell/Syntax/Expr.hs
index 563505e373..2215ed1210 100644
--- a/compiler/Language/Haskell/Syntax/Expr.hs
+++ b/compiler/Language/Haskell/Syntax/Expr.hs
@@ -1674,7 +1674,8 @@ data HsMatchContext p
| LambdaExpr -- ^Patterns of a lambda
| CaseAlt -- ^Patterns and guards on a case alternative
| IfAlt -- ^Guards of a multi-way if alternative
- | ProcExpr -- ^Patterns of a proc
+ | ArrowMatchCtxt -- ^A pattern match inside arrow notation
+ HsArrowMatchContext
| PatBindRhs -- ^A pattern binding eg [y] <- e = e
| PatBindGuards -- ^Guards of pattern bindings, e.g.,
-- (Just b) | Just _ <- x = e
@@ -1705,6 +1706,12 @@ data HsStmtContext p
| TransStmtCtxt (HsStmtContext p) -- ^A branch of a transform stmt
| ArrowExpr -- ^do-notation in an arrow-command context
+-- | Haskell arrow match context.
+data HsArrowMatchContext
+ = ProcExpr -- ^ A proc expression
+ | ArrowCaseAlt -- ^ A case alternative inside arrow notation
+ | KappaExpr -- ^ An arrow kappa abstraction
+
data HsDoFlavour
= DoExpr (Maybe ModuleName) -- ^[ModuleName.]do { ... }
| MDoExpr (Maybe ModuleName) -- ^[ModuleName.]mdo { ... } ie recursive do-expression
@@ -1767,7 +1774,7 @@ matchSeparator (FunRhs {}) = text "="
matchSeparator CaseAlt = text "->"
matchSeparator IfAlt = text "->"
matchSeparator LambdaExpr = text "->"
-matchSeparator ProcExpr = text "->"
+matchSeparator (ArrowMatchCtxt{})= text "->"
matchSeparator PatBindRhs = text "="
matchSeparator PatBindGuards = text "="
matchSeparator (StmtCtxt _) = text "<-"
@@ -1783,9 +1790,10 @@ pprMatchContext ctxt
| want_an ctxt = text "an" <+> pprMatchContextNoun ctxt
| otherwise = text "a" <+> pprMatchContextNoun ctxt
where
- want_an (FunRhs {}) = True -- Use "an" in front
- want_an ProcExpr = True
- want_an _ = False
+ want_an (FunRhs {}) = True -- Use "an" in front
+ want_an (ArrowMatchCtxt ProcExpr) = True
+ want_an (ArrowMatchCtxt KappaExpr) = True
+ want_an _ = False
pprMatchContextNoun :: forall p. (Outputable (IdP p), UnXRec p)
=> HsMatchContext p -> SDoc
@@ -1800,11 +1808,16 @@ pprMatchContextNoun ThPatQuote = text "Template Haskell pattern quotation"
pprMatchContextNoun PatBindRhs = text "pattern binding"
pprMatchContextNoun PatBindGuards = text "pattern binding guards"
pprMatchContextNoun LambdaExpr = text "lambda abstraction"
-pprMatchContextNoun ProcExpr = text "arrow abstraction"
+pprMatchContextNoun (ArrowMatchCtxt c)= pprArrowMatchContextNoun c
pprMatchContextNoun (StmtCtxt ctxt) = text "pattern binding in"
$$ pprAStmtContext ctxt
pprMatchContextNoun PatSyn = text "pattern synonym declaration"
+pprArrowMatchContextNoun :: HsArrowMatchContext -> SDoc
+pprArrowMatchContextNoun ProcExpr = text "arrow proc pattern"
+pprArrowMatchContextNoun ArrowCaseAlt = text "case alternative within arrow notation"
+pprArrowMatchContextNoun KappaExpr = text "arrow kappa abstraction"
+
-----------------
pprAStmtContext, pprStmtContext :: (Outputable (IdP p), UnXRec p)
=> HsStmtContext p -> SDoc