+\begin{code}
+rnStmts :: HsStmtContext Name -> [LStmt RdrName]
+ -> RnM (thing, FreeVars)
+ -> RnM (([LStmt Name], thing), FreeVars)
+
+rnStmts (MDoExpr _) = rnMDoStmts
+rnStmts ctxt = rnNormalStmts ctxt
+
+rnNormalStmts :: HsStmtContext Name -> [LStmt RdrName]
+ -> RnM (thing, FreeVars)
+ -> RnM (([LStmt Name], thing), FreeVars)
+-- Used for cases *other* than recursive mdo
+-- Implements nested scopes
+
+rnNormalStmts ctxt [] thing_inside
+ = do { (thing, fvs) <- thing_inside
+ ; return (([],thing), fvs) }
+
+rnNormalStmts ctxt (L loc stmt : stmts) thing_inside
+ = do { ((stmt', (stmts', thing)), fvs)
+ <- rnStmt ctxt stmt $
+ rnNormalStmts ctxt stmts thing_inside
+ ; return (((L loc stmt' : stmts'), thing), fvs) }
+
+rnStmt :: HsStmtContext Name -> Stmt RdrName
+ -> RnM (thing, FreeVars)
+ -> RnM ((Stmt Name, thing), FreeVars)
+
+rnStmt ctxt (ExprStmt expr _ _) thing_inside
+ = do { (expr', fv_expr) <- rnLExpr expr
+ ; (then_op, fvs1) <- lookupSyntaxName thenMName
+ ; (thing, fvs2) <- thing_inside
+ ; return ((ExprStmt expr' then_op placeHolderType, thing),
+ fv_expr `plusFV` fvs1 `plusFV` fvs2) }
+
+rnStmt ctxt (BindStmt pat expr _ _) thing_inside
+ = do { (expr', fv_expr) <- rnLExpr expr
+ -- The binders do not scope over the expression
+ ; (bind_op, fvs1) <- lookupSyntaxName bindMName
+ ; (fail_op, fvs2) <- lookupSyntaxName failMName
+
+ ; let reportUnused = case ctxt of
+ ParStmtCtxt{} -> False
+ _ -> True
+ ; rnPatsAndThen (StmtCtxt ctxt) reportUnused [pat] $ \ [pat'] -> do
+ { (thing, fvs3) <- thing_inside
+ ; return ((BindStmt pat' expr' bind_op fail_op, thing),
+ fv_expr `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) }}
+ -- fv_expr shouldn't really be filtered by
+ -- the rnPatsAndThen, but it does not matter
+
+rnStmt ctxt (LetStmt binds) thing_inside
+ = do { checkErr (ok ctxt binds) (badIpBinds binds)
+ ; rnBindGroupsAndThen binds $ \ binds' -> do
+ { (thing, fvs) <- thing_inside
+ ; return ((LetStmt binds', thing), fvs) }}
+ where
+ -- We do not allow implicit-parameter bindings in a parallel
+ -- list comprehension. I'm not sure what it might mean.
+ ok (ParStmtCtxt _) binds = not (any is_ip_bind binds)
+ ok _ _ = True
+
+ is_ip_bind (HsIPBinds _) = True
+ is_ip_bind _ = False
+
+rnStmt ctxt (ParStmt stmtss) thing_inside
+ = do { opt_GlasgowExts <- doptM Opt_GlasgowExts
+ ; checkM opt_GlasgowExts parStmtErr
+ ; (stmtss'_w_unit, fv_stmtss) <- mapFvRn rn_branch stmtss
+ ; let
+ bndrss :: [[Name]] -- NB: Name, not RdrName
+ bndrss = map (map unLoc . collectLStmtsBinders) stmtss'
+ (bndrs, dups) = removeDups cmpByOcc (concat bndrss)
+ stmtss' = map fst stmtss'_w_unit
+ ; mappM dupErr dups
+
+ ; bindLocalNamesFV bndrs $ do
+ { (thing, fvs) <- thing_inside
+ -- Note: binders are returned in scope order, so one may
+ -- shadow the next; e.g. x <- xs; x <- ys
+
+ -- Cut down the exported binders to just the ones needed in the body
+ ; let used_bndrs_s = map (filter (`elemNameSet` fvs)) bndrss
+ unused_bndrs = filter (not . (`elemNameSet` fvs)) bndrs
+
+ -- With processing of the branches and the tail of comprehension done,
+ -- we can finally compute&report any unused ParStmt binders.
+ ; warnUnusedMatches unused_bndrs
+ ; return ((ParStmt (stmtss' `zip` used_bndrs_s), thing),
+ fv_stmtss `plusFV` fvs) }}
+ where
+ rn_branch (stmts, _) = rnNormalStmts (ParStmtCtxt ctxt) stmts $
+ return ((), emptyFVs)
+
+ cmpByOcc n1 n2 = nameOccName n1 `compare` nameOccName n2
+ dupErr (v:_) = addErr (ptext SLIT("Duplicate binding in parallel list comprehension for:")
+ <+> quotes (ppr v))
+
+rnStmt ctxt (RecStmt rec_stmts _ _ _ _) thing_inside
+ = bindLocatedLocalsRn doc (collectLStmtsBinders rec_stmts) $ \ _ ->
+ rn_rec_stmts rec_stmts `thenM` \ segs ->
+ thing_inside `thenM` \ (thing, fvs) ->
+ let
+ segs_w_fwd_refs = addFwdRefs segs
+ (ds, us, fs, rec_stmts') = unzip4 segs_w_fwd_refs
+ later_vars = nameSetToList (plusFVs ds `intersectNameSet` fvs)
+ fwd_vars = nameSetToList (plusFVs fs)
+ uses = plusFVs us
+ rec_stmt = RecStmt rec_stmts' later_vars fwd_vars [] emptyLHsBinds
+ in
+ returnM ((rec_stmt, thing), uses `plusFV` fvs)
+ where
+ doc = text "In a recursive do statement"
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsubsection{mdo expressions}
+%* *
+%************************************************************************