+%************************************************************************
+%* *
+\subsection{tcStmts}
+%* *
+%************************************************************************
+
+\begin{code}
+type TcStmtChecker
+ = forall thing. HsStmtContext Name
+ -> Stmt Name
+ -> TcM thing
+ -> TcM (Stmt TcId, thing)
+
+tcStmts :: HsStmtContext Name
+ -> TcStmtChecker -- NB: higher-rank type
+ -> [LStmt Name]
+ -> TcM thing
+ -> TcM ([LStmt TcId], thing)
+
+-- Note the higher-rank type. stmt_chk is applied at different
+-- types in the equations for tcStmts
+
+tcStmts ctxt stmt_chk [] thing_inside
+ = do { thing <- thing_inside
+ ; return ([], thing) }
+
+-- LetStmts are handled uniformly, regardless of context
+tcStmts ctxt stmt_chk (L loc (LetStmt binds) : stmts) thing_inside
+ = tcBindsAndThen -- No error context, but a binding group is
+ glue_binds -- rather a large thing for an error context anyway
+ binds
+ (tcStmts ctxt stmt_chk stmts thing_inside)
+ where
+ glue_binds binds (stmts, thing) = (L loc (LetStmt [binds]) : stmts, thing)
+
+
+-- For the vanilla case, handle the location-setting part
+tcStmts ctxt stmt_chk (L loc stmt : stmts) thing_inside
+ = do { (stmt', (stmts', thing)) <-
+ setSrcSpan loc $
+ addErrCtxt (stmtCtxt ctxt stmt) $
+ stmt_chk ctxt stmt $
+ popErrCtxt $
+ tcStmts ctxt stmt_chk stmts $
+ thing_inside
+ ; return (L loc stmt' : stmts', thing) }
+
+--------------------------------
+-- Pattern guards
+tcGuardStmt :: TcType -> TcStmtChecker
+tcGuardStmt res_ty ctxt (ExprStmt guard _ _) thing_inside
+ = do { guard' <- tcCheckRho guard boolTy
+ ; thing <- thing_inside
+ ; return (ExprStmt guard' noSyntaxExpr boolTy, thing) }
+
+tcGuardStmt res_ty ctxt (BindStmt pat rhs _ _) thing_inside
+ = do { (rhs', rhs_ty) <- tcInferRho rhs
+ ; (pat', thing) <- tcBindPat pat rhs_ty res_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+tcGuardStmt res_ty ctxt stmt thing_inside
+ = pprPanic "tcGuardStmt: unexpected Stmt" (ppr stmt)
+
+
+--------------------------------
+-- List comprehensions and PArrays
+
+tcLcStmt :: TyCon -- The list/Parray type constructor ([] or PArray)
+ -> TcType -- The element type of the list or PArray
+ -> TcStmtChecker
+
+-- A generator, pat <- rhs
+tcLcStmt m_tc elt_ty ctxt (BindStmt pat rhs _ _) thing_inside
+ = do { (rhs', rhs_ty) <- tcInferRho rhs
+ ; [pat_ty] <- unifyTyConApp m_tc rhs_ty
+ ; (pat', thing) <- tcBindPat pat pat_ty elt_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+-- A boolean guard
+tcLcStmt m_tc elt_ty ctxt (ExprStmt rhs _ _) thing_inside
+ = do { rhs' <- tcCheckRho rhs boolTy
+ ; thing <- thing_inside
+ ; return (ExprStmt rhs' noSyntaxExpr boolTy, thing) }
+
+-- A parallel set of comprehensions
+-- [ (g x, h x) | ... ; let g v = ...
+-- | ... ; let h v = ... ]
+--
+-- It's possible that g,h are overloaded, so we need to feed the LIE from the
+-- (g x, h x) up through both lots of bindings (so we get the bindInstsOfLocalFuns).
+-- Similarly if we had an existential pattern match:
+--
+-- data T = forall a. Show a => C a
+--
+-- [ (show x, show y) | ... ; C x <- ...
+-- | ... ; C y <- ... ]
+--
+-- Then we need the LIE from (show x, show y) to be simplified against
+-- the bindings for x and y.
+--
+-- It's difficult to do this in parallel, so we rely on the renamer to
+-- ensure that g,h and x,y don't duplicate, and simply grow the environment.
+-- So the binders of the first parallel group will be in scope in the second
+-- group. But that's fine; there's no shadowing to worry about.
+
+tcLcStmt m_tc elt_ty ctxt (ParStmt bndr_stmts_s) thing_inside
+ = do { (pairs', thing) <- loop bndr_stmts_s
+ ; return (ParStmt pairs', thing) }
+ where
+ -- loop :: [([LStmt Name], [Name])] -> TcM ([([LStmt TcId], [TcId])], thing)
+ loop [] = do { thing <- thing_inside
+ ; return ([], thing) }
+
+ loop ((stmts, names) : pairs)
+ = do { (stmts', (ids, pairs', thing))
+ <- tcStmts ctxt (tcLcStmt m_tc elt_ty) stmts $
+ do { ids <- tcLookupLocalIds names
+ ; (pairs', thing) <- loop pairs
+ ; return (ids, pairs', thing) }
+ ; return ( (stmts', ids) : pairs', thing ) }
+
+tcLcStmt m_tc elt_ty ctxt stmt thing_inside
+ = pprPanic "tcLcStmt: unexpected Stmt" (ppr stmt)
+
+--------------------------------
+-- Do-notation
+-- The main excitement here is dealing with rebindable syntax
+
+tcDoStmt :: TcType -- Monad type, m
+ -> TcType -- Result type, m b
+ -> TcStmtChecker
+ -- BindStmt
+tcDoStmt m_ty res_ty ctxt (BindStmt pat rhs bind_op fail_op) thing_inside
+ = do { -- Deal with rebindable syntax; (>>=) :: m a -> (a -> m b) -> m b
+ ; (rhs', rhs_ty) <- tcInferRho rhs
+ -- We should use type *inference* for the RHS computations, becuase of GADTs.
+ -- do { pat <- rhs; <rest> }
+ -- is rather like
+ -- case rhs of { pat -> <rest> }
+ -- We do inference on rhs, so that information about its type can be refined
+ -- when type-checking the pattern.
+
+ ; (n_ty, pat_ty) <- unifyAppTy rhs_ty
+ ; unifyTauTy m_ty n_ty
+ ; let bind_ty = mkFunTys [rhs_ty, mkFunTy pat_ty res_ty] res_ty
+
+ ; (pat', thing) <- tcBindPat pat pat_ty res_ty thing_inside
+
+ -- Rebindable syntax stuff
+ ; bind_op' <- tcSyntaxOp DoOrigin bind_op bind_ty
+ -- If (but only if) the pattern can fail,
+ -- typecheck the 'fail' operator
+ ; fail_op' <- if isIrrefutableHsPat pat'
+ then return noSyntaxExpr
+ else tcSyntaxOp DoOrigin fail_op (mkFunTy stringTy res_ty)
+ ; return (BindStmt pat' rhs' bind_op' fail_op', thing) }
+
+
+tcDoStmt m_ty res_ty ctxt (ExprStmt rhs then_op _) thing_inside
+ = do { -- Deal with rebindable syntax; (>>) :: m a -> m b -> m b
+ a_ty <- newTyFlexiVarTy liftedTypeKind
+ ; let rhs_ty = mkAppTy m_ty a_ty
+ then_ty = mkFunTys [rhs_ty, res_ty] res_ty
+ ; then_op' <- tcSyntaxOp DoOrigin then_op then_ty
+ ; rhs' <- tcCheckSigma rhs rhs_ty
+ ; thing <- thing_inside
+ ; return (ExprStmt rhs' then_op' rhs_ty, thing) }
+
+tcDoStmt m_ty res_ty ctxt stmt thing_inside
+ = pprPanic "tcDoStmt: unexpected Stmt" (ppr stmt)
+
+--------------------------------
+-- Mdo-notation
+-- The distinctive features here are
+-- (a) RecStmts, and
+-- (b) no rebindable syntax
+
+tcMDoStmt :: TcType -- Result type, m b
+ -> (LHsExpr Name -> TcM (LHsExpr TcId, TcType)) -- RHS inference
+ -> TcStmtChecker
+tcMDoStmt res_ty tc_rhs ctxt (BindStmt pat rhs bind_op fail_op) thing_inside
+ = do { (rhs', pat_ty) <- tc_rhs rhs
+ ; (pat', thing) <- tcBindPat pat pat_ty res_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+tcMDoStmt res_ty tc_rhs ctxt (ExprStmt rhs then_op _) thing_inside
+ = do { (rhs', elt_ty) <- tc_rhs rhs
+ ; thing <- thing_inside
+ ; return (ExprStmt rhs' noSyntaxExpr elt_ty, thing) }
+
+tcMDoStmt res_ty tc_rhs ctxt (RecStmt stmts laterNames recNames _ _) thing_inside
+ = do { rec_tys <- newTyFlexiVarTys (length recNames) liftedTypeKind
+ ; let rec_ids = zipWith mkLocalId recNames rec_tys
+ ; tcExtendIdEnv rec_ids $ do
+ { (stmts', (later_ids, rec_rets))
+ <- tcStmts ctxt (tcMDoStmt res_ty tc_rhs) stmts $
+ -- ToDo: res_ty not really right
+ do { rec_rets <- zipWithM tc_ret recNames rec_tys
+ ; later_ids <- tcLookupLocalIds laterNames
+ ; return (later_ids, rec_rets) }
+
+ ; (thing,lie) <- tcExtendIdEnv later_ids (getLIE thing_inside)
+ -- NB: The rec_ids for the recursive things
+ -- already scope over this part. This binding may shadow
+ -- some of them with polymorphic things with the same Name
+ -- (see note [RecStmt] in HsExpr)
+ ; lie_binds <- bindInstsOfLocalFuns lie later_ids
+
+ ; return (RecStmt stmts' later_ids rec_ids rec_rets lie_binds, thing)
+ }}
+ where
+ -- Unify the types of the "final" Ids with those of "knot-tied" Ids
+ tc_ret rec_name mono_ty
+ = tcLookupId rec_name `thenM` \ poly_id ->
+ -- poly_id may have a polymorphic type
+ -- but mono_ty is just a monomorphic type variable
+ tcSubExp (Check mono_ty) (idType poly_id) `thenM` \ co_fn ->
+ returnM (co_fn <$> HsVar poly_id)
+
+tcMDoStmt res_ty tc_rhs ctxt stmt thing_inside
+ = pprPanic "tcMDoStmt: unexpected Stmt" (ppr stmt)
+
+-----------------
+tcBindPat :: LPat Name -> TcType
+ -> TcType -- Result type; used only to check existential escape
+ -> TcM a
+ -> TcM (LPat TcId, a)
+tcBindPat pat pat_ty res_ty thing_inside
+ = do { ([pat'],thing) <- tcMatchPats [pat] [Check pat_ty]
+ (Check res_ty) thing_inside
+ ; return (pat', thing) }