-tcStmts :: StmtCtxt
- -> (TcType -> TcType) -- m, the relationship type of pat and rhs in pat <- rhs
- -> [RenamedStmt]
- -> TcType -- elt_ty, where type of the comprehension is (m elt_ty)
- -> TcM s ([TcStmt], LIE)
-
-tcStmts do_or_lc m (stmt@(ReturnStmt exp) : stmts) elt_ty
- = ASSERT( null stmts )
- tcSetErrCtxt (stmtCtxt do_or_lc stmt) $
- tcExpr exp elt_ty `thenTc` \ (exp', exp_lie) ->
- returnTc ([ReturnStmt exp'], exp_lie)
-
- -- ExprStmt at the end
-tcStmts do_or_lc m [stmt@(ExprStmt exp src_loc)] elt_ty
- = tcSetErrCtxt (stmtCtxt do_or_lc stmt) $
- tcExpr exp (m elt_ty) `thenTc` \ (exp', exp_lie) ->
- returnTc ([ExprStmt exp' src_loc], exp_lie)
-
- -- ExprStmt not at the end
-tcStmts do_or_lc m (stmt@(ExprStmt exp src_loc) : stmts) elt_ty
- = ASSERT( isDoStmt do_or_lc )
- tcAddSrcLoc src_loc (
- tcSetErrCtxt (stmtCtxt do_or_lc stmt) $
- -- exp has type (m tau) for some tau (doesn't matter what)
- newTyVarTy openTypeKind `thenNF_Tc` \ any_ty ->
- tcExpr exp (m any_ty)
- ) `thenTc` \ (exp', exp_lie) ->
- tcStmts do_or_lc m stmts elt_ty `thenTc` \ (stmts', stmts_lie) ->
- returnTc (ExprStmt exp' src_loc : stmts',
- exp_lie `plusLIE` stmts_lie)
-
-tcStmts do_or_lc m (stmt@(GuardStmt exp src_loc) : stmts) elt_ty
- = ASSERT( not (isDoStmt do_or_lc) )
- tcSetErrCtxt (stmtCtxt do_or_lc stmt) (
- tcAddSrcLoc src_loc $
- tcExpr exp boolTy
- ) `thenTc` \ (exp', exp_lie) ->
- tcStmts do_or_lc m stmts elt_ty `thenTc` \ (stmts', stmts_lie) ->
- returnTc (GuardStmt exp' src_loc : stmts',
- exp_lie `plusLIE` stmts_lie)
-
-tcStmts do_or_lc m (stmt@(BindStmt pat exp src_loc) : stmts) elt_ty
- = tcAddSrcLoc src_loc (
- tcSetErrCtxt (stmtCtxt do_or_lc stmt) $
- newTyVarTy boxedTypeKind `thenNF_Tc` \ pat_ty ->
- tcPat tcPatBndr_NoSigs pat pat_ty `thenTc` \ (pat', pat_lie, pat_tvs, pat_ids, avail) ->
- tcExpr exp (m pat_ty) `thenTc` \ (exp', exp_lie) ->
- returnTc (pat', exp',
- pat_lie `plusLIE` exp_lie,
- pat_tvs, pat_ids, avail)
- ) `thenTc` \ (pat', exp', lie_req, pat_tvs, pat_bndrs, lie_avail) ->
- let
- new_val_env = bagToList pat_bndrs
- pat_ids = map snd new_val_env
- pat_tv_list = bagToList pat_tvs
- in
-
- -- Do the rest; we don't need to add the pat_tvs to the envt
- -- because they all appear in the pat_ids's types
- tcExtendLocalValEnv new_val_env (
- tcStmts do_or_lc m stmts elt_ty
- ) `thenTc` \ (stmts', stmts_lie) ->
-
-
- -- Reinstate context for existential checks
- tcSetErrCtxt (stmtCtxt do_or_lc stmt) $
- tcExtendGlobalTyVars (tyVarsOfType (m elt_ty)) $
- tcAddErrCtxtM (sigPatCtxt pat_tv_list pat_ids) $
-
- checkSigTyVars pat_tv_list emptyVarSet `thenTc` \ zonked_pat_tvs ->
-
- tcSimplifyAndCheck
- (text ("the existential context of a data constructor"))
- (mkVarSet zonked_pat_tvs)
- lie_avail stmts_lie `thenTc` \ (final_lie, dict_binds) ->
-
- returnTc (BindStmt pat' exp' src_loc :
- consLetStmt (mkMonoBind dict_binds [] Recursive) stmts',
- lie_req `plusLIE` final_lie)
-
-tcStmts do_or_lc m (LetStmt binds : stmts) elt_ty
- = tcBindsAndThen -- No error context, but a binding group is
- combine -- rather a large thing for an error context anyway
- binds
- (tcStmts do_or_lc m stmts elt_ty)
- where
- combine is_rec binds' stmts' = consLetStmt (mkMonoBind binds' [] is_rec) stmts'
-
-
-isDoStmt DoStmt = True
-isDoStmt other = False
+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)
+