summaryrefslogtreecommitdiff
path: root/compiler/rename/RnExpr.hs
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2019-10-06 12:52:27 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-01-08 06:16:31 -0500
commitd491a6795d507eabe35d8aec63c534d29f2d305b (patch)
tree25d60450944f4c1ce6bea35b65f58dc7d761ad67 /compiler/rename/RnExpr.hs
parentb69a3460d11cba49e861f708100801c8e25efa3e (diff)
downloadhaskell-d491a6795d507eabe35d8aec63c534d29f2d305b.tar.gz
Module hierarchy: Renamer (cf #13009)
Diffstat (limited to 'compiler/rename/RnExpr.hs')
-rw-r--r--compiler/rename/RnExpr.hs2210
1 files changed, 0 insertions, 2210 deletions
diff --git a/compiler/rename/RnExpr.hs b/compiler/rename/RnExpr.hs
deleted file mode 100644
index 693d818f67..0000000000
--- a/compiler/rename/RnExpr.hs
+++ /dev/null
@@ -1,2210 +0,0 @@
-{-
-(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-
-\section[RnExpr]{Renaming of expressions}
-
-Basically dependency analysis.
-
-Handles @Match@, @GRHSs@, @HsExpr@, and @Qualifier@ datatypes. In
-general, all of these functions return a renamed thing, and a set of
-free variables.
--}
-
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE ViewPatterns #-}
-
-module RnExpr (
- rnLExpr, rnExpr, rnStmts
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import RnBinds ( rnLocalBindsAndThen, rnLocalValBindsLHS, rnLocalValBindsRHS,
- rnMatchGroup, rnGRHS, makeMiniFixityEnv)
-import GHC.Hs
-import TcEnv ( isBrackStage )
-import TcRnMonad
-import Module ( getModule )
-import RnEnv
-import RnFixity
-import RnUtils ( HsDocContext(..), bindLocalNamesFV, checkDupNames
- , bindLocalNames
- , mapMaybeFvRn, mapFvRn
- , warnUnusedLocalBinds, typeAppErr
- , checkUnusedRecordWildcard )
-import RnUnbound ( reportUnboundName )
-import RnSplice ( rnBracket, rnSpliceExpr, checkThLocalName )
-import RnTypes
-import RnPat
-import DynFlags
-import PrelNames
-
-import BasicTypes
-import Name
-import NameSet
-import RdrName
-import UniqSet
-import Data.List
-import Util
-import ListSetOps ( removeDups )
-import ErrUtils
-import Outputable
-import SrcLoc
-import FastString
-import Control.Monad
-import TysWiredIn ( nilDataConName )
-import qualified GHC.LanguageExtensions as LangExt
-
-import Data.Ord
-import Data.Array
-import qualified Data.List.NonEmpty as NE
-
-import Unique ( mkVarOccUnique )
-
-{-
-************************************************************************
-* *
-\subsubsection{Expressions}
-* *
-************************************************************************
--}
-
-rnExprs :: [LHsExpr GhcPs] -> RnM ([LHsExpr GhcRn], FreeVars)
-rnExprs ls = rnExprs' ls emptyUniqSet
- where
- rnExprs' [] acc = return ([], acc)
- rnExprs' (expr:exprs) acc =
- do { (expr', fvExpr) <- rnLExpr expr
- -- Now we do a "seq" on the free vars because typically it's small
- -- or empty, especially in very long lists of constants
- ; let acc' = acc `plusFV` fvExpr
- ; (exprs', fvExprs) <- acc' `seq` rnExprs' exprs acc'
- ; return (expr':exprs', fvExprs) }
-
--- Variables. We look up the variable and return the resulting name.
-
-rnLExpr :: LHsExpr GhcPs -> RnM (LHsExpr GhcRn, FreeVars)
-rnLExpr = wrapLocFstM rnExpr
-
-rnExpr :: HsExpr GhcPs -> RnM (HsExpr GhcRn, FreeVars)
-
-finishHsVar :: Located Name -> RnM (HsExpr GhcRn, FreeVars)
--- Separated from rnExpr because it's also used
--- when renaming infix expressions
-finishHsVar (L l name)
- = do { this_mod <- getModule
- ; when (nameIsLocalOrFrom this_mod name) $
- checkThLocalName name
- ; return (HsVar noExtField (L l name), unitFV name) }
-
-rnUnboundVar :: RdrName -> RnM (HsExpr GhcRn, FreeVars)
-rnUnboundVar v
- = do { if isUnqual v
- then -- Treat this as a "hole"
- -- Do not fail right now; instead, return HsUnboundVar
- -- and let the type checker report the error
- return (HsUnboundVar noExtField (rdrNameOcc v), emptyFVs)
-
- else -- Fail immediately (qualified name)
- do { n <- reportUnboundName v
- ; return (HsVar noExtField (noLoc n), emptyFVs) } }
-
-rnExpr (HsVar _ (L l v))
- = do { opt_DuplicateRecordFields <- xoptM LangExt.DuplicateRecordFields
- ; mb_name <- lookupOccRn_overloaded opt_DuplicateRecordFields v
- ; dflags <- getDynFlags
- ; case mb_name of {
- Nothing -> rnUnboundVar v ;
- Just (Left name)
- | name == nilDataConName -- Treat [] as an ExplicitList, so that
- -- OverloadedLists works correctly
- -- Note [Empty lists] in GHC.Hs.Expr
- , xopt LangExt.OverloadedLists dflags
- -> rnExpr (ExplicitList noExtField Nothing [])
-
- | otherwise
- -> finishHsVar (L l name) ;
- Just (Right [s]) ->
- return ( HsRecFld noExtField (Unambiguous s (L l v) ), unitFV s) ;
- Just (Right fs@(_:_:_)) ->
- return ( HsRecFld noExtField (Ambiguous noExtField (L l v))
- , mkFVs fs);
- Just (Right []) -> panic "runExpr/HsVar" } }
-
-rnExpr (HsIPVar x v)
- = return (HsIPVar x v, emptyFVs)
-
-rnExpr (HsUnboundVar x v)
- = return (HsUnboundVar x v, emptyFVs)
-
-rnExpr (HsOverLabel x _ v)
- = do { rebindable_on <- xoptM LangExt.RebindableSyntax
- ; if rebindable_on
- then do { fromLabel <- lookupOccRn (mkVarUnqual (fsLit "fromLabel"))
- ; return (HsOverLabel x (Just fromLabel) v, unitFV fromLabel) }
- else return (HsOverLabel x Nothing v, emptyFVs) }
-
-rnExpr (HsLit x lit@(HsString src s))
- = do { opt_OverloadedStrings <- xoptM LangExt.OverloadedStrings
- ; if opt_OverloadedStrings then
- rnExpr (HsOverLit x (mkHsIsString src s))
- else do {
- ; rnLit lit
- ; return (HsLit x (convertLit lit), emptyFVs) } }
-
-rnExpr (HsLit x lit)
- = do { rnLit lit
- ; return (HsLit x(convertLit lit), emptyFVs) }
-
-rnExpr (HsOverLit x lit)
- = do { ((lit', mb_neg), fvs) <- rnOverLit lit -- See Note [Negative zero]
- ; case mb_neg of
- Nothing -> return (HsOverLit x lit', fvs)
- Just neg -> return (HsApp x (noLoc neg) (noLoc (HsOverLit x lit'))
- , fvs ) }
-
-rnExpr (HsApp x fun arg)
- = do { (fun',fvFun) <- rnLExpr fun
- ; (arg',fvArg) <- rnLExpr arg
- ; return (HsApp x fun' arg', fvFun `plusFV` fvArg) }
-
-rnExpr (HsAppType x fun arg)
- = do { type_app <- xoptM LangExt.TypeApplications
- ; unless type_app $ addErr $ typeAppErr "type" $ hswc_body arg
- ; (fun',fvFun) <- rnLExpr fun
- ; (arg',fvArg) <- rnHsWcType HsTypeCtx arg
- ; return (HsAppType x fun' arg', fvFun `plusFV` fvArg) }
-
-rnExpr (OpApp _ e1 op e2)
- = do { (e1', fv_e1) <- rnLExpr e1
- ; (e2', fv_e2) <- rnLExpr e2
- ; (op', fv_op) <- rnLExpr op
-
- -- Deal with fixity
- -- When renaming code synthesised from "deriving" declarations
- -- we used to avoid fixity stuff, but we can't easily tell any
- -- more, so I've removed the test. Adding HsPars in TcGenDeriv
- -- should prevent bad things happening.
- ; fixity <- case op' of
- L _ (HsVar _ (L _ n)) -> lookupFixityRn n
- L _ (HsRecFld _ f) -> lookupFieldFixityRn f
- _ -> return (Fixity NoSourceText minPrecedence InfixL)
- -- c.f. lookupFixity for unbound
-
- ; final_e <- mkOpAppRn e1' op' fixity e2'
- ; return (final_e, fv_e1 `plusFV` fv_op `plusFV` fv_e2) }
-
-rnExpr (NegApp _ e _)
- = do { (e', fv_e) <- rnLExpr e
- ; (neg_name, fv_neg) <- lookupSyntaxName negateName
- ; final_e <- mkNegAppRn e' neg_name
- ; return (final_e, fv_e `plusFV` fv_neg) }
-
-------------------------------------------
--- Template Haskell extensions
-rnExpr e@(HsBracket _ br_body) = rnBracket e br_body
-
-rnExpr (HsSpliceE _ splice) = rnSpliceExpr splice
-
----------------------------------------------
--- Sections
--- See Note [Parsing sections] in Parser.y
-rnExpr (HsPar x (L loc (section@(SectionL {}))))
- = do { (section', fvs) <- rnSection section
- ; return (HsPar x (L loc section'), fvs) }
-
-rnExpr (HsPar x (L loc (section@(SectionR {}))))
- = do { (section', fvs) <- rnSection section
- ; return (HsPar x (L loc section'), fvs) }
-
-rnExpr (HsPar x e)
- = do { (e', fvs_e) <- rnLExpr e
- ; return (HsPar x e', fvs_e) }
-
-rnExpr expr@(SectionL {})
- = do { addErr (sectionErr expr); rnSection expr }
-rnExpr expr@(SectionR {})
- = do { addErr (sectionErr expr); rnSection expr }
-
----------------------------------------------
-rnExpr (HsPragE x prag expr)
- = do { (expr', fvs_expr) <- rnLExpr expr
- ; return (HsPragE x (rn_prag prag) expr', fvs_expr) }
- where
- rn_prag :: HsPragE GhcPs -> HsPragE GhcRn
- rn_prag (HsPragSCC x1 src ann) = HsPragSCC x1 src ann
- rn_prag (HsPragCore x1 src lbl) = HsPragCore x1 src lbl
- rn_prag (HsPragTick x1 src info srcInfo) = HsPragTick x1 src info srcInfo
- rn_prag (XHsPragE x) = noExtCon x
-
-rnExpr (HsLam x matches)
- = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLExpr matches
- ; return (HsLam x matches', fvMatch) }
-
-rnExpr (HsLamCase x matches)
- = do { (matches', fvs_ms) <- rnMatchGroup CaseAlt rnLExpr matches
- ; return (HsLamCase x matches', fvs_ms) }
-
-rnExpr (HsCase x expr matches)
- = do { (new_expr, e_fvs) <- rnLExpr expr
- ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLExpr matches
- ; return (HsCase x new_expr new_matches, e_fvs `plusFV` ms_fvs) }
-
-rnExpr (HsLet x (L l binds) expr)
- = rnLocalBindsAndThen binds $ \binds' _ -> do
- { (expr',fvExpr) <- rnLExpr expr
- ; return (HsLet x (L l binds') expr', fvExpr) }
-
-rnExpr (HsDo x do_or_lc (L l stmts))
- = do { ((stmts', _), fvs) <-
- rnStmtsWithPostProcessing do_or_lc rnLExpr
- postProcessStmtsForApplicativeDo stmts
- (\ _ -> return ((), emptyFVs))
- ; return ( HsDo x do_or_lc (L l stmts'), fvs ) }
-
-rnExpr (ExplicitList x _ exps)
- = do { opt_OverloadedLists <- xoptM LangExt.OverloadedLists
- ; (exps', fvs) <- rnExprs exps
- ; if opt_OverloadedLists
- then do {
- ; (from_list_n_name, fvs') <- lookupSyntaxName fromListNName
- ; return (ExplicitList x (Just from_list_n_name) exps'
- , fvs `plusFV` fvs') }
- else
- return (ExplicitList x Nothing exps', fvs) }
-
-rnExpr (ExplicitTuple x tup_args boxity)
- = do { checkTupleSection tup_args
- ; checkTupSize (length tup_args)
- ; (tup_args', fvs) <- mapAndUnzipM rnTupArg tup_args
- ; return (ExplicitTuple x tup_args' boxity, plusFVs fvs) }
- where
- rnTupArg (L l (Present x e)) = do { (e',fvs) <- rnLExpr e
- ; return (L l (Present x e'), fvs) }
- rnTupArg (L l (Missing _)) = return (L l (Missing noExtField)
- , emptyFVs)
- rnTupArg (L _ (XTupArg nec)) = noExtCon nec
-
-rnExpr (ExplicitSum x alt arity expr)
- = do { (expr', fvs) <- rnLExpr expr
- ; return (ExplicitSum x alt arity expr', fvs) }
-
-rnExpr (RecordCon { rcon_con_name = con_id
- , rcon_flds = rec_binds@(HsRecFields { rec_dotdot = dd }) })
- = do { con_lname@(L _ con_name) <- lookupLocatedOccRn con_id
- ; (flds, fvs) <- rnHsRecFields (HsRecFieldCon con_name) mk_hs_var rec_binds
- ; (flds', fvss) <- mapAndUnzipM rn_field flds
- ; let rec_binds' = HsRecFields { rec_flds = flds', rec_dotdot = dd }
- ; return (RecordCon { rcon_ext = noExtField
- , rcon_con_name = con_lname, rcon_flds = rec_binds' }
- , fvs `plusFV` plusFVs fvss `addOneFV` con_name) }
- where
- mk_hs_var l n = HsVar noExtField (L l n)
- rn_field (L l fld) = do { (arg', fvs) <- rnLExpr (hsRecFieldArg fld)
- ; return (L l (fld { hsRecFieldArg = arg' }), fvs) }
-
-rnExpr (RecordUpd { rupd_expr = expr, rupd_flds = rbinds })
- = do { (expr', fvExpr) <- rnLExpr expr
- ; (rbinds', fvRbinds) <- rnHsRecUpdFields rbinds
- ; return (RecordUpd { rupd_ext = noExtField, rupd_expr = expr'
- , rupd_flds = rbinds' }
- , fvExpr `plusFV` fvRbinds) }
-
-rnExpr (ExprWithTySig _ expr pty)
- = do { (pty', fvTy) <- rnHsSigWcType BindUnlessForall ExprWithTySigCtx pty
- ; (expr', fvExpr) <- bindSigTyVarsFV (hsWcScopedTvs pty') $
- rnLExpr expr
- ; return (ExprWithTySig noExtField expr' pty', fvExpr `plusFV` fvTy) }
-
-rnExpr (HsIf x _ p b1 b2)
- = do { (p', fvP) <- rnLExpr p
- ; (b1', fvB1) <- rnLExpr b1
- ; (b2', fvB2) <- rnLExpr b2
- ; (mb_ite, fvITE) <- lookupIfThenElse
- ; return (HsIf x mb_ite p' b1' b2', plusFVs [fvITE, fvP, fvB1, fvB2]) }
-
-rnExpr (HsMultiIf x alts)
- = do { (alts', fvs) <- mapFvRn (rnGRHS IfAlt rnLExpr) alts
- -- ; return (HsMultiIf ty alts', fvs) }
- ; return (HsMultiIf x alts', fvs) }
-
-rnExpr (ArithSeq x _ seq)
- = do { opt_OverloadedLists <- xoptM LangExt.OverloadedLists
- ; (new_seq, fvs) <- rnArithSeq seq
- ; if opt_OverloadedLists
- then do {
- ; (from_list_name, fvs') <- lookupSyntaxName fromListName
- ; return (ArithSeq x (Just from_list_name) new_seq
- , fvs `plusFV` fvs') }
- else
- return (ArithSeq x Nothing new_seq, fvs) }
-
-{-
-************************************************************************
-* *
- Static values
-* *
-************************************************************************
-
-For the static form we check that it is not used in splices.
-We also collect the free variables of the term which come from
-this module. See Note [Grand plan for static forms] in StaticPtrTable.
--}
-
-rnExpr e@(HsStatic _ expr) = do
- -- Normally, you wouldn't be able to construct a static expression without
- -- first enabling -XStaticPointers in the first place, since that extension
- -- is what makes the parser treat `static` as a keyword. But this is not a
- -- sufficient safeguard, as one can construct static expressions by another
- -- mechanism: Template Haskell (see #14204). To ensure that GHC is
- -- absolutely prepared to cope with static forms, we check for
- -- -XStaticPointers here as well.
- unlessXOptM LangExt.StaticPointers $
- addErr $ hang (text "Illegal static expression:" <+> ppr e)
- 2 (text "Use StaticPointers to enable this extension")
- (expr',fvExpr) <- rnLExpr expr
- stage <- getStage
- case stage of
- Splice _ -> addErr $ sep
- [ text "static forms cannot be used in splices:"
- , nest 2 $ ppr e
- ]
- _ -> return ()
- mod <- getModule
- let fvExpr' = filterNameSet (nameIsLocalOrFrom mod) fvExpr
- return (HsStatic fvExpr' expr', fvExpr)
-
-{-
-************************************************************************
-* *
- Arrow notation
-* *
-************************************************************************
--}
-
-rnExpr (HsProc x pat body)
- = newArrowScope $
- rnPat ProcExpr pat $ \ pat' -> do
- { (body',fvBody) <- rnCmdTop body
- ; return (HsProc x pat' body', fvBody) }
-
-rnExpr other = pprPanic "rnExpr: unexpected expression" (ppr other)
- -- HsWrap
-
-----------------------
--- See Note [Parsing sections] in Parser.y
-rnSection :: HsExpr GhcPs -> RnM (HsExpr GhcRn, FreeVars)
-rnSection section@(SectionR x op expr)
- = do { (op', fvs_op) <- rnLExpr op
- ; (expr', fvs_expr) <- rnLExpr expr
- ; checkSectionPrec InfixR section op' expr'
- ; return (SectionR x op' expr', fvs_op `plusFV` fvs_expr) }
-
-rnSection section@(SectionL x expr op)
- = do { (expr', fvs_expr) <- rnLExpr expr
- ; (op', fvs_op) <- rnLExpr op
- ; checkSectionPrec InfixL section op' expr'
- ; return (SectionL x expr' op', fvs_op `plusFV` fvs_expr) }
-
-rnSection other = pprPanic "rnSection" (ppr other)
-
-{-
-************************************************************************
-* *
- Arrow commands
-* *
-************************************************************************
--}
-
-rnCmdArgs :: [LHsCmdTop GhcPs] -> RnM ([LHsCmdTop GhcRn], FreeVars)
-rnCmdArgs [] = return ([], emptyFVs)
-rnCmdArgs (arg:args)
- = do { (arg',fvArg) <- rnCmdTop arg
- ; (args',fvArgs) <- rnCmdArgs args
- ; return (arg':args', fvArg `plusFV` fvArgs) }
-
-rnCmdTop :: LHsCmdTop GhcPs -> RnM (LHsCmdTop GhcRn, FreeVars)
-rnCmdTop = wrapLocFstM rnCmdTop'
- where
- rnCmdTop' (HsCmdTop _ cmd)
- = do { (cmd', fvCmd) <- rnLCmd cmd
- ; let cmd_names = [arrAName, composeAName, firstAName] ++
- nameSetElemsStable (methodNamesCmd (unLoc cmd'))
- -- Generate the rebindable syntax for the monad
- ; (cmd_names', cmd_fvs) <- lookupSyntaxNames cmd_names
-
- ; return (HsCmdTop (cmd_names `zip` cmd_names') cmd',
- fvCmd `plusFV` cmd_fvs) }
- rnCmdTop' (XCmdTop nec) = noExtCon nec
-
-rnLCmd :: LHsCmd GhcPs -> RnM (LHsCmd GhcRn, FreeVars)
-rnLCmd = wrapLocFstM rnCmd
-
-rnCmd :: HsCmd GhcPs -> RnM (HsCmd GhcRn, FreeVars)
-
-rnCmd (HsCmdArrApp x arrow arg ho rtl)
- = do { (arrow',fvArrow) <- select_arrow_scope (rnLExpr arrow)
- ; (arg',fvArg) <- rnLExpr arg
- ; return (HsCmdArrApp x arrow' arg' ho rtl,
- fvArrow `plusFV` fvArg) }
- where
- select_arrow_scope tc = case ho of
- HsHigherOrderApp -> tc
- HsFirstOrderApp -> escapeArrowScope tc
- -- See Note [Escaping the arrow scope] in TcRnTypes
- -- Before renaming 'arrow', use the environment of the enclosing
- -- proc for the (-<) case.
- -- Local bindings, inside the enclosing proc, are not in scope
- -- inside 'arrow'. In the higher-order case (-<<), they are.
-
--- infix form
-rnCmd (HsCmdArrForm _ op _ (Just _) [arg1, arg2])
- = do { (op',fv_op) <- escapeArrowScope (rnLExpr op)
- ; let L _ (HsVar _ (L _ op_name)) = op'
- ; (arg1',fv_arg1) <- rnCmdTop arg1
- ; (arg2',fv_arg2) <- rnCmdTop arg2
- -- Deal with fixity
- ; fixity <- lookupFixityRn op_name
- ; final_e <- mkOpFormRn arg1' op' fixity arg2'
- ; return (final_e, fv_arg1 `plusFV` fv_op `plusFV` fv_arg2) }
-
-rnCmd (HsCmdArrForm x op f fixity cmds)
- = do { (op',fvOp) <- escapeArrowScope (rnLExpr op)
- ; (cmds',fvCmds) <- rnCmdArgs cmds
- ; return (HsCmdArrForm x op' f fixity cmds', fvOp `plusFV` fvCmds) }
-
-rnCmd (HsCmdApp x fun arg)
- = do { (fun',fvFun) <- rnLCmd fun
- ; (arg',fvArg) <- rnLExpr arg
- ; return (HsCmdApp x fun' arg', fvFun `plusFV` fvArg) }
-
-rnCmd (HsCmdLam x matches)
- = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLCmd matches
- ; return (HsCmdLam x matches', fvMatch) }
-
-rnCmd (HsCmdPar x e)
- = do { (e', fvs_e) <- rnLCmd e
- ; return (HsCmdPar x e', fvs_e) }
-
-rnCmd (HsCmdCase x expr matches)
- = do { (new_expr, e_fvs) <- rnLExpr expr
- ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches
- ; return (HsCmdCase x new_expr new_matches, e_fvs `plusFV` ms_fvs) }
-
-rnCmd (HsCmdIf x _ p b1 b2)
- = do { (p', fvP) <- rnLExpr p
- ; (b1', fvB1) <- rnLCmd b1
- ; (b2', fvB2) <- rnLCmd b2
- ; (mb_ite, fvITE) <- lookupIfThenElse
- ; return (HsCmdIf x mb_ite p' b1' b2', plusFVs [fvITE, fvP, fvB1, fvB2])}
-
-rnCmd (HsCmdLet x (L l binds) cmd)
- = rnLocalBindsAndThen binds $ \ binds' _ -> do
- { (cmd',fvExpr) <- rnLCmd cmd
- ; return (HsCmdLet x (L l binds') cmd', fvExpr) }
-
-rnCmd (HsCmdDo x (L l stmts))
- = do { ((stmts', _), fvs) <-
- rnStmts ArrowExpr rnLCmd stmts (\ _ -> return ((), emptyFVs))
- ; return ( HsCmdDo x (L l stmts'), fvs ) }
-
-rnCmd cmd@(HsCmdWrap {}) = pprPanic "rnCmd" (ppr cmd)
-rnCmd (XCmd nec) = noExtCon nec
-
----------------------------------------------------
-type CmdNeeds = FreeVars -- Only inhabitants are
- -- appAName, choiceAName, loopAName
-
--- find what methods the Cmd needs (loop, choice, apply)
-methodNamesLCmd :: LHsCmd GhcRn -> CmdNeeds
-methodNamesLCmd = methodNamesCmd . unLoc
-
-methodNamesCmd :: HsCmd GhcRn -> CmdNeeds
-
-methodNamesCmd (HsCmdArrApp _ _arrow _arg HsFirstOrderApp _rtl)
- = emptyFVs
-methodNamesCmd (HsCmdArrApp _ _arrow _arg HsHigherOrderApp _rtl)
- = unitFV appAName
-methodNamesCmd (HsCmdArrForm {}) = emptyFVs
-methodNamesCmd (HsCmdWrap _ _ cmd) = methodNamesCmd cmd
-
-methodNamesCmd (HsCmdPar _ c) = methodNamesLCmd c
-
-methodNamesCmd (HsCmdIf _ _ _ c1 c2)
- = methodNamesLCmd c1 `plusFV` methodNamesLCmd c2 `addOneFV` choiceAName
-
-methodNamesCmd (HsCmdLet _ _ c) = methodNamesLCmd c
-methodNamesCmd (HsCmdDo _ (L _ stmts)) = methodNamesStmts stmts
-methodNamesCmd (HsCmdApp _ c _) = methodNamesLCmd c
-methodNamesCmd (HsCmdLam _ match) = methodNamesMatch match
-
-methodNamesCmd (HsCmdCase _ _ matches)
- = methodNamesMatch matches `addOneFV` choiceAName
-
-methodNamesCmd (XCmd nec) = noExtCon nec
-
---methodNamesCmd _ = emptyFVs
- -- Other forms can't occur in commands, but it's not convenient
- -- to error here so we just do what's convenient.
- -- The type checker will complain later
-
----------------------------------------------------
-methodNamesMatch :: MatchGroup GhcRn (LHsCmd GhcRn) -> FreeVars
-methodNamesMatch (MG { mg_alts = L _ ms })
- = plusFVs (map do_one ms)
- where
- do_one (L _ (Match { m_grhss = grhss })) = methodNamesGRHSs grhss
- do_one (L _ (XMatch nec)) = noExtCon nec
-methodNamesMatch (XMatchGroup nec) = noExtCon nec
-
--------------------------------------------------
--- gaw 2004
-methodNamesGRHSs :: GRHSs GhcRn (LHsCmd GhcRn) -> FreeVars
-methodNamesGRHSs (GRHSs _ grhss _) = plusFVs (map methodNamesGRHS grhss)
-methodNamesGRHSs (XGRHSs nec) = noExtCon nec
-
--------------------------------------------------
-
-methodNamesGRHS :: Located (GRHS GhcRn (LHsCmd GhcRn)) -> CmdNeeds
-methodNamesGRHS (L _ (GRHS _ _ rhs)) = methodNamesLCmd rhs
-methodNamesGRHS (L _ (XGRHS nec)) = noExtCon nec
-
----------------------------------------------------
-methodNamesStmts :: [Located (StmtLR GhcRn GhcRn (LHsCmd GhcRn))] -> FreeVars
-methodNamesStmts stmts = plusFVs (map methodNamesLStmt stmts)
-
----------------------------------------------------
-methodNamesLStmt :: Located (StmtLR GhcRn GhcRn (LHsCmd GhcRn)) -> FreeVars
-methodNamesLStmt = methodNamesStmt . unLoc
-
-methodNamesStmt :: StmtLR GhcRn GhcRn (LHsCmd GhcRn) -> FreeVars
-methodNamesStmt (LastStmt _ cmd _ _) = methodNamesLCmd cmd
-methodNamesStmt (BodyStmt _ cmd _ _) = methodNamesLCmd cmd
-methodNamesStmt (BindStmt _ _ cmd _ _) = methodNamesLCmd cmd
-methodNamesStmt (RecStmt { recS_stmts = stmts }) =
- methodNamesStmts stmts `addOneFV` loopAName
-methodNamesStmt (LetStmt {}) = emptyFVs
-methodNamesStmt (ParStmt {}) = emptyFVs
-methodNamesStmt (TransStmt {}) = emptyFVs
-methodNamesStmt ApplicativeStmt{} = emptyFVs
- -- ParStmt and TransStmt can't occur in commands, but it's not
- -- convenient to error here so we just do what's convenient
-methodNamesStmt (XStmtLR nec) = noExtCon nec
-
-{-
-************************************************************************
-* *
- Arithmetic sequences
-* *
-************************************************************************
--}
-
-rnArithSeq :: ArithSeqInfo GhcPs -> RnM (ArithSeqInfo GhcRn, FreeVars)
-rnArithSeq (From expr)
- = do { (expr', fvExpr) <- rnLExpr expr
- ; return (From expr', fvExpr) }
-
-rnArithSeq (FromThen expr1 expr2)
- = do { (expr1', fvExpr1) <- rnLExpr expr1
- ; (expr2', fvExpr2) <- rnLExpr expr2
- ; return (FromThen expr1' expr2', fvExpr1 `plusFV` fvExpr2) }
-
-rnArithSeq (FromTo expr1 expr2)
- = do { (expr1', fvExpr1) <- rnLExpr expr1
- ; (expr2', fvExpr2) <- rnLExpr expr2
- ; return (FromTo expr1' expr2', fvExpr1 `plusFV` fvExpr2) }
-
-rnArithSeq (FromThenTo expr1 expr2 expr3)
- = do { (expr1', fvExpr1) <- rnLExpr expr1
- ; (expr2', fvExpr2) <- rnLExpr expr2
- ; (expr3', fvExpr3) <- rnLExpr expr3
- ; return (FromThenTo expr1' expr2' expr3',
- plusFVs [fvExpr1, fvExpr2, fvExpr3]) }
-
-{-
-************************************************************************
-* *
-\subsubsection{@Stmt@s: in @do@ expressions}
-* *
-************************************************************************
--}
-
-{-
-Note [Deterministic ApplicativeDo and RecursiveDo desugaring]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Both ApplicativeDo and RecursiveDo need to create tuples not
-present in the source text.
-
-For ApplicativeDo we create:
-
- (a,b,c) <- (\c b a -> (a,b,c)) <$>
-
-For RecursiveDo we create:
-
- mfix (\ ~(a,b,c) -> do ...; return (a',b',c'))
-
-The order of the components in those tuples needs to be stable
-across recompilations, otherwise they can get optimized differently
-and we end up with incompatible binaries.
-To get a stable order we use nameSetElemsStable.
-See Note [Deterministic UniqFM] to learn more about nondeterminism.
--}
-
--- | Rename some Stmts
-rnStmts :: Outputable (body GhcPs)
- => HsStmtContext Name
- -> (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -- ^ How to rename the body of each statement (e.g. rnLExpr)
- -> [LStmt GhcPs (Located (body GhcPs))]
- -- ^ Statements
- -> ([Name] -> RnM (thing, FreeVars))
- -- ^ if these statements scope over something, this renames it
- -- and returns the result.
- -> RnM (([LStmt GhcRn (Located (body GhcRn))], thing), FreeVars)
-rnStmts ctxt rnBody = rnStmtsWithPostProcessing ctxt rnBody noPostProcessStmts
-
--- | like 'rnStmts' but applies a post-processing step to the renamed Stmts
-rnStmtsWithPostProcessing
- :: Outputable (body GhcPs)
- => HsStmtContext Name
- -> (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -- ^ How to rename the body of each statement (e.g. rnLExpr)
- -> (HsStmtContext Name
- -> [(LStmt GhcRn (Located (body GhcRn)), FreeVars)]
- -> RnM ([LStmt GhcRn (Located (body GhcRn))], FreeVars))
- -- ^ postprocess the statements
- -> [LStmt GhcPs (Located (body GhcPs))]
- -- ^ Statements
- -> ([Name] -> RnM (thing, FreeVars))
- -- ^ if these statements scope over something, this renames it
- -- and returns the result.
- -> RnM (([LStmt GhcRn (Located (body GhcRn))], thing), FreeVars)
-rnStmtsWithPostProcessing ctxt rnBody ppStmts stmts thing_inside
- = do { ((stmts', thing), fvs) <-
- rnStmtsWithFreeVars ctxt rnBody stmts thing_inside
- ; (pp_stmts, fvs') <- ppStmts ctxt stmts'
- ; return ((pp_stmts, thing), fvs `plusFV` fvs')
- }
-
--- | maybe rearrange statements according to the ApplicativeDo transformation
-postProcessStmtsForApplicativeDo
- :: HsStmtContext Name
- -> [(ExprLStmt GhcRn, FreeVars)]
- -> RnM ([ExprLStmt GhcRn], FreeVars)
-postProcessStmtsForApplicativeDo ctxt stmts
- = do {
- -- rearrange the statements using ApplicativeStmt if
- -- -XApplicativeDo is on. Also strip out the FreeVars attached
- -- to each Stmt body.
- ado_is_on <- xoptM LangExt.ApplicativeDo
- ; let is_do_expr | DoExpr <- ctxt = True
- | otherwise = False
- -- don't apply the transformation inside TH brackets, because
- -- DsMeta does not handle ApplicativeDo.
- ; in_th_bracket <- isBrackStage <$> getStage
- ; if ado_is_on && is_do_expr && not in_th_bracket
- then do { traceRn "ppsfa" (ppr stmts)
- ; rearrangeForApplicativeDo ctxt stmts }
- else noPostProcessStmts ctxt stmts }
-
--- | strip the FreeVars annotations from statements
-noPostProcessStmts
- :: HsStmtContext Name
- -> [(LStmt GhcRn (Located (body GhcRn)), FreeVars)]
- -> RnM ([LStmt GhcRn (Located (body GhcRn))], FreeVars)
-noPostProcessStmts _ stmts = return (map fst stmts, emptyNameSet)
-
-
-rnStmtsWithFreeVars :: Outputable (body GhcPs)
- => HsStmtContext Name
- -> (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -> [LStmt GhcPs (Located (body GhcPs))]
- -> ([Name] -> RnM (thing, FreeVars))
- -> RnM ( ([(LStmt GhcRn (Located (body GhcRn)), FreeVars)], thing)
- , FreeVars)
--- Each Stmt body is annotated with its FreeVars, so that
--- we can rearrange statements for ApplicativeDo.
---
--- Variables bound by the Stmts, and mentioned in thing_inside,
--- do not appear in the result FreeVars
-
-rnStmtsWithFreeVars ctxt _ [] thing_inside
- = do { checkEmptyStmts ctxt
- ; (thing, fvs) <- thing_inside []
- ; return (([], thing), fvs) }
-
-rnStmtsWithFreeVars MDoExpr rnBody stmts thing_inside -- Deal with mdo
- = -- Behave like do { rec { ...all but last... }; last }
- do { ((stmts1, (stmts2, thing)), fvs)
- <- rnStmt MDoExpr rnBody (noLoc $ mkRecStmt all_but_last) $ \ _ ->
- do { last_stmt' <- checkLastStmt MDoExpr last_stmt
- ; rnStmt MDoExpr rnBody last_stmt' thing_inside }
- ; return (((stmts1 ++ stmts2), thing), fvs) }
- where
- Just (all_but_last, last_stmt) = snocView stmts
-
-rnStmtsWithFreeVars ctxt rnBody (lstmt@(L loc _) : lstmts) thing_inside
- | null lstmts
- = setSrcSpan loc $
- do { lstmt' <- checkLastStmt ctxt lstmt
- ; rnStmt ctxt rnBody lstmt' thing_inside }
-
- | otherwise
- = do { ((stmts1, (stmts2, thing)), fvs)
- <- setSrcSpan loc $
- do { checkStmt ctxt lstmt
- ; rnStmt ctxt rnBody lstmt $ \ bndrs1 ->
- rnStmtsWithFreeVars ctxt rnBody lstmts $ \ bndrs2 ->
- thing_inside (bndrs1 ++ bndrs2) }
- ; return (((stmts1 ++ stmts2), thing), fvs) }
-
-----------------------
-
-{-
-Note [Failing pattern matches in Stmts]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Many things desugar to HsStmts including monadic things like `do` and `mdo`
-statements, pattern guards, and list comprehensions (see 'HsStmtContext' for an
-exhaustive list). How we deal with pattern match failure is context-dependent.
-
- * In the case of list comprehensions and pattern guards we don't need any 'fail'
- function; the desugarer ignores the fail function field of 'BindStmt' entirely.
- * In the case of monadic contexts (e.g. monad comprehensions, do, and mdo
- expressions) we want pattern match failure to be desugared to the appropriate
- 'fail' function (either that of Monad or MonadFail, depending on whether
- -XMonadFailDesugaring is enabled.)
-
-At one point we failed to make this distinction, leading to #11216.
--}
-
-rnStmt :: Outputable (body GhcPs)
- => HsStmtContext Name
- -> (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -- ^ How to rename the body of the statement
- -> LStmt GhcPs (Located (body GhcPs))
- -- ^ The statement
- -> ([Name] -> RnM (thing, FreeVars))
- -- ^ Rename the stuff that this statement scopes over
- -> RnM ( ([(LStmt GhcRn (Located (body GhcRn)), FreeVars)], thing)
- , FreeVars)
--- Variables bound by the Stmt, and mentioned in thing_inside,
--- do not appear in the result FreeVars
-
-rnStmt ctxt rnBody (L loc (LastStmt _ body noret _)) thing_inside
- = do { (body', fv_expr) <- rnBody body
- ; (ret_op, fvs1) <- if isMonadCompContext ctxt
- then lookupStmtName ctxt returnMName
- else return (noSyntaxExpr, emptyFVs)
- -- The 'return' in a LastStmt is used only
- -- for MonadComp; and we don't want to report
- -- "non in scope: return" in other cases
- -- #15607
-
- ; (thing, fvs3) <- thing_inside []
- ; return (([(L loc (LastStmt noExtField body' noret ret_op), fv_expr)]
- , thing), fv_expr `plusFV` fvs1 `plusFV` fvs3) }
-
-rnStmt ctxt rnBody (L loc (BodyStmt _ body _ _)) thing_inside
- = do { (body', fv_expr) <- rnBody body
- ; (then_op, fvs1) <- lookupStmtName ctxt thenMName
-
- ; (guard_op, fvs2) <- if isComprehensionContext ctxt
- then lookupStmtName ctxt guardMName
- else return (noSyntaxExpr, emptyFVs)
- -- Only list/monad comprehensions use 'guard'
- -- Also for sub-stmts of same eg [ e | x<-xs, gd | blah ]
- -- Here "gd" is a guard
-
- ; (thing, fvs3) <- thing_inside []
- ; return ( ([(L loc (BodyStmt noExtField body' then_op guard_op), fv_expr)]
- , thing), fv_expr `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) }
-
-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) <- monadFailOp pat ctxt
-
- ; rnPat (StmtCtxt ctxt) pat $ \ pat' -> do
- { (thing, fvs3) <- thing_inside (collectPatBinders pat')
- ; return (( [( L loc (BindStmt noExtField pat' body' bind_op fail_op)
- , fv_expr )]
- , thing),
- fv_expr `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) }}
- -- fv_expr shouldn't really be filtered by the rnPatsAndThen
- -- but it does not matter because the names are unique
-
-rnStmt _ _ (L loc (LetStmt _ (L l binds))) thing_inside
- = do { rnLocalBindsAndThen binds $ \binds' bind_fvs -> do
- { (thing, fvs) <- thing_inside (collectLocalBinders binds')
- ; return ( ([(L loc (LetStmt noExtField (L l binds')), bind_fvs)], thing)
- , fvs) } }
-
-rnStmt ctxt rnBody (L loc (RecStmt { recS_stmts = rec_stmts })) thing_inside
- = do { (return_op, fvs1) <- lookupStmtName ctxt returnMName
- ; (mfix_op, fvs2) <- lookupStmtName ctxt mfixName
- ; (bind_op, fvs3) <- lookupStmtName ctxt bindMName
- ; let empty_rec_stmt = emptyRecStmtName { recS_ret_fn = return_op
- , recS_mfix_fn = mfix_op
- , recS_bind_fn = bind_op }
-
- -- Step1: Bring all the binders of the mdo into scope
- -- (Remember that this also removes the binders from the
- -- finally-returned free-vars.)
- -- And rename each individual stmt, making a
- -- singleton segment. At this stage the FwdRefs field
- -- isn't finished: it's empty for all except a BindStmt
- -- for which it's the fwd refs within the bind itself
- -- (This set may not be empty, because we're in a recursive
- -- context.)
- ; rnRecStmtsAndThen rnBody rec_stmts $ \ segs -> do
- { let bndrs = nameSetElemsStable $
- foldr (unionNameSet . (\(ds,_,_,_) -> ds))
- emptyNameSet
- segs
- -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]
- ; (thing, fvs_later) <- thing_inside bndrs
- ; let (rec_stmts', fvs) = segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later
- -- We aren't going to try to group RecStmts with
- -- ApplicativeDo, so attaching empty FVs is fine.
- ; return ( ((zip rec_stmts' (repeat emptyNameSet)), thing)
- , fvs `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) } }
-
-rnStmt ctxt _ (L loc (ParStmt _ segs _ _)) thing_inside
- = do { (mzip_op, fvs1) <- lookupStmtNamePoly ctxt mzipName
- ; (bind_op, fvs2) <- lookupStmtName ctxt bindMName
- ; (return_op, fvs3) <- lookupStmtName ctxt returnMName
- ; ((segs', thing), fvs4) <- rnParallelStmts (ParStmtCtxt ctxt) return_op segs thing_inside
- ; return (([(L loc (ParStmt noExtField segs' mzip_op bind_op), fvs4)], thing)
- , fvs1 `plusFV` fvs2 `plusFV` fvs3 `plusFV` fvs4) }
-
-rnStmt ctxt _ (L loc (TransStmt { trS_stmts = stmts, trS_by = by, trS_form = form
- , trS_using = using })) thing_inside
- = do { -- Rename the 'using' expression in the context before the transform is begun
- (using', fvs1) <- rnLExpr using
-
- -- Rename the stmts and the 'by' expression
- -- Keep track of the variables mentioned in the 'by' expression
- ; ((stmts', (by', used_bndrs, thing)), fvs2)
- <- rnStmts (TransStmtCtxt ctxt) rnLExpr stmts $ \ bndrs ->
- do { (by', fvs_by) <- mapMaybeFvRn rnLExpr by
- ; (thing, fvs_thing) <- thing_inside bndrs
- ; let fvs = fvs_by `plusFV` fvs_thing
- used_bndrs = filter (`elemNameSet` fvs) bndrs
- -- The paper (Fig 5) has a bug here; we must treat any free variable
- -- of the "thing inside", **or of the by-expression**, as used
- ; return ((by', used_bndrs, thing), fvs) }
-
- -- Lookup `return`, `(>>=)` and `liftM` for monad comprehensions
- ; (return_op, fvs3) <- lookupStmtName ctxt returnMName
- ; (bind_op, fvs4) <- lookupStmtName ctxt bindMName
- ; (fmap_op, fvs5) <- case form of
- ThenForm -> return (noExpr, emptyFVs)
- _ -> lookupStmtNamePoly ctxt fmapName
-
- ; let all_fvs = fvs1 `plusFV` fvs2 `plusFV` fvs3
- `plusFV` fvs4 `plusFV` fvs5
- bndr_map = used_bndrs `zip` used_bndrs
- -- See Note [TransStmt binder map] in GHC.Hs.Expr
-
- ; traceRn "rnStmt: implicitly rebound these used binders:" (ppr bndr_map)
- ; return (([(L loc (TransStmt { trS_ext = noExtField
- , trS_stmts = stmts', trS_bndrs = bndr_map
- , trS_by = by', trS_using = using', trS_form = form
- , trS_ret = return_op, trS_bind = bind_op
- , trS_fmap = fmap_op }), fvs2)], thing), all_fvs) }
-
-rnStmt _ _ (L _ ApplicativeStmt{}) _ =
- panic "rnStmt: ApplicativeStmt"
-
-rnStmt _ _ (L _ (XStmtLR nec)) _ =
- noExtCon nec
-
-rnParallelStmts :: forall thing. HsStmtContext Name
- -> SyntaxExpr GhcRn
- -> [ParStmtBlock GhcPs GhcPs]
- -> ([Name] -> RnM (thing, FreeVars))
- -> RnM (([ParStmtBlock GhcRn GhcRn], thing), FreeVars)
--- Note [Renaming parallel Stmts]
-rnParallelStmts ctxt return_op segs thing_inside
- = do { orig_lcl_env <- getLocalRdrEnv
- ; rn_segs orig_lcl_env [] segs }
- where
- rn_segs :: LocalRdrEnv
- -> [Name] -> [ParStmtBlock GhcPs GhcPs]
- -> RnM (([ParStmtBlock GhcRn GhcRn], thing), FreeVars)
- rn_segs _ bndrs_so_far []
- = do { let (bndrs', dups) = removeDups cmpByOcc bndrs_so_far
- ; mapM_ dupErr dups
- ; (thing, fvs) <- bindLocalNames bndrs' (thing_inside bndrs')
- ; return (([], thing), fvs) }
-
- rn_segs env bndrs_so_far (ParStmtBlock x stmts _ _ : segs)
- = do { ((stmts', (used_bndrs, segs', thing)), fvs)
- <- rnStmts ctxt rnLExpr stmts $ \ bndrs ->
- setLocalRdrEnv env $ do
- { ((segs', thing), fvs) <- rn_segs env (bndrs ++ bndrs_so_far) segs
- ; let used_bndrs = filter (`elemNameSet` fvs) bndrs
- ; return ((used_bndrs, segs', thing), fvs) }
-
- ; let seg' = ParStmtBlock x stmts' used_bndrs return_op
- ; return ((seg':segs', thing), fvs) }
- rn_segs _ _ (XParStmtBlock nec:_) = noExtCon nec
-
- cmpByOcc n1 n2 = nameOccName n1 `compare` nameOccName n2
- dupErr vs = addErr (text "Duplicate binding in parallel list comprehension for:"
- <+> quotes (ppr (NE.head vs)))
-
-lookupStmtName :: HsStmtContext Name -> Name -> RnM (SyntaxExpr GhcRn, FreeVars)
--- Like lookupSyntaxName, but respects contexts
-lookupStmtName ctxt n
- | rebindableContext ctxt
- = lookupSyntaxName n
- | otherwise
- = return (mkRnSyntaxExpr n, emptyFVs)
-
-lookupStmtNamePoly :: HsStmtContext Name -> Name -> RnM (HsExpr GhcRn, FreeVars)
-lookupStmtNamePoly ctxt name
- | rebindableContext ctxt
- = do { rebindable_on <- xoptM LangExt.RebindableSyntax
- ; if rebindable_on
- then do { fm <- lookupOccRn (nameRdrName name)
- ; return (HsVar noExtField (noLoc fm), unitFV fm) }
- else not_rebindable }
- | otherwise
- = not_rebindable
- where
- not_rebindable = return (HsVar noExtField (noLoc name), emptyFVs)
-
--- | Is this a context where we respect RebindableSyntax?
--- but ListComp are never rebindable
--- Neither is ArrowExpr, which has its own desugarer in DsArrows
-rebindableContext :: HsStmtContext Name -> Bool
-rebindableContext ctxt = case ctxt of
- ListComp -> False
- ArrowExpr -> False
- PatGuard {} -> False
-
- DoExpr -> True
- MDoExpr -> True
- MonadComp -> True
- GhciStmtCtxt -> True -- I suppose?
-
- ParStmtCtxt c -> rebindableContext c -- Look inside to
- TransStmtCtxt c -> rebindableContext c -- the parent context
-
-{-
-Note [Renaming parallel Stmts]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Renaming parallel statements is painful. Given, say
- [ a+c | a <- as, bs <- bss
- | c <- bs, a <- ds ]
-Note that
- (a) In order to report "Defined but not used" about 'bs', we must
- rename each group of Stmts with a thing_inside whose FreeVars
- include at least {a,c}
-
- (b) We want to report that 'a' is illegally bound in both branches
-
- (c) The 'bs' in the second group must obviously not be captured by
- the binding in the first group
-
-To satisfy (a) we nest the segements.
-To satisfy (b) we check for duplicates just before thing_inside.
-To satisfy (c) we reset the LocalRdrEnv each time.
-
-************************************************************************
-* *
-\subsubsection{mdo expressions}
-* *
-************************************************************************
--}
-
-type FwdRefs = NameSet
-type Segment stmts = (Defs,
- Uses, -- May include defs
- FwdRefs, -- A subset of uses that are
- -- (a) used before they are bound in this segment, or
- -- (b) used here, and bound in subsequent segments
- stmts) -- Either Stmt or [Stmt]
-
-
--- wrapper that does both the left- and right-hand sides
-rnRecStmtsAndThen :: Outputable (body GhcPs) =>
- (Located (body GhcPs)
- -> RnM (Located (body GhcRn), FreeVars))
- -> [LStmt GhcPs (Located (body GhcPs))]
- -- assumes that the FreeVars returned includes
- -- the FreeVars of the Segments
- -> ([Segment (LStmt GhcRn (Located (body GhcRn)))]
- -> RnM (a, FreeVars))
- -> RnM (a, FreeVars)
-rnRecStmtsAndThen rnBody s cont
- = do { -- (A) Make the mini fixity env for all of the stmts
- fix_env <- makeMiniFixityEnv (collectRecStmtsFixities s)
-
- -- (B) Do the LHSes
- ; new_lhs_and_fv <- rn_rec_stmts_lhs fix_env s
-
- -- ...bring them and their fixities into scope
- ; let bound_names = collectLStmtsBinders (map fst new_lhs_and_fv)
- -- Fake uses of variables introduced implicitly (warning suppression, see #4404)
- rec_uses = lStmtsImplicits (map fst new_lhs_and_fv)
- implicit_uses = mkNameSet $ concatMap snd $ rec_uses
- ; bindLocalNamesFV bound_names $
- addLocalFixities fix_env bound_names $ do
-
- -- (C) do the right-hand-sides and thing-inside
- { segs <- rn_rec_stmts rnBody bound_names new_lhs_and_fv
- ; (res, fvs) <- cont segs
- ; mapM_ (\(loc, ns) -> checkUnusedRecordWildcard loc fvs (Just ns))
- rec_uses
- ; warnUnusedLocalBinds bound_names (fvs `unionNameSet` implicit_uses)
- ; return (res, fvs) }}
-
--- get all the fixity decls in any Let stmt
-collectRecStmtsFixities :: [LStmtLR GhcPs GhcPs body] -> [LFixitySig GhcPs]
-collectRecStmtsFixities l =
- foldr (\ s -> \acc -> case s of
- (L _ (LetStmt _ (L _ (HsValBinds _ (ValBinds _ _ sigs))))) ->
- foldr (\ sig -> \ acc -> case sig of
- (L loc (FixSig _ s)) -> (L loc s) : acc
- _ -> acc) acc sigs
- _ -> acc) [] l
-
--- left-hand sides
-
-rn_rec_stmt_lhs :: Outputable body => MiniFixityEnv
- -> LStmt GhcPs body
- -- rename LHS, and return its FVs
- -- Warning: we will only need the FreeVars below in the case of a BindStmt,
- -- so we don't bother to compute it accurately in the other cases
- -> RnM [(LStmtLR GhcRn GhcPs body, FreeVars)]
-
-rn_rec_stmt_lhs _ (L loc (BodyStmt _ body a b))
- = return [(L loc (BodyStmt noExtField body a b), emptyFVs)]
-
-rn_rec_stmt_lhs _ (L loc (LastStmt _ body noret a))
- = return [(L loc (LastStmt noExtField body noret a), emptyFVs)]
-
-rn_rec_stmt_lhs fix_env (L loc (BindStmt _ pat body a b))
- = do
- -- should the ctxt be MDo instead?
- (pat', fv_pat) <- rnBindPat (localRecNameMaker fix_env) pat
- return [(L loc (BindStmt noExtField pat' body a b), fv_pat)]
-
-rn_rec_stmt_lhs _ (L _ (LetStmt _ (L _ binds@(HsIPBinds {}))))
- = failWith (badIpBinds (text "an mdo expression") binds)
-
-rn_rec_stmt_lhs fix_env (L loc (LetStmt _ (L l (HsValBinds x binds))))
- = do (_bound_names, binds') <- rnLocalValBindsLHS fix_env binds
- return [(L loc (LetStmt noExtField (L l (HsValBinds x binds'))),
- -- Warning: this is bogus; see function invariant
- emptyFVs
- )]
-
--- XXX Do we need to do something with the return and mfix names?
-rn_rec_stmt_lhs fix_env (L _ (RecStmt { recS_stmts = stmts })) -- Flatten Rec inside Rec
- = rn_rec_stmts_lhs fix_env stmts
-
-rn_rec_stmt_lhs _ stmt@(L _ (ParStmt {})) -- Syntactically illegal in mdo
- = pprPanic "rn_rec_stmt" (ppr stmt)
-
-rn_rec_stmt_lhs _ stmt@(L _ (TransStmt {})) -- Syntactically illegal in mdo
- = pprPanic "rn_rec_stmt" (ppr stmt)
-
-rn_rec_stmt_lhs _ stmt@(L _ (ApplicativeStmt {})) -- Shouldn't appear yet
- = pprPanic "rn_rec_stmt" (ppr stmt)
-
-rn_rec_stmt_lhs _ (L _ (LetStmt _ (L _ (EmptyLocalBinds _))))
- = panic "rn_rec_stmt LetStmt EmptyLocalBinds"
-rn_rec_stmt_lhs _ (L _ (LetStmt _ (L _ (XHsLocalBindsLR nec))))
- = noExtCon nec
-rn_rec_stmt_lhs _ (L _ (XStmtLR nec))
- = noExtCon nec
-
-rn_rec_stmts_lhs :: Outputable body => MiniFixityEnv
- -> [LStmt GhcPs body]
- -> RnM [(LStmtLR GhcRn GhcPs body, FreeVars)]
-rn_rec_stmts_lhs fix_env stmts
- = do { ls <- concatMapM (rn_rec_stmt_lhs fix_env) stmts
- ; let boundNames = collectLStmtsBinders (map fst ls)
- -- First do error checking: we need to check for dups here because we
- -- don't bind all of the variables from the Stmt at once
- -- with bindLocatedLocals.
- ; checkDupNames boundNames
- ; return ls }
-
-
--- right-hand-sides
-
-rn_rec_stmt :: (Outputable (body GhcPs)) =>
- (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -> [Name]
- -> (LStmtLR GhcRn GhcPs (Located (body GhcPs)), FreeVars)
- -> RnM [Segment (LStmt GhcRn (Located (body GhcRn)))]
- -- Rename a Stmt that is inside a RecStmt (or mdo)
- -- Assumes all binders are already in scope
- -- Turns each stmt into a singleton Stmt
-rn_rec_stmt rnBody _ (L loc (LastStmt _ body noret _), _)
- = do { (body', fv_expr) <- rnBody body
- ; (ret_op, fvs1) <- lookupSyntaxName returnMName
- ; return [(emptyNameSet, fv_expr `plusFV` fvs1, emptyNameSet,
- L loc (LastStmt noExtField body' noret ret_op))] }
-
-rn_rec_stmt rnBody _ (L loc (BodyStmt _ body _ _), _)
- = do { (body', fvs) <- rnBody body
- ; (then_op, fvs1) <- lookupSyntaxName thenMName
- ; return [(emptyNameSet, fvs `plusFV` fvs1, emptyNameSet,
- L loc (BodyStmt noExtField body' then_op noSyntaxExpr))] }
-
-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) <- getMonadFailOp
-
- ; let bndrs = mkNameSet (collectPatBinders pat')
- fvs = fv_expr `plusFV` fv_pat `plusFV` fvs1 `plusFV` fvs2
- ; return [(bndrs, fvs, bndrs `intersectNameSet` fvs,
- L loc (BindStmt noExtField pat' body' bind_op fail_op))] }
-
-rn_rec_stmt _ _ (L _ (LetStmt _ (L _ binds@(HsIPBinds {}))), _)
- = failWith (badIpBinds (text "an mdo expression") binds)
-
-rn_rec_stmt _ all_bndrs (L loc (LetStmt _ (L l (HsValBinds x binds'))), _)
- = do { (binds', du_binds) <- rnLocalValBindsRHS (mkNameSet all_bndrs) binds'
- -- fixities and unused are handled above in rnRecStmtsAndThen
- ; let fvs = allUses du_binds
- ; return [(duDefs du_binds, fvs, emptyNameSet,
- L loc (LetStmt noExtField (L l (HsValBinds x binds'))))] }
-
--- no RecStmt case because they get flattened above when doing the LHSes
-rn_rec_stmt _ _ stmt@(L _ (RecStmt {}), _)
- = pprPanic "rn_rec_stmt: RecStmt" (ppr stmt)
-
-rn_rec_stmt _ _ stmt@(L _ (ParStmt {}), _) -- Syntactically illegal in mdo
- = pprPanic "rn_rec_stmt: ParStmt" (ppr stmt)
-
-rn_rec_stmt _ _ stmt@(L _ (TransStmt {}), _) -- Syntactically illegal in mdo
- = pprPanic "rn_rec_stmt: TransStmt" (ppr stmt)
-
-rn_rec_stmt _ _ (L _ (LetStmt _ (L _ (XHsLocalBindsLR nec))), _)
- = noExtCon nec
-
-rn_rec_stmt _ _ (L _ (LetStmt _ (L _ (EmptyLocalBinds _))), _)
- = panic "rn_rec_stmt: LetStmt EmptyLocalBinds"
-
-rn_rec_stmt _ _ stmt@(L _ (ApplicativeStmt {}), _)
- = pprPanic "rn_rec_stmt: ApplicativeStmt" (ppr stmt)
-
-rn_rec_stmt _ _ (L _ (XStmtLR nec), _)
- = noExtCon nec
-
-rn_rec_stmts :: Outputable (body GhcPs) =>
- (Located (body GhcPs) -> RnM (Located (body GhcRn), FreeVars))
- -> [Name]
- -> [(LStmtLR GhcRn GhcPs (Located (body GhcPs)), FreeVars)]
- -> RnM [Segment (LStmt GhcRn (Located (body GhcRn)))]
-rn_rec_stmts rnBody bndrs stmts
- = do { segs_s <- mapM (rn_rec_stmt rnBody bndrs) stmts
- ; return (concat segs_s) }
-
----------------------------------------------
-segmentRecStmts :: SrcSpan -> HsStmtContext Name
- -> Stmt GhcRn body
- -> [Segment (LStmt GhcRn body)] -> FreeVars
- -> ([LStmt GhcRn body], FreeVars)
-
-segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later
- | null segs
- = ([], fvs_later)
-
- | MDoExpr <- ctxt
- = segsToStmts empty_rec_stmt grouped_segs fvs_later
- -- Step 4: Turn the segments into Stmts
- -- Use RecStmt when and only when there are fwd refs
- -- Also gather up the uses from the end towards the
- -- start, so we can tell the RecStmt which things are
- -- used 'after' the RecStmt
-
- | otherwise
- = ([ L loc $
- empty_rec_stmt { recS_stmts = ss
- , recS_later_ids = nameSetElemsStable
- (defs `intersectNameSet` fvs_later)
- , recS_rec_ids = nameSetElemsStable
- (defs `intersectNameSet` uses) }]
- -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]
- , uses `plusFV` fvs_later)
-
- where
- (defs_s, uses_s, _, ss) = unzip4 segs
- defs = plusFVs defs_s
- uses = plusFVs uses_s
-
- -- Step 2: Fill in the fwd refs.
- -- The segments are all singletons, but their fwd-ref
- -- field mentions all the things used by the segment
- -- that are bound after their use
- segs_w_fwd_refs = addFwdRefs segs
-
- -- Step 3: Group together the segments to make bigger segments
- -- Invariant: in the result, no segment uses a variable
- -- bound in a later segment
- grouped_segs = glomSegments ctxt segs_w_fwd_refs
-
-----------------------------
-addFwdRefs :: [Segment a] -> [Segment a]
--- So far the segments only have forward refs *within* the Stmt
--- (which happens for bind: x <- ...x...)
--- This function adds the cross-seg fwd ref info
-
-addFwdRefs segs
- = fst (foldr mk_seg ([], emptyNameSet) segs)
- where
- mk_seg (defs, uses, fwds, stmts) (segs, later_defs)
- = (new_seg : segs, all_defs)
- where
- new_seg = (defs, uses, new_fwds, stmts)
- all_defs = later_defs `unionNameSet` defs
- new_fwds = fwds `unionNameSet` (uses `intersectNameSet` later_defs)
- -- Add the downstream fwd refs here
-
-{-
-Note [Segmenting mdo]
-~~~~~~~~~~~~~~~~~~~~~
-NB. June 7 2012: We only glom segments that appear in an explicit mdo;
-and leave those found in "do rec"'s intact. See
-https://gitlab.haskell.org/ghc/ghc/issues/4148 for the discussion
-leading to this design choice. Hence the test in segmentRecStmts.
-
-Note [Glomming segments]
-~~~~~~~~~~~~~~~~~~~~~~~~
-Glomming the singleton segments of an mdo into minimal recursive groups.
-
-At first I thought this was just strongly connected components, but
-there's an important constraint: the order of the stmts must not change.
-
-Consider
- mdo { x <- ...y...
- p <- z
- y <- ...x...
- q <- x
- z <- y
- r <- x }
-
-Here, the first stmt mention 'y', which is bound in the third.
-But that means that the innocent second stmt (p <- z) gets caught
-up in the recursion. And that in turn means that the binding for
-'z' has to be included... and so on.
-
-Start at the tail { r <- x }
-Now add the next one { z <- y ; r <- x }
-Now add one more { q <- x ; z <- y ; r <- x }
-Now one more... but this time we have to group a bunch into rec
- { rec { y <- ...x... ; q <- x ; z <- y } ; r <- x }
-Now one more, which we can add on without a rec
- { p <- z ;
- rec { y <- ...x... ; q <- x ; z <- y } ;
- r <- x }
-Finally we add the last one; since it mentions y we have to
-glom it together with the first two groups
- { rec { x <- ...y...; p <- z ; y <- ...x... ;
- q <- x ; z <- y } ;
- r <- x }
--}
-
-glomSegments :: HsStmtContext Name
- -> [Segment (LStmt GhcRn body)]
- -> [Segment [LStmt GhcRn body]]
- -- Each segment has a non-empty list of Stmts
--- See Note [Glomming segments]
-
-glomSegments _ [] = []
-glomSegments ctxt ((defs,uses,fwds,stmt) : segs)
- -- Actually stmts will always be a singleton
- = (seg_defs, seg_uses, seg_fwds, seg_stmts) : others
- where
- segs' = glomSegments ctxt segs
- (extras, others) = grab uses segs'
- (ds, us, fs, ss) = unzip4 extras
-
- seg_defs = plusFVs ds `plusFV` defs
- seg_uses = plusFVs us `plusFV` uses
- seg_fwds = plusFVs fs `plusFV` fwds
- seg_stmts = stmt : concat ss
-
- grab :: NameSet -- The client
- -> [Segment a]
- -> ([Segment a], -- Needed by the 'client'
- [Segment a]) -- Not needed by the client
- -- The result is simply a split of the input
- grab uses dus
- = (reverse yeses, reverse noes)
- where
- (noes, yeses) = span not_needed (reverse dus)
- not_needed (defs,_,_,_) = not (intersectsNameSet defs uses)
-
-----------------------------------------------------
-segsToStmts :: Stmt GhcRn body
- -- A RecStmt with the SyntaxOps filled in
- -> [Segment [LStmt GhcRn body]]
- -- Each Segment has a non-empty list of Stmts
- -> FreeVars -- Free vars used 'later'
- -> ([LStmt GhcRn body], FreeVars)
-
-segsToStmts _ [] fvs_later = ([], fvs_later)
-segsToStmts empty_rec_stmt ((defs, uses, fwds, ss) : segs) fvs_later
- = ASSERT( not (null ss) )
- (new_stmt : later_stmts, later_uses `plusFV` uses)
- where
- (later_stmts, later_uses) = segsToStmts empty_rec_stmt segs fvs_later
- new_stmt | non_rec = head ss
- | otherwise = L (getLoc (head ss)) rec_stmt
- rec_stmt = empty_rec_stmt { recS_stmts = ss
- , recS_later_ids = nameSetElemsStable used_later
- , recS_rec_ids = nameSetElemsStable fwds }
- -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]
- non_rec = isSingleton ss && isEmptyNameSet fwds
- used_later = defs `intersectNameSet` later_uses
- -- The ones needed after the RecStmt
-
-{-
-************************************************************************
-* *
-ApplicativeDo
-* *
-************************************************************************
-
-Note [ApplicativeDo]
-
-= Example =
-
-For a sequence of statements
-
- do
- x <- A
- y <- B x
- z <- C
- return (f x y z)
-
-We want to transform this to
-
- (\(x,y) z -> f x y z) <$> (do x <- A; y <- B x; return (x,y)) <*> C
-
-It would be easy to notice that "y <- B x" and "z <- C" are
-independent and do something like this:
-
- do
- x <- A
- (y,z) <- (,) <$> B x <*> C
- return (f x y z)
-
-But this isn't enough! A and C were also independent, and this
-transformation loses the ability to do A and C in parallel.
-
-The algorithm works by first splitting the sequence of statements into
-independent "segments", and a separate "tail" (the final statement). In
-our example above, the segements would be
-
- [ x <- A
- , y <- B x ]
-
- [ z <- C ]
-
-and the tail is:
-
- return (f x y z)
-
-Then we take these segments and make an Applicative expression from them:
-
- (\(x,y) z -> return (f x y z))
- <$> do { x <- A; y <- B x; return (x,y) }
- <*> C
-
-Finally, we recursively apply the transformation to each segment, to
-discover any nested parallelism.
-
-= Syntax & spec =
-
- expr ::= ... | do {stmt_1; ..; stmt_n} expr | ...
-
- stmt ::= pat <- expr
- | (arg_1 | ... | arg_n) -- applicative composition, n>=1
- | ... -- other kinds of statement (e.g. let)
-
- arg ::= pat <- expr
- | {stmt_1; ..; stmt_n} {var_1..var_n}
-
-(note that in the actual implementation,the expr in a do statement is
-represented by a LastStmt as the final stmt, this is just a
-representational issue and may change later.)
-
-== Transformation to introduce applicative stmts ==
-
-ado {} tail = tail
-ado {pat <- expr} {return expr'} = (mkArg(pat <- expr)); return expr'
-ado {one} tail = one : tail
-ado stmts tail
- | n == 1 = ado before (ado after tail)
- where (before,after) = split(stmts_1)
- | n > 1 = (mkArg(stmts_1) | ... | mkArg(stmts_n)); tail
- where
- {stmts_1 .. stmts_n} = segments(stmts)
-
-segments(stmts) =
- -- divide stmts into segments with no interdependencies
-
-mkArg({pat <- expr}) = (pat <- expr)
-mkArg({stmt_1; ...; stmt_n}) =
- {stmt_1; ...; stmt_n} {vars(stmt_1) u .. u vars(stmt_n)}
-
-split({stmt_1; ..; stmt_n) =
- ({stmt_1; ..; stmt_i}, {stmt_i+1; ..; stmt_n})
- -- 1 <= i <= n
- -- i is a good place to insert a bind
-
-== Desugaring for do ==
-
-dsDo {} expr = expr
-
-dsDo {pat <- rhs; stmts} expr =
- rhs >>= \pat -> dsDo stmts expr
-
-dsDo {(arg_1 | ... | arg_n)} (return expr) =
- (\argpat (arg_1) .. argpat(arg_n) -> expr)
- <$> argexpr(arg_1)
- <*> ...
- <*> argexpr(arg_n)
-
-dsDo {(arg_1 | ... | arg_n); stmts} expr =
- join (\argpat (arg_1) .. argpat(arg_n) -> dsDo stmts expr)
- <$> argexpr(arg_1)
- <*> ...
- <*> argexpr(arg_n)
-
-= Relevant modules in the rest of the compiler =
-
-ApplicativeDo touches a few phases in the compiler:
-
-* Renamer: The journey begins here in the renamer, where do-blocks are
- scheduled as outlined above and transformed into applicative
- combinators. However, the code is still represented as a do-block
- with special forms of applicative statements. This allows us to
- recover the original do-block when e.g. printing type errors, where
- we don't want to show any of the applicative combinators since they
- don't exist in the source code.
- See ApplicativeStmt and ApplicativeArg in HsExpr.
-
-* Typechecker: ApplicativeDo passes through the typechecker much like any
- other form of expression. The only crux is that the typechecker has to
- be aware of the special ApplicativeDo statements in the do-notation, and
- typecheck them appropriately.
- Relevant module: TcMatches
-
-* Desugarer: Any do-block which contains applicative statements is desugared
- as outlined above, to use the Applicative combinators.
- Relevant module: DsExpr
-
--}
-
--- | The 'Name's of @return@ and @pure@. These may not be 'returnName' and
--- 'pureName' due to @RebindableSyntax@.
-data MonadNames = MonadNames { return_name, pure_name :: Name }
-
-instance Outputable MonadNames where
- ppr (MonadNames {return_name=return_name,pure_name=pure_name}) =
- hcat
- [text "MonadNames { return_name = "
- ,ppr return_name
- ,text ", pure_name = "
- ,ppr pure_name
- ,text "}"
- ]
-
--- | rearrange a list of statements using ApplicativeDoStmt. See
--- Note [ApplicativeDo].
-rearrangeForApplicativeDo
- :: HsStmtContext Name
- -> [(ExprLStmt GhcRn, FreeVars)]
- -> RnM ([ExprLStmt GhcRn], FreeVars)
-
-rearrangeForApplicativeDo _ [] = return ([], emptyNameSet)
-rearrangeForApplicativeDo _ [(one,_)] = return ([one], emptyNameSet)
-rearrangeForApplicativeDo ctxt stmts0 = do
- optimal_ado <- goptM Opt_OptimalApplicativeDo
- let stmt_tree | optimal_ado = mkStmtTreeOptimal stmts
- | otherwise = mkStmtTreeHeuristic stmts
- traceRn "rearrangeForADo" (ppr stmt_tree)
- return_name <- lookupSyntaxName' returnMName
- pure_name <- lookupSyntaxName' pureAName
- let monad_names = MonadNames { return_name = return_name
- , pure_name = pure_name }
- stmtTreeToStmts monad_names ctxt stmt_tree [last] last_fvs
- where
- (stmts,(last,last_fvs)) = findLast stmts0
- findLast [] = error "findLast"
- findLast [last] = ([],last)
- findLast (x:xs) = (x:rest,last) where (rest,last) = findLast xs
-
--- | A tree of statements using a mixture of applicative and bind constructs.
-data StmtTree a
- = StmtTreeOne a
- | StmtTreeBind (StmtTree a) (StmtTree a)
- | StmtTreeApplicative [StmtTree a]
-
-instance Outputable a => Outputable (StmtTree a) where
- ppr (StmtTreeOne x) = parens (text "StmtTreeOne" <+> ppr x)
- ppr (StmtTreeBind x y) = parens (hang (text "StmtTreeBind")
- 2 (sep [ppr x, ppr y]))
- ppr (StmtTreeApplicative xs) = parens (hang (text "StmtTreeApplicative")
- 2 (vcat (map ppr xs)))
-
-flattenStmtTree :: StmtTree a -> [a]
-flattenStmtTree t = go t []
- where
- go (StmtTreeOne a) as = a : as
- go (StmtTreeBind l r) as = go l (go r as)
- go (StmtTreeApplicative ts) as = foldr go as ts
-
-type ExprStmtTree = StmtTree (ExprLStmt GhcRn, FreeVars)
-type Cost = Int
-
--- | Turn a sequence of statements into an ExprStmtTree using a
--- heuristic algorithm. /O(n^2)/
-mkStmtTreeHeuristic :: [(ExprLStmt GhcRn, FreeVars)] -> ExprStmtTree
-mkStmtTreeHeuristic [one] = StmtTreeOne one
-mkStmtTreeHeuristic stmts =
- case segments stmts of
- [one] -> split one
- segs -> StmtTreeApplicative (map split segs)
- where
- split [one] = StmtTreeOne one
- split stmts =
- StmtTreeBind (mkStmtTreeHeuristic before) (mkStmtTreeHeuristic after)
- where (before, after) = splitSegment stmts
-
--- | Turn a sequence of statements into an ExprStmtTree optimally,
--- using dynamic programming. /O(n^3)/
-mkStmtTreeOptimal :: [(ExprLStmt GhcRn, FreeVars)] -> ExprStmtTree
-mkStmtTreeOptimal stmts =
- ASSERT(not (null stmts)) -- the empty case is handled by the caller;
- -- we don't support empty StmtTrees.
- fst (arr ! (0,n))
- where
- n = length stmts - 1
- stmt_arr = listArray (0,n) stmts
-
- -- lazy cache of optimal trees for subsequences of the input
- arr :: Array (Int,Int) (ExprStmtTree, Cost)
- arr = array ((0,0),(n,n))
- [ ((lo,hi), tree lo hi)
- | lo <- [0..n]
- , hi <- [lo..n] ]
-
- -- compute the optimal tree for the sequence [lo..hi]
- tree lo hi
- | hi == lo = (StmtTreeOne (stmt_arr ! lo), 1)
- | otherwise =
- case segments [ stmt_arr ! i | i <- [lo..hi] ] of
- [] -> panic "mkStmtTree"
- [_one] -> split lo hi
- segs -> (StmtTreeApplicative trees, maximum costs)
- where
- bounds = scanl (\(_,hi) a -> (hi+1, hi + length a)) (0,lo-1) segs
- (trees,costs) = unzip (map (uncurry split) (tail bounds))
-
- -- find the best place to split the segment [lo..hi]
- split :: Int -> Int -> (ExprStmtTree, Cost)
- split lo hi
- | hi == lo = (StmtTreeOne (stmt_arr ! lo), 1)
- | otherwise = (StmtTreeBind before after, c1+c2)
- where
- -- As per the paper, for a sequence s1...sn, we want to find
- -- the split with the minimum cost, where the cost is the
- -- sum of the cost of the left and right subsequences.
- --
- -- As an optimisation (also in the paper) if the cost of
- -- s1..s(n-1) is different from the cost of s2..sn, we know
- -- that the optimal solution is the lower of the two. Only
- -- in the case that these two have the same cost do we need
- -- to do the exhaustive search.
- --
- ((before,c1),(after,c2))
- | hi - lo == 1
- = ((StmtTreeOne (stmt_arr ! lo), 1),
- (StmtTreeOne (stmt_arr ! hi), 1))
- | left_cost < right_cost
- = ((left,left_cost), (StmtTreeOne (stmt_arr ! hi), 1))
- | left_cost > right_cost
- = ((StmtTreeOne (stmt_arr ! lo), 1), (right,right_cost))
- | otherwise = minimumBy (comparing cost) alternatives
- where
- (left, left_cost) = arr ! (lo,hi-1)
- (right, right_cost) = arr ! (lo+1,hi)
- cost ((_,c1),(_,c2)) = c1 + c2
- alternatives = [ (arr ! (lo,k), arr ! (k+1,hi))
- | k <- [lo .. hi-1] ]
-
-
--- | Turn the ExprStmtTree back into a sequence of statements, using
--- ApplicativeStmt where necessary.
-stmtTreeToStmts
- :: MonadNames
- -> HsStmtContext Name
- -> ExprStmtTree
- -> [ExprLStmt GhcRn] -- ^ the "tail"
- -> FreeVars -- ^ free variables of the tail
- -> RnM ( [ExprLStmt GhcRn] -- ( output statements,
- , FreeVars ) -- , things we needed
-
--- If we have a single bind, and we can do it without a join, transform
--- to an ApplicativeStmt. This corresponds to the rule
--- dsBlock [pat <- rhs] (return expr) = expr <$> rhs
--- In the spec, but we do it here rather than in the desugarer,
--- because we need the typechecker to typecheck the <$> form rather than
--- the bind form, which would give rise to a Monad constraint.
-stmtTreeToStmts monad_names ctxt (StmtTreeOne (L _ (BindStmt _ pat rhs _ fail_op), _))
- tail _tail_fvs
- | not (isStrictPattern pat), (False,tail') <- needJoin monad_names tail
- -- See Note [ApplicativeDo and strict patterns]
- = mkApplicativeStmt ctxt [ApplicativeArgOne
- { xarg_app_arg_one = noExtField
- , app_arg_pattern = pat
- , arg_expr = rhs
- , is_body_stmt = False
- , fail_operator = fail_op}]
- False tail'
-stmtTreeToStmts monad_names ctxt (StmtTreeOne (L _ (BodyStmt _ rhs _ fail_op),_))
- tail _tail_fvs
- | (False,tail') <- needJoin monad_names tail
- = mkApplicativeStmt ctxt
- [ApplicativeArgOne
- { xarg_app_arg_one = noExtField
- , app_arg_pattern = nlWildPatName
- , arg_expr = rhs
- , is_body_stmt = True
- , fail_operator = fail_op}] False tail'
-
-stmtTreeToStmts _monad_names _ctxt (StmtTreeOne (s,_)) tail _tail_fvs =
- return (s : tail, emptyNameSet)
-
-stmtTreeToStmts monad_names ctxt (StmtTreeBind before after) tail tail_fvs = do
- (stmts1, fvs1) <- stmtTreeToStmts monad_names ctxt after tail tail_fvs
- let tail1_fvs = unionNameSets (tail_fvs : map snd (flattenStmtTree after))
- (stmts2, fvs2) <- stmtTreeToStmts monad_names ctxt before stmts1 tail1_fvs
- return (stmts2, fvs1 `plusFV` fvs2)
-
-stmtTreeToStmts monad_names ctxt (StmtTreeApplicative trees) tail tail_fvs = do
- pairs <- mapM (stmtTreeArg ctxt tail_fvs) trees
- let (stmts', fvss) = unzip pairs
- let (need_join, tail') =
- if any hasStrictPattern trees
- then (True, tail)
- else needJoin monad_names tail
-
- (stmts, fvs) <- mkApplicativeStmt ctxt stmts' need_join tail'
- return (stmts, unionNameSets (fvs:fvss))
- where
- stmtTreeArg _ctxt _tail_fvs (StmtTreeOne (L _ (BindStmt _ pat exp _ fail_op), _))
- = return (ApplicativeArgOne
- { xarg_app_arg_one = noExtField
- , app_arg_pattern = pat
- , arg_expr = exp
- , is_body_stmt = False
- , fail_operator = fail_op
- }, emptyFVs)
- stmtTreeArg _ctxt _tail_fvs (StmtTreeOne (L _ (BodyStmt _ exp _ fail_op), _)) =
- return (ApplicativeArgOne
- { xarg_app_arg_one = noExtField
- , app_arg_pattern = nlWildPatName
- , arg_expr = exp
- , is_body_stmt = True
- , fail_operator = fail_op
- }, emptyFVs)
- stmtTreeArg ctxt tail_fvs tree = do
- let stmts = flattenStmtTree tree
- pvarset = mkNameSet (concatMap (collectStmtBinders.unLoc.fst) stmts)
- `intersectNameSet` tail_fvs
- pvars = nameSetElemsStable pvarset
- -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]
- pat = mkBigLHsVarPatTup pvars
- tup = mkBigLHsVarTup pvars
- (stmts',fvs2) <- stmtTreeToStmts monad_names ctxt tree [] pvarset
- (mb_ret, fvs1) <-
- if | L _ ApplicativeStmt{} <- last stmts' ->
- return (unLoc tup, emptyNameSet)
- | otherwise -> do
- ret <- lookupSyntaxName' returnMName
- let expr = HsApp noExtField (noLoc (HsVar noExtField (noLoc ret))) tup
- return (expr, emptyFVs)
- return ( ApplicativeArgMany
- { xarg_app_arg_many = noExtField
- , app_stmts = stmts'
- , final_expr = mb_ret
- , bv_pattern = pat
- }
- , fvs1 `plusFV` fvs2)
-
-
--- | Divide a sequence of statements into segments, where no segment
--- depends on any variables defined by a statement in another segment.
-segments
- :: [(ExprLStmt GhcRn, FreeVars)]
- -> [[(ExprLStmt GhcRn, FreeVars)]]
-segments stmts = map fst $ merge $ reverse $ map reverse $ walk (reverse stmts)
- where
- allvars = mkNameSet (concatMap (collectStmtBinders.unLoc.fst) stmts)
-
- -- We would rather not have a segment that just has LetStmts in
- -- it, so combine those with an adjacent segment where possible.
- merge [] = []
- merge (seg : segs)
- = case rest of
- [] -> [(seg,all_lets)]
- ((s,s_lets):ss) | all_lets || s_lets
- -> (seg ++ s, all_lets && s_lets) : ss
- _otherwise -> (seg,all_lets) : rest
- where
- rest = merge segs
- all_lets = all (isLetStmt . fst) seg
-
- -- walk splits the statement sequence into segments, traversing
- -- the sequence from the back to the front, and keeping track of
- -- the set of free variables of the current segment. Whenever
- -- this set of free variables is empty, we have a complete segment.
- walk :: [(ExprLStmt GhcRn, FreeVars)] -> [[(ExprLStmt GhcRn, FreeVars)]]
- walk [] = []
- walk ((stmt,fvs) : stmts) = ((stmt,fvs) : seg) : walk rest
- where (seg,rest) = chunter fvs' stmts
- (_, fvs') = stmtRefs stmt fvs
-
- chunter _ [] = ([], [])
- chunter vars ((stmt,fvs) : rest)
- | not (isEmptyNameSet vars)
- || isStrictPatternBind stmt
- -- See Note [ApplicativeDo and strict patterns]
- = ((stmt,fvs) : chunk, rest')
- where (chunk,rest') = chunter vars' rest
- (pvars, evars) = stmtRefs stmt fvs
- vars' = (vars `minusNameSet` pvars) `unionNameSet` evars
- chunter _ rest = ([], rest)
-
- stmtRefs stmt fvs
- | isLetStmt stmt = (pvars, fvs' `minusNameSet` pvars)
- | otherwise = (pvars, fvs')
- where fvs' = fvs `intersectNameSet` allvars
- pvars = mkNameSet (collectStmtBinders (unLoc stmt))
-
- isStrictPatternBind :: ExprLStmt GhcRn -> Bool
- isStrictPatternBind (L _ (BindStmt _ pat _ _ _)) = isStrictPattern pat
- isStrictPatternBind _ = False
-
-{-
-Note [ApplicativeDo and strict patterns]
-
-A strict pattern match is really a dependency. For example,
-
-do
- (x,y) <- A
- z <- B
- return C
-
-The pattern (_,_) must be matched strictly before we do B. If we
-allowed this to be transformed into
-
- (\(x,y) -> \z -> C) <$> A <*> B
-
-then it could be lazier than the standard desuraging using >>=. See #13875
-for more examples.
-
-Thus, whenever we have a strict pattern match, we treat it as a
-dependency between that statement and the following one. The
-dependency prevents those two statements from being performed "in
-parallel" in an ApplicativeStmt, but doesn't otherwise affect what we
-can do with the rest of the statements in the same "do" expression.
--}
-
-isStrictPattern :: LPat (GhcPass p) -> Bool
-isStrictPattern lpat =
- case unLoc lpat of
- WildPat{} -> False
- VarPat{} -> False
- LazyPat{} -> False
- AsPat _ _ p -> isStrictPattern p
- ParPat _ p -> isStrictPattern p
- ViewPat _ _ p -> isStrictPattern p
- SigPat _ p _ -> isStrictPattern p
- BangPat{} -> True
- ListPat{} -> True
- TuplePat{} -> True
- SumPat{} -> True
- ConPatIn{} -> True
- ConPatOut{} -> True
- LitPat{} -> True
- NPat{} -> True
- NPlusKPat{} -> True
- SplicePat{} -> True
- _otherwise -> panic "isStrictPattern"
-
-hasStrictPattern :: ExprStmtTree -> Bool
-hasStrictPattern (StmtTreeOne (L _ (BindStmt _ pat _ _ _), _)) = isStrictPattern pat
-hasStrictPattern (StmtTreeOne _) = False
-hasStrictPattern (StmtTreeBind a b) = hasStrictPattern a || hasStrictPattern b
-hasStrictPattern (StmtTreeApplicative trees) = any hasStrictPattern trees
-
-
-isLetStmt :: LStmt a b -> Bool
-isLetStmt (L _ LetStmt{}) = True
-isLetStmt _ = False
-
--- | Find a "good" place to insert a bind in an indivisible segment.
--- This is the only place where we use heuristics. The current
--- heuristic is to peel off the first group of independent statements
--- and put the bind after those.
-splitSegment
- :: [(ExprLStmt GhcRn, FreeVars)]
- -> ( [(ExprLStmt GhcRn, FreeVars)]
- , [(ExprLStmt GhcRn, FreeVars)] )
-splitSegment [one,two] = ([one],[two])
- -- there is no choice when there are only two statements; this just saves
- -- some work in a common case.
-splitSegment stmts
- | Just (lets,binds,rest) <- slurpIndependentStmts stmts
- = if not (null lets)
- then (lets, binds++rest)
- else (lets++binds, rest)
- | otherwise
- = case stmts of
- (x:xs) -> ([x],xs)
- _other -> (stmts,[])
-
-slurpIndependentStmts
- :: [(LStmt GhcRn (Located (body GhcRn)), FreeVars)]
- -> Maybe ( [(LStmt GhcRn (Located (body GhcRn)), FreeVars)] -- LetStmts
- , [(LStmt GhcRn (Located (body GhcRn)), FreeVars)] -- BindStmts
- , [(LStmt GhcRn (Located (body GhcRn)), FreeVars)] )
-slurpIndependentStmts stmts = go [] [] emptyNameSet stmts
- where
- -- If we encounter a BindStmt that doesn't depend on a previous BindStmt
- -- in this group, then add it to the group. We have to be careful about
- -- strict patterns though; splitSegments expects that if we return Just
- -- then we have actually done some splitting. Otherwise it will go into
- -- an infinite loop (#14163).
- go lets indep bndrs ((L loc (BindStmt _ pat body bind_op fail_op), fvs): rest)
- | isEmptyNameSet (bndrs `intersectNameSet` fvs) && not (isStrictPattern pat)
- = go lets ((L loc (BindStmt noExtField pat body bind_op fail_op), fvs) : indep)
- bndrs' rest
- where bndrs' = bndrs `unionNameSet` mkNameSet (collectPatBinders pat)
- -- If we encounter a LetStmt that doesn't depend on a BindStmt in this
- -- group, then move it to the beginning, so that it doesn't interfere with
- -- grouping more BindStmts.
- -- TODO: perhaps we shouldn't do this if there are any strict bindings,
- -- because we might be moving evaluation earlier.
- go lets indep bndrs ((L loc (LetStmt noExtField binds), fvs) : rest)
- | isEmptyNameSet (bndrs `intersectNameSet` fvs)
- = go ((L loc (LetStmt noExtField binds), fvs) : lets) indep bndrs rest
- go _ [] _ _ = Nothing
- go _ [_] _ _ = Nothing
- go lets indep _ stmts = Just (reverse lets, reverse indep, stmts)
-
--- | Build an ApplicativeStmt, and strip the "return" from the tail
--- if necessary.
---
--- For example, if we start with
--- do x <- E1; y <- E2; return (f x y)
--- then we get
--- do (E1[x] | E2[y]); f x y
---
--- the LastStmt in this case has the return removed, but we set the
--- flag on the LastStmt to indicate this, so that we can print out the
--- original statement correctly in error messages. It is easier to do
--- it this way rather than try to ignore the return later in both the
--- typechecker and the desugarer (I tried it that way first!).
-mkApplicativeStmt
- :: HsStmtContext Name
- -> [ApplicativeArg GhcRn] -- ^ The args
- -> Bool -- ^ True <=> need a join
- -> [ExprLStmt GhcRn] -- ^ The body statements
- -> RnM ([ExprLStmt GhcRn], FreeVars)
-mkApplicativeStmt ctxt args need_join body_stmts
- = do { (fmap_op, fvs1) <- lookupStmtName ctxt fmapName
- ; (ap_op, fvs2) <- lookupStmtName ctxt apAName
- ; (mb_join, fvs3) <-
- if need_join then
- do { (join_op, fvs) <- lookupStmtName ctxt joinMName
- ; return (Just join_op, fvs) }
- else
- return (Nothing, emptyNameSet)
- ; let applicative_stmt = noLoc $ ApplicativeStmt noExtField
- (zip (fmap_op : repeat ap_op) args)
- mb_join
- ; return ( applicative_stmt : body_stmts
- , fvs1 `plusFV` fvs2 `plusFV` fvs3) }
-
--- | Given the statements following an ApplicativeStmt, determine whether
--- we need a @join@ or not, and remove the @return@ if necessary.
-needJoin :: MonadNames
- -> [ExprLStmt GhcRn]
- -> (Bool, [ExprLStmt GhcRn])
-needJoin _monad_names [] = (False, []) -- we're in an ApplicativeArg
-needJoin monad_names [L loc (LastStmt _ e _ t)]
- | Just arg <- isReturnApp monad_names e =
- (False, [L loc (LastStmt noExtField arg True t)])
-needJoin _monad_names stmts = (True, stmts)
-
--- | @Just e@, if the expression is @return e@ or @return $ e@,
--- otherwise @Nothing@
-isReturnApp :: MonadNames
- -> LHsExpr GhcRn
- -> Maybe (LHsExpr GhcRn)
-isReturnApp monad_names (L _ (HsPar _ expr)) = isReturnApp monad_names expr
-isReturnApp monad_names (L _ e) = case e of
- OpApp _ l op r | is_return l, is_dollar op -> Just r
- HsApp _ f arg | is_return f -> Just arg
- _otherwise -> Nothing
- where
- is_var f (L _ (HsPar _ e)) = is_var f e
- is_var f (L _ (HsAppType _ e _)) = is_var f e
- is_var f (L _ (HsVar _ (L _ r))) = f r
- -- TODO: I don't know how to get this right for rebindable syntax
- is_var _ _ = False
-
- is_return = is_var (\n -> n == return_name monad_names
- || n == pure_name monad_names)
- is_dollar = is_var (`hasKey` dollarIdKey)
-
-{-
-************************************************************************
-* *
-\subsubsection{Errors}
-* *
-************************************************************************
--}
-
-checkEmptyStmts :: HsStmtContext Name -> RnM ()
--- We've seen an empty sequence of Stmts... is that ok?
-checkEmptyStmts ctxt
- = unless (okEmpty ctxt) (addErr (emptyErr ctxt))
-
-okEmpty :: HsStmtContext a -> Bool
-okEmpty (PatGuard {}) = True
-okEmpty _ = False
-
-emptyErr :: HsStmtContext Name -> SDoc
-emptyErr (ParStmtCtxt {}) = text "Empty statement group in parallel comprehension"
-emptyErr (TransStmtCtxt {}) = text "Empty statement group preceding 'group' or 'then'"
-emptyErr ctxt = text "Empty" <+> pprStmtContext ctxt
-
-----------------------
-checkLastStmt :: Outputable (body GhcPs) => HsStmtContext Name
- -> LStmt GhcPs (Located (body GhcPs))
- -> RnM (LStmt GhcPs (Located (body GhcPs)))
-checkLastStmt ctxt lstmt@(L loc stmt)
- = case ctxt of
- ListComp -> check_comp
- MonadComp -> check_comp
- ArrowExpr -> check_do
- DoExpr -> check_do
- MDoExpr -> check_do
- _ -> check_other
- where
- check_do -- Expect BodyStmt, and change it to LastStmt
- = case stmt of
- BodyStmt _ e _ _ -> return (L loc (mkLastStmt e))
- LastStmt {} -> return lstmt -- "Deriving" clauses may generate a
- -- LastStmt directly (unlike the parser)
- _ -> do { addErr (hang last_error 2 (ppr stmt)); return lstmt }
- last_error = (text "The last statement in" <+> pprAStmtContext ctxt
- <+> text "must be an expression")
-
- check_comp -- Expect LastStmt; this should be enforced by the parser!
- = case stmt of
- LastStmt {} -> return lstmt
- _ -> pprPanic "checkLastStmt" (ppr lstmt)
-
- check_other -- Behave just as if this wasn't the last stmt
- = do { checkStmt ctxt lstmt; return lstmt }
-
--- Checking when a particular Stmt is ok
-checkStmt :: HsStmtContext Name
- -> LStmt GhcPs (Located (body GhcPs))
- -> RnM ()
-checkStmt ctxt (L _ stmt)
- = do { dflags <- getDynFlags
- ; case okStmt dflags ctxt stmt of
- IsValid -> return ()
- NotValid extra -> addErr (msg $$ extra) }
- where
- msg = sep [ text "Unexpected" <+> pprStmtCat stmt <+> ptext (sLit "statement")
- , text "in" <+> pprAStmtContext ctxt ]
-
-pprStmtCat :: Stmt (GhcPass a) body -> SDoc
-pprStmtCat (TransStmt {}) = text "transform"
-pprStmtCat (LastStmt {}) = text "return expression"
-pprStmtCat (BodyStmt {}) = text "body"
-pprStmtCat (BindStmt {}) = text "binding"
-pprStmtCat (LetStmt {}) = text "let"
-pprStmtCat (RecStmt {}) = text "rec"
-pprStmtCat (ParStmt {}) = text "parallel"
-pprStmtCat (ApplicativeStmt {}) = panic "pprStmtCat: ApplicativeStmt"
-pprStmtCat (XStmtLR nec) = noExtCon nec
-
-------------
-emptyInvalid :: Validity -- Payload is the empty document
-emptyInvalid = NotValid Outputable.empty
-
-okStmt, okDoStmt, okCompStmt, okParStmt
- :: DynFlags -> HsStmtContext Name
- -> Stmt GhcPs (Located (body GhcPs)) -> Validity
--- Return Nothing if OK, (Just extra) if not ok
--- The "extra" is an SDoc that is appended to a generic error message
-
-okStmt dflags ctxt stmt
- = case ctxt of
- PatGuard {} -> okPatGuardStmt stmt
- ParStmtCtxt ctxt -> okParStmt dflags ctxt stmt
- DoExpr -> okDoStmt dflags ctxt stmt
- MDoExpr -> okDoStmt dflags ctxt stmt
- ArrowExpr -> okDoStmt dflags ctxt stmt
- GhciStmtCtxt -> okDoStmt dflags ctxt stmt
- ListComp -> okCompStmt dflags ctxt stmt
- MonadComp -> okCompStmt dflags ctxt stmt
- TransStmtCtxt ctxt -> okStmt dflags ctxt stmt
-
--------------
-okPatGuardStmt :: Stmt GhcPs (Located (body GhcPs)) -> Validity
-okPatGuardStmt stmt
- = case stmt of
- BodyStmt {} -> IsValid
- BindStmt {} -> IsValid
- LetStmt {} -> IsValid
- _ -> emptyInvalid
-
--------------
-okParStmt dflags ctxt stmt
- = case stmt of
- LetStmt _ (L _ (HsIPBinds {})) -> emptyInvalid
- _ -> okStmt dflags ctxt stmt
-
-----------------
-okDoStmt dflags ctxt stmt
- = case stmt of
- RecStmt {}
- | LangExt.RecursiveDo `xopt` dflags -> IsValid
- | ArrowExpr <- ctxt -> IsValid -- Arrows allows 'rec'
- | otherwise -> NotValid (text "Use RecursiveDo")
- BindStmt {} -> IsValid
- LetStmt {} -> IsValid
- BodyStmt {} -> IsValid
- _ -> emptyInvalid
-
-----------------
-okCompStmt dflags _ stmt
- = case stmt of
- BindStmt {} -> IsValid
- LetStmt {} -> IsValid
- BodyStmt {} -> IsValid
- ParStmt {}
- | LangExt.ParallelListComp `xopt` dflags -> IsValid
- | otherwise -> NotValid (text "Use ParallelListComp")
- TransStmt {}
- | LangExt.TransformListComp `xopt` dflags -> IsValid
- | otherwise -> NotValid (text "Use TransformListComp")
- RecStmt {} -> emptyInvalid
- LastStmt {} -> emptyInvalid -- Should not happen (dealt with by checkLastStmt)
- ApplicativeStmt {} -> emptyInvalid
- XStmtLR nec -> noExtCon nec
-
----------
-checkTupleSection :: [LHsTupArg GhcPs] -> RnM ()
-checkTupleSection args
- = do { tuple_section <- xoptM LangExt.TupleSections
- ; checkErr (all tupArgPresent args || tuple_section) msg }
- where
- msg = text "Illegal tuple section: use TupleSections"
-
----------
-sectionErr :: HsExpr GhcPs -> SDoc
-sectionErr expr
- = hang (text "A section must be enclosed in parentheses")
- 2 (text "thus:" <+> (parens (ppr expr)))
-
-badIpBinds :: Outputable a => SDoc -> a -> SDoc
-badIpBinds what binds
- = hang (text "Implicit-parameter bindings illegal in" <+> what)
- 2 (ppr binds)
-
----------
-
-monadFailOp :: LPat GhcPs
- -> HsStmtContext Name
- -> RnM (SyntaxExpr GhcRn, FreeVars)
-monadFailOp pat ctxt
- -- If the pattern is irrefutable (e.g.: wildcard, tuple, ~pat, etc.)
- -- we should not need to fail.
- | isIrrefutableHsPat pat = return (noSyntaxExpr, emptyFVs)
-
- -- For non-monadic contexts (e.g. guard patterns, list
- -- comprehensions, etc.) we should not need to fail. See Note
- -- [Failing pattern matches in Stmts]
- | not (isMonadFailStmtContext ctxt) = return (noSyntaxExpr, emptyFVs)
-
- | otherwise = getMonadFailOp
-
-{-
-Note [Monad fail : Rebindable syntax, overloaded strings]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Given the code
- foo x = do { Just y <- x; return y }
-
-we expect it to desugar as
- foo x = x >>= \r -> case r of
- Just y -> return y
- Nothing -> fail "Pattern match error"
-
-But with RebindableSyntax and OverloadedStrings, we really want
-it to desugar thus:
- foo x = x >>= \r -> case r of
- Just y -> return y
- Nothing -> fail (fromString "Patterm match error")
-
-So, in this case, we synthesize the function
- \x -> fail (fromString x)
-
-(rather than plain 'fail') for the 'fail' operation. This is done in
-'getMonadFailOp'.
--}
-getMonadFailOp :: RnM (SyntaxExpr GhcRn, FreeVars) -- Syntax expr fail op
-getMonadFailOp
- = do { xOverloadedStrings <- fmap (xopt LangExt.OverloadedStrings) getDynFlags
- ; xRebindableSyntax <- fmap (xopt LangExt.RebindableSyntax) getDynFlags
- ; reallyGetMonadFailOp xRebindableSyntax xOverloadedStrings
- }
- where
- reallyGetMonadFailOp rebindableSyntax overloadedStrings
- | rebindableSyntax && overloadedStrings = do
- (failExpr, failFvs) <- lookupSyntaxName failMName
- (fromStringExpr, fromStringFvs) <- lookupSyntaxName fromStringName
- let arg_lit = fsLit "arg"
- arg_name = mkSystemVarName (mkVarOccUnique arg_lit) arg_lit
- arg_syn_expr = mkRnSyntaxExpr arg_name
- let body :: LHsExpr GhcRn =
- nlHsApp (noLoc $ syn_expr failExpr)
- (nlHsApp (noLoc $ syn_expr fromStringExpr)
- (noLoc $ syn_expr arg_syn_expr))
- let failAfterFromStringExpr :: HsExpr GhcRn =
- unLoc $ mkHsLam [noLoc $ VarPat noExtField $ noLoc arg_name] body
- let failAfterFromStringSynExpr :: SyntaxExpr GhcRn =
- mkSyntaxExpr failAfterFromStringExpr
- return (failAfterFromStringSynExpr, failFvs `plusFV` fromStringFvs)
- | otherwise = lookupSyntaxName failMName