+type TcStmtChecker
+ = forall thing. HsStmtContext Name
+ -> Stmt Name
+ -> BoxyRhoType -- Result type for comprehension
+ -> (BoxyRhoType -> TcM thing) -- Checker for what follows the stmt
+ -> TcM (Stmt TcId, thing)
+
+ -- The incoming BoxyRhoType may be refined by type refinements
+ -- before being passed to the thing_inside
+
+tcStmts :: HsStmtContext Name
+ -> TcStmtChecker -- NB: higher-rank type
+ -> [LStmt Name]
+ -> BoxyRhoType
+ -> (BoxyRhoType -> 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 [] res_ty thing_inside
+ = do { thing <- thing_inside res_ty
+ ; return ([], thing) }
+
+-- LetStmts are handled uniformly, regardless of context
+tcStmts ctxt stmt_chk (L loc (LetStmt binds) : stmts) res_ty thing_inside
+ = do { (binds', (stmts',thing)) <- tcLocalBinds binds $
+ tcStmts ctxt stmt_chk stmts res_ty thing_inside
+ ; return (L loc (LetStmt binds') : stmts', thing) }
+
+-- For the vanilla case, handle the location-setting part
+tcStmts ctxt stmt_chk (L loc stmt : stmts) res_ty thing_inside
+ = do { (stmt', (stmts', thing)) <-
+ setSrcSpan loc $
+ addErrCtxt (stmtCtxt ctxt stmt) $
+ stmt_chk ctxt stmt res_ty $ \ res_ty' ->
+ popErrCtxt $
+ tcStmts ctxt stmt_chk stmts res_ty' $
+ thing_inside
+ ; return (L loc stmt' : stmts', thing) }
+
+--------------------------------
+-- Pattern guards
+tcGuardStmt :: TcStmtChecker
+tcGuardStmt ctxt (ExprStmt guard _ _) res_ty thing_inside
+ = do { guard' <- tcMonoExpr guard boolTy
+ ; thing <- thing_inside res_ty
+ ; return (ExprStmt guard' noSyntaxExpr boolTy, thing) }
+
+tcGuardStmt ctxt (BindStmt pat rhs _ _) res_ty thing_inside
+ = do { (rhs', rhs_ty) <- tcInferRho rhs
+ ; (pat', thing) <- tcPat LamPat pat rhs_ty res_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+tcGuardStmt ctxt stmt res_ty thing_inside
+ = pprPanic "tcGuardStmt: unexpected Stmt" (ppr stmt)
+
+
+--------------------------------
+-- List comprehensions and PArrays
+
+tcLcStmt :: TyCon -- The list/Parray type constructor ([] or PArray)
+ -> TcStmtChecker
+
+-- A generator, pat <- rhs
+tcLcStmt m_tc ctxt (BindStmt pat rhs _ _) res_ty thing_inside
+ = do { (rhs', pat_ty) <- withBox liftedTypeKind $ \ ty ->
+ tcMonoExpr rhs (mkTyConApp m_tc [ty])
+ ; (pat', thing) <- tcPat LamPat pat pat_ty res_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+-- A boolean guard
+tcLcStmt m_tc ctxt (ExprStmt rhs _ _) res_ty thing_inside
+ = do { rhs' <- tcMonoExpr rhs boolTy
+ ; thing <- thing_inside res_ty
+ ; 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 ctxt (ParStmt bndr_stmts_s) elt_ty 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 elt_ty -- No refinement from pattern
+ ; return ([], thing) } -- matching in the branches
+
+ loop ((stmts, names) : pairs)
+ = do { (stmts', (ids, pairs', thing))
+ <- tcStmts ctxt (tcLcStmt m_tc) stmts elt_ty $ \ elt_ty' ->
+ do { ids <- tcLookupLocalIds names
+ ; (pairs', thing) <- loop pairs
+ ; return (ids, pairs', thing) }
+ ; return ( (stmts', ids) : pairs', thing ) }
+
+tcLcStmt m_tc ctxt stmt elt_ty thing_inside
+ = pprPanic "tcLcStmt: unexpected Stmt" (ppr stmt)
+
+--------------------------------
+-- Do-notation
+-- The main excitement here is dealing with rebindable syntax
+
+tcDoStmt :: TcType -- Monad type, m
+ -> TcStmtChecker
+
+tcDoStmt m_ty ctxt (BindStmt pat rhs bind_op fail_op) res_ty thing_inside
+ = do { (rhs', pat_ty) <- withBox liftedTypeKind $ \ pat_ty ->
+ tcMonoExpr rhs (mkAppTy m_ty pat_ty)
+ -- 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.
+
+ ; (pat', thing) <- tcPat LamPat pat pat_ty res_ty thing_inside
+
+ -- Deal with rebindable syntax; (>>=) :: m a -> (a -> m b) -> m b
+ ; let bind_ty = mkFunTys [mkAppTy m_ty pat_ty,
+ mkFunTy pat_ty res_ty] res_ty
+ ; 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 ctxt (ExprStmt rhs then_op _) res_ty thing_inside
+ = do { -- Deal with rebindable syntax; (>>) :: m a -> m b -> m b
+ a_ty <- newFlexiTyVarTy 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' <- tcPolyExpr rhs rhs_ty
+ ; thing <- thing_inside res_ty
+ ; return (ExprStmt rhs' then_op' rhs_ty, thing) }
+
+tcDoStmt m_ty ctxt stmt res_ty thing_inside
+ = pprPanic "tcDoStmt: unexpected Stmt" (ppr stmt)
+
+--------------------------------
+-- Mdo-notation
+-- The distinctive features here are
+-- (a) RecStmts, and
+-- (b) no rebindable syntax
+
+tcMDoStmt :: (LHsExpr Name -> TcM (LHsExpr TcId, TcType)) -- RHS inference
+ -> TcStmtChecker
+tcMDoStmt tc_rhs ctxt (BindStmt pat rhs bind_op fail_op) res_ty thing_inside
+ = do { (rhs', pat_ty) <- tc_rhs rhs
+ ; (pat', thing) <- tcPat LamPat pat pat_ty res_ty thing_inside
+ ; return (BindStmt pat' rhs' noSyntaxExpr noSyntaxExpr, thing) }
+
+tcMDoStmt tc_rhs ctxt (ExprStmt rhs then_op _) res_ty thing_inside
+ = do { (rhs', elt_ty) <- tc_rhs rhs
+ ; thing <- thing_inside res_ty
+ ; return (ExprStmt rhs' noSyntaxExpr elt_ty, thing) }
+
+tcMDoStmt tc_rhs ctxt (RecStmt stmts laterNames recNames _ _) res_ty thing_inside
+ = do { rec_tys <- newFlexiTyVarTys (length recNames) liftedTypeKind
+ ; let rec_ids = zipWith mkLocalId recNames rec_tys
+ ; tcExtendIdEnv rec_ids $ do
+ { (stmts', (later_ids, rec_rets))
+ <- tcStmts ctxt (tcMDoStmt tc_rhs) stmts res_ty $ \ res_ty' ->
+ -- 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 res_ty))
+ -- 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
+ = do { poly_id <- tcLookupId rec_name
+ -- poly_id may have a polymorphic type
+ -- but mono_ty is just a monomorphic type variable
+ ; co_fn <- tcSubExp (idType poly_id) mono_ty
+ ; return (mkHsCoerce co_fn (HsVar poly_id)) }
+
+tcMDoStmt tc_rhs ctxt stmt res_ty thing_inside
+ = pprPanic "tcMDoStmt: unexpected Stmt" (ppr stmt)
+