summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorRyan Scott <ryan.gl.scott@gmail.com>2017-09-02 15:33:11 -0400
committerRyan Scott <ryan.gl.scott@gmail.com>2017-09-02 15:33:12 -0400
commit5dd6b13c6e2942976aa3b5f4906ff7d0f959272d (patch)
tree233df1050c497f1accc7a3ded00fa4bd9f71ee6e /compiler
parent6330b0b0938bc7b27463b3bbfa0df661e4a966b1 (diff)
downloadhaskell-5dd6b13c6e2942976aa3b5f4906ff7d0f959272d.tar.gz
Disallow bang/lazy patterns in the RHSes of implicitly bidirectional patsyns
Summary: GHC was allowing implicitly bidirectional pattern synonyms with bang patterns and irrefutable patterns in the RHS, like so: ```lang=haskell pattern StrictJust a = Just !a ``` This has multiple problems: 1. `Just !a` isn't a valid expression, so it feels strange to allow it in an implicitly bidirectional pattern synonym. 2. `StrictJust` doesn't provide the strictness properties one would expect from a strict constructor. (One could imagine a design where the `StrictJust` builder infers a bang pattern for its pattern variable, but accomplishing this inference in a way that accounts for all possible patterns on the RHS, including other pattern synonyms, is somewhat awkward, so we do not pursue this design.) We nip these issues in the bud by simply disallowing bang/irrefutable patterns on the RHS. Test Plan: make test TEST="T14112 unidir" Reviewers: simonpj, austin, bgamari Reviewed By: simonpj Subscribers: rwbarton, thomie GHC Trac Issues: #14112 Differential Revision: https://phabricator.haskell.org/D3896
Diffstat (limited to 'compiler')
-rw-r--r--compiler/typecheck/TcPatSyn.hs32
1 files changed, 26 insertions, 6 deletions
diff --git a/compiler/typecheck/TcPatSyn.hs b/compiler/typecheck/TcPatSyn.hs
index 67e031aeaa..fe9ad18a92 100644
--- a/compiler/typecheck/TcPatSyn.hs
+++ b/compiler/typecheck/TcPatSyn.hs
@@ -574,7 +574,7 @@ tcPatSynBuilderBind (PSB { psb_id = L loc name, psb_def = lpat
mb_match_group
= case dir of
ExplicitBidirectional explicit_mg -> Right explicit_mg
- ImplicitBidirectional -> fmap mk_mg (tcPatToExpr args lpat)
+ ImplicitBidirectional -> fmap mk_mg (tcPatToExpr name args lpat)
Unidirectional -> panic "tcPatSynBuilderBind"
mk_mg :: LHsExpr GhcRn -> MatchGroup GhcRn (LHsExpr GhcRn)
@@ -621,7 +621,8 @@ add_void need_dummy_arg ty
| need_dummy_arg = mkFunTy voidPrimTy ty
| otherwise = ty
-tcPatToExpr :: [Located Name] -> LPat GhcRn -> Either MsgDoc (LHsExpr GhcRn)
+tcPatToExpr :: Name -> [Located Name] -> LPat GhcRn
+ -> Either MsgDoc (LHsExpr GhcRn)
-- Given a /pattern/, return an /expression/ that builds a value
-- that matches the pattern. E.g. if the pattern is (Just [x]),
-- the expression is (Just [x]). They look the same, but the
@@ -630,7 +631,7 @@ tcPatToExpr :: [Located Name] -> LPat GhcRn -> Either MsgDoc (LHsExpr GhcRn)
--
-- Returns (Left r) if the pattern is not invertible, for reason r.
-- See Note [Builder for a bidirectional pattern synonym]
-tcPatToExpr args pat = go pat
+tcPatToExpr name args pat = go pat
where
lhsVars = mkNameSet (map unLoc args)
@@ -667,8 +668,6 @@ tcPatToExpr args pat = go pat
| otherwise
= Left (quotes (ppr var) <+> text "is not bound by the LHS of the pattern synonym")
go1 (ParPat pat) = fmap HsPar $ go pat
- go1 (LazyPat pat) = go1 (unLoc pat)
- go1 (BangPat pat) = go1 (unLoc pat)
go1 (PArrPat pats ptt) = do { exprs <- mapM go pats
; return $ ExplicitPArr ptt exprs }
go1 (ListPat pats ptt reb) = do { exprs <- mapM go pats
@@ -689,7 +688,28 @@ tcPatToExpr args pat = go pat
go1 (SplicePat (HsSpliced _ (HsSplicedPat pat)))
= go1 pat
go1 (SplicePat (HsSpliced{})) = panic "Invalid splice variety"
- go1 p = Left (text "pattern" <+> quotes (ppr p) <+> text "is not invertible")
+
+ -- The following patterns are not invertible.
+ go1 p@(BangPat {}) = notInvertible p -- #14112
+ go1 p@(LazyPat {}) = notInvertible p
+ go1 p@(WildPat {}) = notInvertible p
+ go1 p@(AsPat {}) = notInvertible p
+ go1 p@(ViewPat {}) = notInvertible p
+ go1 p@(NPlusKPat {}) = notInvertible p
+ go1 p@(SplicePat (HsTypedSplice {})) = notInvertible p
+ go1 p@(SplicePat (HsUntypedSplice {})) = notInvertible p
+ go1 p@(SplicePat (HsQuasiQuote {})) = notInvertible p
+
+ notInvertible p = Left $
+ text "Pattern" <+> quotes (ppr p) <+> text "is not invertible"
+ $+$ hang (text "Suggestion: instead use an explicitly bidirectional"
+ <+> text "pattern synonym, e.g.")
+ 2 (hang (text "pattern" <+> pp_name <+> pp_args <+> larrow
+ <+> ppr pat <+> text "where")
+ 2 (pp_name <+> pp_args <+> equals <+> text "..."))
+ where
+ pp_name = ppr name
+ pp_args = hsep (map ppr args)
{- Note [Builder for a bidirectional pattern synonym]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~