summaryrefslogtreecommitdiff
path: root/compiler/deSugar/DsArrows.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/deSugar/DsArrows.lhs')
-rw-r--r--compiler/deSugar/DsArrows.lhs1055
1 files changed, 1055 insertions, 0 deletions
diff --git a/compiler/deSugar/DsArrows.lhs b/compiler/deSugar/DsArrows.lhs
new file mode 100644
index 0000000000..111e0bccd0
--- /dev/null
+++ b/compiler/deSugar/DsArrows.lhs
@@ -0,0 +1,1055 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsArrows]{Desugaring arrow commands}
+
+\begin{code}
+module DsArrows ( dsProcExpr ) where
+
+#include "HsVersions.h"
+
+import Match ( matchSimply )
+import DsUtils ( mkErrorAppDs,
+ mkCoreTupTy, mkCoreTup, selectSimpleMatchVarL,
+ mkTupleCase, mkBigCoreTup, mkTupleType,
+ mkTupleExpr, mkTupleSelector,
+ dsSyntaxTable, lookupEvidence )
+import DsMonad
+
+import HsSyn
+import TcHsSyn ( hsPatType )
+
+-- NB: The desugarer, which straddles the source and Core worlds, sometimes
+-- needs to see source types (newtypes etc), and sometimes not
+-- So WATCH OUT; check each use of split*Ty functions.
+-- Sigh. This is a pain.
+
+import {-# SOURCE #-} DsExpr ( dsExpr, dsLExpr, dsLocalBinds )
+
+import TcType ( Type, tcSplitAppTy, mkFunTy )
+import Type ( mkTyConApp, funArgTy )
+import CoreSyn
+import CoreFVs ( exprFreeVars )
+import CoreUtils ( mkIfThenElse, bindNonRec, exprType )
+
+import Id ( Id, idType )
+import Name ( Name )
+import PrelInfo ( pAT_ERROR_ID )
+import DataCon ( dataConWrapId )
+import TysWiredIn ( tupleCon )
+import BasicTypes ( Boxity(..) )
+import PrelNames ( eitherTyConName, leftDataConName, rightDataConName,
+ arrAName, composeAName, firstAName,
+ appAName, choiceAName, loopAName )
+import Util ( mapAccumL )
+import Outputable
+
+import HsUtils ( collectPatBinders, collectPatsBinders )
+import VarSet ( IdSet, mkVarSet, varSetElems,
+ intersectVarSet, minusVarSet, extendVarSetList,
+ unionVarSet, unionVarSets, elemVarSet )
+import SrcLoc ( Located(..), unLoc, noLoc )
+\end{code}
+
+\begin{code}
+data DsCmdEnv = DsCmdEnv {
+ meth_binds :: [CoreBind],
+ arr_id, compose_id, first_id, app_id, choice_id, loop_id :: CoreExpr
+ }
+
+mkCmdEnv :: SyntaxTable Id -> DsM DsCmdEnv
+mkCmdEnv ids
+ = dsSyntaxTable ids `thenDs` \ (meth_binds, ds_meths) ->
+ return $ DsCmdEnv {
+ meth_binds = meth_binds,
+ arr_id = Var (lookupEvidence ds_meths arrAName),
+ compose_id = Var (lookupEvidence ds_meths composeAName),
+ first_id = Var (lookupEvidence ds_meths firstAName),
+ app_id = Var (lookupEvidence ds_meths appAName),
+ choice_id = Var (lookupEvidence ds_meths choiceAName),
+ loop_id = Var (lookupEvidence ds_meths loopAName)
+ }
+
+bindCmdEnv :: DsCmdEnv -> CoreExpr -> CoreExpr
+bindCmdEnv ids body = foldr Let body (meth_binds ids)
+
+-- arr :: forall b c. (b -> c) -> a b c
+do_arr :: DsCmdEnv -> Type -> Type -> CoreExpr -> CoreExpr
+do_arr ids b_ty c_ty f = mkApps (arr_id ids) [Type b_ty, Type c_ty, f]
+
+-- (>>>) :: forall b c d. a b c -> a c d -> a b d
+do_compose :: DsCmdEnv -> Type -> Type -> Type ->
+ CoreExpr -> CoreExpr -> CoreExpr
+do_compose ids b_ty c_ty d_ty f g
+ = mkApps (compose_id ids) [Type b_ty, Type c_ty, Type d_ty, f, g]
+
+-- first :: forall b c d. a b c -> a (b,d) (c,d)
+do_first :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr
+do_first ids b_ty c_ty d_ty f
+ = mkApps (first_id ids) [Type b_ty, Type c_ty, Type d_ty, f]
+
+-- app :: forall b c. a (a b c, b) c
+do_app :: DsCmdEnv -> Type -> Type -> CoreExpr
+do_app ids b_ty c_ty = mkApps (app_id ids) [Type b_ty, Type c_ty]
+
+-- (|||) :: forall b d c. a b d -> a c d -> a (Either b c) d
+-- note the swapping of d and c
+do_choice :: DsCmdEnv -> Type -> Type -> Type ->
+ CoreExpr -> CoreExpr -> CoreExpr
+do_choice ids b_ty c_ty d_ty f g
+ = mkApps (choice_id ids) [Type b_ty, Type d_ty, Type c_ty, f, g]
+
+-- loop :: forall b d c. a (b,d) (c,d) -> a b c
+-- note the swapping of d and c
+do_loop :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr
+do_loop ids b_ty c_ty d_ty f
+ = mkApps (loop_id ids) [Type b_ty, Type d_ty, Type c_ty, f]
+
+-- map_arrow (f :: b -> c) (g :: a c d) = arr f >>> g :: a b d
+do_map_arrow :: DsCmdEnv -> Type -> Type -> Type ->
+ CoreExpr -> CoreExpr -> CoreExpr
+do_map_arrow ids b_ty c_ty d_ty f c
+ = do_compose ids b_ty c_ty d_ty (do_arr ids b_ty c_ty f) c
+
+mkFailExpr :: HsMatchContext Id -> Type -> DsM CoreExpr
+mkFailExpr ctxt ty
+ = mkErrorAppDs pAT_ERROR_ID ty (matchContextErrString ctxt)
+
+-- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> b
+mkSndExpr :: Type -> Type -> DsM CoreExpr
+mkSndExpr a_ty b_ty
+ = newSysLocalDs a_ty `thenDs` \ a_var ->
+ newSysLocalDs b_ty `thenDs` \ b_var ->
+ newSysLocalDs (mkCorePairTy a_ty b_ty) `thenDs` \ pair_var ->
+ returnDs (Lam pair_var
+ (coreCasePair pair_var a_var b_var (Var b_var)))
+\end{code}
+
+Build case analysis of a tuple. This cannot be done in the DsM monad,
+because the list of variables is typically not yet defined.
+
+\begin{code}
+-- coreCaseTuple [u1..] v [x1..xn] body
+-- = case v of v { (x1, .., xn) -> body }
+-- But the matching may be nested if the tuple is very big
+
+coreCaseTuple :: UniqSupply -> Id -> [Id] -> CoreExpr -> CoreExpr
+coreCaseTuple uniqs scrut_var vars body
+ = mkTupleCase uniqs vars body scrut_var (Var scrut_var)
+
+coreCasePair :: Id -> Id -> Id -> CoreExpr -> CoreExpr
+coreCasePair scrut_var var1 var2 body
+ = Case (Var scrut_var) scrut_var (exprType body)
+ [(DataAlt (tupleCon Boxed 2), [var1, var2], body)]
+\end{code}
+
+\begin{code}
+mkCorePairTy :: Type -> Type -> Type
+mkCorePairTy t1 t2 = mkCoreTupTy [t1, t2]
+
+mkCorePairExpr :: CoreExpr -> CoreExpr -> CoreExpr
+mkCorePairExpr e1 e2 = mkCoreTup [e1, e2]
+\end{code}
+
+The input is divided into a local environment, which is a flat tuple
+(unless it's too big), and a stack, each element of which is paired
+with the stack in turn. In general, the input has the form
+
+ (...((x1,...,xn),s1),...sk)
+
+where xi are the environment values, and si the ones on the stack,
+with s1 being the "top", the first one to be matched with a lambda.
+
+\begin{code}
+envStackType :: [Id] -> [Type] -> Type
+envStackType ids stack_tys = foldl mkCorePairTy (mkTupleType ids) stack_tys
+
+----------------------------------------------
+-- buildEnvStack
+--
+-- (...((x1,...,xn),s1),...sk)
+
+buildEnvStack :: [Id] -> [Id] -> CoreExpr
+buildEnvStack env_ids stack_ids
+ = foldl mkCorePairExpr (mkTupleExpr env_ids) (map Var stack_ids)
+
+----------------------------------------------
+-- matchEnvStack
+--
+-- \ (...((x1,...,xn),s1),...sk) -> e
+-- =>
+-- \ zk ->
+-- case zk of (zk-1,sk) ->
+-- ...
+-- case z1 of (z0,s1) ->
+-- case z0 of (x1,...,xn) ->
+-- e
+
+matchEnvStack :: [Id] -- x1..xn
+ -> [Id] -- s1..sk
+ -> CoreExpr -- e
+ -> DsM CoreExpr
+matchEnvStack env_ids stack_ids body
+ = newUniqueSupply `thenDs` \ uniqs ->
+ newSysLocalDs (mkTupleType env_ids) `thenDs` \ tup_var ->
+ matchVarStack tup_var stack_ids
+ (coreCaseTuple uniqs tup_var env_ids body)
+
+
+----------------------------------------------
+-- matchVarStack
+--
+-- \ (...(z0,s1),...sk) -> e
+-- =>
+-- \ zk ->
+-- case zk of (zk-1,sk) ->
+-- ...
+-- case z1 of (z0,s1) ->
+-- e
+
+matchVarStack :: Id -- z0
+ -> [Id] -- s1..sk
+ -> CoreExpr -- e
+ -> DsM CoreExpr
+matchVarStack env_id [] body
+ = returnDs (Lam env_id body)
+matchVarStack env_id (stack_id:stack_ids) body
+ = newSysLocalDs (mkCorePairTy (idType env_id) (idType stack_id))
+ `thenDs` \ pair_id ->
+ matchVarStack pair_id stack_ids
+ (coreCasePair pair_id env_id stack_id body)
+\end{code}
+
+\begin{code}
+mkHsTupleExpr :: [HsExpr Id] -> HsExpr Id
+mkHsTupleExpr [e] = e
+mkHsTupleExpr es = ExplicitTuple (map noLoc es) Boxed
+
+mkHsPairExpr :: HsExpr Id -> HsExpr Id -> HsExpr Id
+mkHsPairExpr e1 e2 = mkHsTupleExpr [e1, e2]
+
+mkHsEnvStackExpr :: [Id] -> [Id] -> HsExpr Id
+mkHsEnvStackExpr env_ids stack_ids
+ = foldl mkHsPairExpr (mkHsTupleExpr (map HsVar env_ids)) (map HsVar stack_ids)
+\end{code}
+
+Translation of arrow abstraction
+
+\begin{code}
+
+-- A | xs |- c :: [] t' ---> c'
+-- --------------------------
+-- A |- proc p -> c :: a t t' ---> arr (\ p -> (xs)) >>> c'
+--
+-- where (xs) is the tuple of variables bound by p
+
+dsProcExpr
+ :: LPat Id
+ -> LHsCmdTop Id
+ -> DsM CoreExpr
+dsProcExpr pat (L _ (HsCmdTop cmd [] cmd_ty ids))
+ = mkCmdEnv ids `thenDs` \ meth_ids ->
+ let
+ locals = mkVarSet (collectPatBinders pat)
+ in
+ dsfixCmd meth_ids locals [] cmd_ty cmd
+ `thenDs` \ (core_cmd, free_vars, env_ids) ->
+ let
+ env_ty = mkTupleType env_ids
+ in
+ mkFailExpr ProcExpr env_ty `thenDs` \ fail_expr ->
+ selectSimpleMatchVarL pat `thenDs` \ var ->
+ matchSimply (Var var) ProcExpr pat (mkTupleExpr env_ids) fail_expr
+ `thenDs` \ match_code ->
+ let
+ pat_ty = hsPatType pat
+ proc_code = do_map_arrow meth_ids pat_ty env_ty cmd_ty
+ (Lam var match_code)
+ core_cmd
+ in
+ returnDs (bindCmdEnv meth_ids proc_code)
+\end{code}
+
+Translation of command judgements of the form
+
+ A | xs |- c :: [ts] t
+
+\begin{code}
+dsLCmd ids local_vars env_ids stack res_ty cmd
+ = dsCmd ids local_vars env_ids stack res_ty (unLoc cmd)
+
+dsCmd :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this command
+ -> [Id] -- list of vars in the input to this command
+ -- This is typically fed back,
+ -- so don't pull on it too early
+ -> [Type] -- type of the stack
+ -> Type -- return type of the command
+ -> HsCmd Id -- command to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet) -- set of local vars that occur free
+
+-- A |- f :: a (t*ts) t'
+-- A, xs |- arg :: t
+-- -----------------------------
+-- A | xs |- f -< arg :: [ts] t'
+--
+-- ---> arr (\ ((xs)*ts) -> (arg*ts)) >>> f
+
+dsCmd ids local_vars env_ids stack res_ty
+ (HsArrApp arrow arg arrow_ty HsFirstOrderApp _)
+ = let
+ (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty
+ (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty
+ env_ty = mkTupleType env_ids
+ in
+ dsLExpr arrow `thenDs` \ core_arrow ->
+ dsLExpr arg `thenDs` \ core_arg ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ matchEnvStack env_ids stack_ids
+ (foldl mkCorePairExpr core_arg (map Var stack_ids))
+ `thenDs` \ core_make_arg ->
+ returnDs (do_map_arrow ids
+ (envStackType env_ids stack)
+ arg_ty
+ res_ty
+ core_make_arg
+ core_arrow,
+ exprFreeVars core_arg `intersectVarSet` local_vars)
+
+-- A, xs |- f :: a (t*ts) t'
+-- A, xs |- arg :: t
+-- ------------------------------
+-- A | xs |- f -<< arg :: [ts] t'
+--
+-- ---> arr (\ ((xs)*ts) -> (f,(arg*ts))) >>> app
+
+dsCmd ids local_vars env_ids stack res_ty
+ (HsArrApp arrow arg arrow_ty HsHigherOrderApp _)
+ = let
+ (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty
+ (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty
+ env_ty = mkTupleType env_ids
+ in
+ dsLExpr arrow `thenDs` \ core_arrow ->
+ dsLExpr arg `thenDs` \ core_arg ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ matchEnvStack env_ids stack_ids
+ (mkCorePairExpr core_arrow
+ (foldl mkCorePairExpr core_arg (map Var stack_ids)))
+ `thenDs` \ core_make_pair ->
+ returnDs (do_map_arrow ids
+ (envStackType env_ids stack)
+ (mkCorePairTy arrow_ty arg_ty)
+ res_ty
+ core_make_pair
+ (do_app ids arg_ty res_ty),
+ (exprFreeVars core_arrow `unionVarSet` exprFreeVars core_arg)
+ `intersectVarSet` local_vars)
+
+-- A | ys |- c :: [t:ts] t'
+-- A, xs |- e :: t
+-- ------------------------
+-- A | xs |- c e :: [ts] t'
+--
+-- ---> arr (\ ((xs)*ts) -> let z = e in (((ys),z)*ts)) >>> c
+
+dsCmd ids local_vars env_ids stack res_ty (HsApp cmd arg)
+ = dsLExpr arg `thenDs` \ core_arg ->
+ let
+ arg_ty = exprType core_arg
+ stack' = arg_ty:stack
+ in
+ dsfixCmd ids local_vars stack' res_ty cmd
+ `thenDs` \ (core_cmd, free_vars, env_ids') ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ newSysLocalDs arg_ty `thenDs` \ arg_id ->
+ -- push the argument expression onto the stack
+ let
+ core_body = bindNonRec arg_id core_arg
+ (buildEnvStack env_ids' (arg_id:stack_ids))
+ in
+ -- match the environment and stack against the input
+ matchEnvStack env_ids stack_ids core_body
+ `thenDs` \ core_map ->
+ returnDs (do_map_arrow ids
+ (envStackType env_ids stack)
+ (envStackType env_ids' stack')
+ res_ty
+ core_map
+ core_cmd,
+ (exprFreeVars core_arg `intersectVarSet` local_vars)
+ `unionVarSet` free_vars)
+
+-- A | ys |- c :: [ts] t'
+-- -----------------------------------------------
+-- A | xs |- \ p1 ... pk -> c :: [t1:...:tk:ts] t'
+--
+-- ---> arr (\ ((((xs), p1), ... pk)*ts) -> ((ys)*ts)) >>> c
+
+dsCmd ids local_vars env_ids stack res_ty
+ (HsLam (MatchGroup [L _ (Match pats _ (GRHSs [L _ (GRHS [] body)] _ ))] _))
+ = let
+ pat_vars = mkVarSet (collectPatsBinders pats)
+ local_vars' = local_vars `unionVarSet` pat_vars
+ stack' = drop (length pats) stack
+ in
+ dsfixCmd ids local_vars' stack' res_ty body
+ `thenDs` \ (core_body, free_vars, env_ids') ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+
+ -- the expression is built from the inside out, so the actions
+ -- are presented in reverse order
+
+ let
+ (actual_ids, stack_ids') = splitAt (length pats) stack_ids
+ -- build a new environment, plus what's left of the stack
+ core_expr = buildEnvStack env_ids' stack_ids'
+ in_ty = envStackType env_ids stack
+ in_ty' = envStackType env_ids' stack'
+ in
+ mkFailExpr LambdaExpr in_ty' `thenDs` \ fail_expr ->
+ -- match the patterns against the top of the old stack
+ matchSimplys (map Var actual_ids) LambdaExpr pats core_expr fail_expr
+ `thenDs` \ match_code ->
+ -- match the old environment and stack against the input
+ matchEnvStack env_ids stack_ids match_code
+ `thenDs` \ select_code ->
+ returnDs (do_map_arrow ids in_ty in_ty' res_ty select_code core_body,
+ free_vars `minusVarSet` pat_vars)
+
+dsCmd ids local_vars env_ids stack res_ty (HsPar cmd)
+ = dsLCmd ids local_vars env_ids stack res_ty cmd
+
+-- A, xs |- e :: Bool
+-- A | xs1 |- c1 :: [ts] t
+-- A | xs2 |- c2 :: [ts] t
+-- ----------------------------------------
+-- A | xs |- if e then c1 else c2 :: [ts] t
+--
+-- ---> arr (\ ((xs)*ts) ->
+-- if e then Left ((xs1)*ts) else Right ((xs2)*ts)) >>>
+-- c1 ||| c2
+
+dsCmd ids local_vars env_ids stack res_ty (HsIf cond then_cmd else_cmd)
+ = dsLExpr cond `thenDs` \ core_cond ->
+ dsfixCmd ids local_vars stack res_ty then_cmd
+ `thenDs` \ (core_then, fvs_then, then_ids) ->
+ dsfixCmd ids local_vars stack res_ty else_cmd
+ `thenDs` \ (core_else, fvs_else, else_ids) ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ dsLookupTyCon eitherTyConName `thenDs` \ either_con ->
+ dsLookupDataCon leftDataConName `thenDs` \ left_con ->
+ dsLookupDataCon rightDataConName `thenDs` \ right_con ->
+ let
+ left_expr ty1 ty2 e = mkConApp left_con [Type ty1, Type ty2, e]
+ right_expr ty1 ty2 e = mkConApp right_con [Type ty1, Type ty2, e]
+
+ in_ty = envStackType env_ids stack
+ then_ty = envStackType then_ids stack
+ else_ty = envStackType else_ids stack
+ sum_ty = mkTyConApp either_con [then_ty, else_ty]
+ fvs_cond = exprFreeVars core_cond `intersectVarSet` local_vars
+ in
+ matchEnvStack env_ids stack_ids
+ (mkIfThenElse core_cond
+ (left_expr then_ty else_ty (buildEnvStack then_ids stack_ids))
+ (right_expr then_ty else_ty (buildEnvStack else_ids stack_ids)))
+ `thenDs` \ core_if ->
+ returnDs(do_map_arrow ids in_ty sum_ty res_ty
+ core_if
+ (do_choice ids then_ty else_ty res_ty core_then core_else),
+ fvs_cond `unionVarSet` fvs_then `unionVarSet` fvs_else)
+\end{code}
+
+Case commands are treated in much the same way as if commands
+(see above) except that there are more alternatives. For example
+
+ case e of { p1 -> c1; p2 -> c2; p3 -> c3 }
+
+is translated to
+
+ arr (\ ((xs)*ts) -> case e of
+ p1 -> (Left (Left (xs1)*ts))
+ p2 -> Left ((Right (xs2)*ts))
+ p3 -> Right ((xs3)*ts)) >>>
+ (c1 ||| c2) ||| c3
+
+The idea is to extract the commands from the case, build a balanced tree
+of choices, and replace the commands with expressions that build tagged
+tuples, obtaining a case expression that can be desugared normally.
+To build all this, we use quadruples decribing segments of the list of
+case bodies, containing the following fields:
+1. an IdSet containing the environment variables free in the case bodies
+2. a list of expressions of the form (Left|Right)* ((xs)*ts), to be put
+ into the case replacing the commands
+3. a sum type that is the common type of these expressions, and also the
+ input type of the arrow
+4. a CoreExpr for an arrow built by combining the translated command
+ bodies with |||.
+
+\begin{code}
+dsCmd ids local_vars env_ids stack res_ty (HsCase exp (MatchGroup matches match_ty))
+ = dsLExpr exp `thenDs` \ core_exp ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+
+ -- Extract and desugar the leaf commands in the case, building tuple
+ -- expressions that will (after tagging) replace these leaves
+
+ let
+ leaves = concatMap leavesMatch matches
+ make_branch (leaf, bound_vars)
+ = dsfixCmd ids (local_vars `unionVarSet` bound_vars) stack res_ty leaf
+ `thenDs` \ (core_leaf, fvs, leaf_ids) ->
+ returnDs (fvs `minusVarSet` bound_vars,
+ [noLoc $ mkHsEnvStackExpr leaf_ids stack_ids],
+ envStackType leaf_ids stack,
+ core_leaf)
+ in
+ mappM make_branch leaves `thenDs` \ branches ->
+ dsLookupTyCon eitherTyConName `thenDs` \ either_con ->
+ dsLookupDataCon leftDataConName `thenDs` \ left_con ->
+ dsLookupDataCon rightDataConName `thenDs` \ right_con ->
+ let
+ left_id = nlHsVar (dataConWrapId left_con)
+ right_id = nlHsVar (dataConWrapId right_con)
+ left_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ TyApp left_id [ty1, ty2]) e
+ right_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ TyApp right_id [ty1, ty2]) e
+
+ -- Prefix each tuple with a distinct series of Left's and Right's,
+ -- in a balanced way, keeping track of the types.
+
+ merge_branches (fvs1, builds1, in_ty1, core_exp1)
+ (fvs2, builds2, in_ty2, core_exp2)
+ = (fvs1 `unionVarSet` fvs2,
+ map (left_expr in_ty1 in_ty2) builds1 ++
+ map (right_expr in_ty1 in_ty2) builds2,
+ mkTyConApp either_con [in_ty1, in_ty2],
+ do_choice ids in_ty1 in_ty2 res_ty core_exp1 core_exp2)
+ (fvs_alts, leaves', sum_ty, core_choices)
+ = foldb merge_branches branches
+
+ -- Replace the commands in the case with these tagged tuples,
+ -- yielding a HsExpr Id we can feed to dsExpr.
+
+ (_, matches') = mapAccumL (replaceLeavesMatch res_ty) leaves' matches
+ in_ty = envStackType env_ids stack
+ fvs_exp = exprFreeVars core_exp `intersectVarSet` local_vars
+
+ pat_ty = funArgTy match_ty
+ match_ty' = mkFunTy pat_ty sum_ty
+ -- Note that we replace the HsCase result type by sum_ty,
+ -- which is the type of matches'
+ in
+ dsExpr (HsCase exp (MatchGroup matches' match_ty')) `thenDs` \ core_body ->
+ matchEnvStack env_ids stack_ids core_body
+ `thenDs` \ core_matches ->
+ returnDs(do_map_arrow ids in_ty sum_ty res_ty core_matches core_choices,
+ fvs_exp `unionVarSet` fvs_alts)
+
+-- A | ys |- c :: [ts] t
+-- ----------------------------------
+-- A | xs |- let binds in c :: [ts] t
+--
+-- ---> arr (\ ((xs)*ts) -> let binds in ((ys)*ts)) >>> c
+
+dsCmd ids local_vars env_ids stack res_ty (HsLet binds body)
+ = let
+ defined_vars = mkVarSet (map unLoc (collectLocalBinders binds))
+ local_vars' = local_vars `unionVarSet` defined_vars
+ in
+ dsfixCmd ids local_vars' stack res_ty body
+ `thenDs` \ (core_body, free_vars, env_ids') ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ -- build a new environment, plus the stack, using the let bindings
+ dsLocalBinds binds (buildEnvStack env_ids' stack_ids)
+ `thenDs` \ core_binds ->
+ -- match the old environment and stack against the input
+ matchEnvStack env_ids stack_ids core_binds
+ `thenDs` \ core_map ->
+ returnDs (do_map_arrow ids
+ (envStackType env_ids stack)
+ (envStackType env_ids' stack)
+ res_ty
+ core_map
+ core_body,
+ exprFreeVars core_binds `intersectVarSet` local_vars)
+
+dsCmd ids local_vars env_ids [] res_ty (HsDo _ctxt stmts body _)
+ = dsCmdDo ids local_vars env_ids res_ty stmts body
+
+-- A |- e :: forall e. a1 (e*ts1) t1 -> ... an (e*tsn) tn -> a (e*ts) t
+-- A | xs |- ci :: [tsi] ti
+-- -----------------------------------
+-- A | xs |- (|e c1 ... cn|) :: [ts] t ---> e [t_xs] c1 ... cn
+
+dsCmd _ids local_vars env_ids _stack _res_ty (HsArrForm op _ args)
+ = let
+ env_ty = mkTupleType env_ids
+ in
+ dsLExpr op `thenDs` \ core_op ->
+ mapAndUnzipDs (dsTrimCmdArg local_vars env_ids) args
+ `thenDs` \ (core_args, fv_sets) ->
+ returnDs (mkApps (App core_op (Type env_ty)) core_args,
+ unionVarSets fv_sets)
+
+-- A | ys |- c :: [ts] t (ys <= xs)
+-- ---------------------
+-- A | xs |- c :: [ts] t ---> arr_ts (\ (xs) -> (ys)) >>> c
+
+dsTrimCmdArg
+ :: IdSet -- set of local vars available to this command
+ -> [Id] -- list of vars in the input to this command
+ -> LHsCmdTop Id -- command argument to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet) -- set of local vars that occur free
+dsTrimCmdArg local_vars env_ids (L _ (HsCmdTop cmd stack cmd_ty ids))
+ = mkCmdEnv ids `thenDs` \ meth_ids ->
+ dsfixCmd meth_ids local_vars stack cmd_ty cmd
+ `thenDs` \ (core_cmd, free_vars, env_ids') ->
+ mappM newSysLocalDs stack `thenDs` \ stack_ids ->
+ matchEnvStack env_ids stack_ids (buildEnvStack env_ids' stack_ids)
+ `thenDs` \ trim_code ->
+ let
+ in_ty = envStackType env_ids stack
+ in_ty' = envStackType env_ids' stack
+ arg_code = if env_ids' == env_ids then core_cmd else
+ do_map_arrow meth_ids in_ty in_ty' cmd_ty trim_code core_cmd
+ in
+ returnDs (bindCmdEnv meth_ids arg_code, free_vars)
+
+-- Given A | xs |- c :: [ts] t, builds c with xs fed back.
+-- Typically needs to be prefixed with arr (\p -> ((xs)*ts))
+
+dsfixCmd
+ :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this command
+ -> [Type] -- type of the stack
+ -> Type -- return type of the command
+ -> LHsCmd Id -- command to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet, -- set of local vars that occur free
+ [Id]) -- set as a list, fed back
+dsfixCmd ids local_vars stack cmd_ty cmd
+ = fixDs (\ ~(_,_,env_ids') ->
+ dsLCmd ids local_vars env_ids' stack cmd_ty cmd
+ `thenDs` \ (core_cmd, free_vars) ->
+ returnDs (core_cmd, free_vars, varSetElems free_vars))
+
+\end{code}
+
+Translation of command judgements of the form
+
+ A | xs |- do { ss } :: [] t
+
+\begin{code}
+
+dsCmdDo :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this statement
+ -> [Id] -- list of vars in the input to this statement
+ -- This is typically fed back,
+ -- so don't pull on it too early
+ -> Type -- return type of the statement
+ -> [LStmt Id] -- statements to desugar
+ -> LHsExpr Id -- body
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet) -- set of local vars that occur free
+
+-- A | xs |- c :: [] t
+-- --------------------------
+-- A | xs |- do { c } :: [] t
+
+dsCmdDo ids local_vars env_ids res_ty [] body
+ = dsLCmd ids local_vars env_ids [] res_ty body
+
+dsCmdDo ids local_vars env_ids res_ty (stmt:stmts) body
+ = let
+ bound_vars = mkVarSet (map unLoc (collectLStmtBinders stmt))
+ local_vars' = local_vars `unionVarSet` bound_vars
+ in
+ fixDs (\ ~(_,_,env_ids') ->
+ dsCmdDo ids local_vars' env_ids' res_ty stmts body
+ `thenDs` \ (core_stmts, fv_stmts) ->
+ returnDs (core_stmts, fv_stmts, varSetElems fv_stmts))
+ `thenDs` \ (core_stmts, fv_stmts, env_ids') ->
+ dsCmdLStmt ids local_vars env_ids env_ids' stmt
+ `thenDs` \ (core_stmt, fv_stmt) ->
+ returnDs (do_compose ids
+ (mkTupleType env_ids)
+ (mkTupleType env_ids')
+ res_ty
+ core_stmt
+ core_stmts,
+ fv_stmt)
+
+\end{code}
+A statement maps one local environment to another, and is represented
+as an arrow from one tuple type to another. A statement sequence is
+translated to a composition of such arrows.
+\begin{code}
+dsCmdLStmt ids local_vars env_ids out_ids cmd
+ = dsCmdStmt ids local_vars env_ids out_ids (unLoc cmd)
+
+dsCmdStmt
+ :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this statement
+ -> [Id] -- list of vars in the input to this statement
+ -- This is typically fed back,
+ -- so don't pull on it too early
+ -> [Id] -- list of vars in the output of this statement
+ -> Stmt Id -- statement to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet) -- set of local vars that occur free
+
+-- A | xs1 |- c :: [] t
+-- A | xs' |- do { ss } :: [] t'
+-- ------------------------------
+-- A | xs |- do { c; ss } :: [] t'
+--
+-- ---> arr (\ (xs) -> ((xs1),(xs'))) >>> first c >>>
+-- arr snd >>> ss
+
+dsCmdStmt ids local_vars env_ids out_ids (ExprStmt cmd _ c_ty)
+ = dsfixCmd ids local_vars [] c_ty cmd
+ `thenDs` \ (core_cmd, fv_cmd, env_ids1) ->
+ matchEnvStack env_ids []
+ (mkCorePairExpr (mkTupleExpr env_ids1) (mkTupleExpr out_ids))
+ `thenDs` \ core_mux ->
+ let
+ in_ty = mkTupleType env_ids
+ in_ty1 = mkTupleType env_ids1
+ out_ty = mkTupleType out_ids
+ before_c_ty = mkCorePairTy in_ty1 out_ty
+ after_c_ty = mkCorePairTy c_ty out_ty
+ in
+ mkSndExpr c_ty out_ty `thenDs` \ snd_fn ->
+ returnDs (do_map_arrow ids in_ty before_c_ty out_ty core_mux $
+ do_compose ids before_c_ty after_c_ty out_ty
+ (do_first ids in_ty1 c_ty out_ty core_cmd) $
+ do_arr ids after_c_ty out_ty snd_fn,
+ extendVarSetList fv_cmd out_ids)
+ where
+
+-- A | xs1 |- c :: [] t
+-- A | xs' |- do { ss } :: [] t' xs2 = xs' - defs(p)
+-- -----------------------------------
+-- A | xs |- do { p <- c; ss } :: [] t'
+--
+-- ---> arr (\ (xs) -> ((xs1),(xs2))) >>> first c >>>
+-- arr (\ (p, (xs2)) -> (xs')) >>> ss
+--
+-- It would be simpler and more consistent to do this using second,
+-- but that's likely to be defined in terms of first.
+
+dsCmdStmt ids local_vars env_ids out_ids (BindStmt pat cmd _ _)
+ = dsfixCmd ids local_vars [] (hsPatType pat) cmd
+ `thenDs` \ (core_cmd, fv_cmd, env_ids1) ->
+ let
+ pat_ty = hsPatType pat
+ pat_vars = mkVarSet (collectPatBinders pat)
+ env_ids2 = varSetElems (mkVarSet out_ids `minusVarSet` pat_vars)
+ env_ty2 = mkTupleType env_ids2
+ in
+
+ -- multiplexing function
+ -- \ (xs) -> ((xs1),(xs2))
+
+ matchEnvStack env_ids []
+ (mkCorePairExpr (mkTupleExpr env_ids1) (mkTupleExpr env_ids2))
+ `thenDs` \ core_mux ->
+
+ -- projection function
+ -- \ (p, (xs2)) -> (zs)
+
+ newSysLocalDs env_ty2 `thenDs` \ env_id ->
+ newUniqueSupply `thenDs` \ uniqs ->
+ let
+ after_c_ty = mkCorePairTy pat_ty env_ty2
+ out_ty = mkTupleType out_ids
+ body_expr = coreCaseTuple uniqs env_id env_ids2 (mkTupleExpr out_ids)
+ in
+ mkFailExpr (StmtCtxt DoExpr) out_ty `thenDs` \ fail_expr ->
+ selectSimpleMatchVarL pat `thenDs` \ pat_id ->
+ matchSimply (Var pat_id) (StmtCtxt DoExpr) pat body_expr fail_expr
+ `thenDs` \ match_code ->
+ newSysLocalDs after_c_ty `thenDs` \ pair_id ->
+ let
+ proj_expr = Lam pair_id (coreCasePair pair_id pat_id env_id match_code)
+ in
+
+ -- put it all together
+ let
+ in_ty = mkTupleType env_ids
+ in_ty1 = mkTupleType env_ids1
+ in_ty2 = mkTupleType env_ids2
+ before_c_ty = mkCorePairTy in_ty1 in_ty2
+ in
+ returnDs (do_map_arrow ids in_ty before_c_ty out_ty core_mux $
+ do_compose ids before_c_ty after_c_ty out_ty
+ (do_first ids in_ty1 pat_ty in_ty2 core_cmd) $
+ do_arr ids after_c_ty out_ty proj_expr,
+ fv_cmd `unionVarSet` (mkVarSet out_ids `minusVarSet` pat_vars))
+
+-- A | xs' |- do { ss } :: [] t
+-- --------------------------------------
+-- A | xs |- do { let binds; ss } :: [] t
+--
+-- ---> arr (\ (xs) -> let binds in (xs')) >>> ss
+
+dsCmdStmt ids local_vars env_ids out_ids (LetStmt binds)
+ -- build a new environment using the let bindings
+ = dsLocalBinds binds (mkTupleExpr out_ids) `thenDs` \ core_binds ->
+ -- match the old environment against the input
+ matchEnvStack env_ids [] core_binds `thenDs` \ core_map ->
+ returnDs (do_arr ids
+ (mkTupleType env_ids)
+ (mkTupleType out_ids)
+ core_map,
+ exprFreeVars core_binds `intersectVarSet` local_vars)
+
+-- A | ys |- do { ss; returnA -< ((xs1), (ys2)) } :: [] ...
+-- A | xs' |- do { ss' } :: [] t
+-- ------------------------------------
+-- A | xs |- do { rec ss; ss' } :: [] t
+--
+-- xs1 = xs' /\ defs(ss)
+-- xs2 = xs' - defs(ss)
+-- ys1 = ys - defs(ss)
+-- ys2 = ys /\ defs(ss)
+--
+-- ---> arr (\(xs) -> ((ys1),(xs2))) >>>
+-- first (loop (arr (\((ys1),~(ys2)) -> (ys)) >>> ss)) >>>
+-- arr (\((xs1),(xs2)) -> (xs')) >>> ss'
+
+dsCmdStmt ids local_vars env_ids out_ids (RecStmt stmts later_ids rec_ids rhss binds)
+ = let -- ToDo: ****** binds not desugared; ROSS PLEASE FIX ********
+ env2_id_set = mkVarSet out_ids `minusVarSet` mkVarSet later_ids
+ env2_ids = varSetElems env2_id_set
+ env2_ty = mkTupleType env2_ids
+ in
+
+ -- post_loop_fn = \((later_ids),(env2_ids)) -> (out_ids)
+
+ newUniqueSupply `thenDs` \ uniqs ->
+ newSysLocalDs env2_ty `thenDs` \ env2_id ->
+ let
+ later_ty = mkTupleType later_ids
+ post_pair_ty = mkCorePairTy later_ty env2_ty
+ post_loop_body = coreCaseTuple uniqs env2_id env2_ids (mkTupleExpr out_ids)
+ in
+ matchEnvStack later_ids [env2_id] post_loop_body
+ `thenDs` \ post_loop_fn ->
+
+ --- loop (...)
+
+ dsRecCmd ids local_vars stmts later_ids rec_ids rhss
+ `thenDs` \ (core_loop, env1_id_set, env1_ids) ->
+
+ -- pre_loop_fn = \(env_ids) -> ((env1_ids),(env2_ids))
+
+ let
+ env1_ty = mkTupleType env1_ids
+ pre_pair_ty = mkCorePairTy env1_ty env2_ty
+ pre_loop_body = mkCorePairExpr (mkTupleExpr env1_ids)
+ (mkTupleExpr env2_ids)
+
+ in
+ matchEnvStack env_ids [] pre_loop_body
+ `thenDs` \ pre_loop_fn ->
+
+ -- arr pre_loop_fn >>> first (loop (...)) >>> arr post_loop_fn
+
+ let
+ env_ty = mkTupleType env_ids
+ out_ty = mkTupleType out_ids
+ core_body = do_map_arrow ids env_ty pre_pair_ty out_ty
+ pre_loop_fn
+ (do_compose ids pre_pair_ty post_pair_ty out_ty
+ (do_first ids env1_ty later_ty env2_ty
+ core_loop)
+ (do_arr ids post_pair_ty out_ty
+ post_loop_fn))
+ in
+ returnDs (core_body, env1_id_set `unionVarSet` env2_id_set)
+
+-- loop (arr (\ ((env1_ids), ~(rec_ids)) -> (env_ids)) >>>
+-- ss >>>
+-- arr (\ (out_ids) -> ((later_ids),(rhss))) >>>
+
+dsRecCmd ids local_vars stmts later_ids rec_ids rhss
+ = let
+ rec_id_set = mkVarSet rec_ids
+ out_ids = varSetElems (mkVarSet later_ids `unionVarSet` rec_id_set)
+ out_ty = mkTupleType out_ids
+ local_vars' = local_vars `unionVarSet` rec_id_set
+ in
+
+ -- mk_pair_fn = \ (out_ids) -> ((later_ids),(rhss))
+
+ mappM dsExpr rhss `thenDs` \ core_rhss ->
+ let
+ later_tuple = mkTupleExpr later_ids
+ later_ty = mkTupleType later_ids
+ rec_tuple = mkBigCoreTup core_rhss
+ rec_ty = mkTupleType rec_ids
+ out_pair = mkCorePairExpr later_tuple rec_tuple
+ out_pair_ty = mkCorePairTy later_ty rec_ty
+ in
+ matchEnvStack out_ids [] out_pair
+ `thenDs` \ mk_pair_fn ->
+
+ -- ss
+
+ dsfixCmdStmts ids local_vars' out_ids stmts
+ `thenDs` \ (core_stmts, fv_stmts, env_ids) ->
+
+ -- squash_pair_fn = \ ((env1_ids), ~(rec_ids)) -> (env_ids)
+
+ newSysLocalDs rec_ty `thenDs` \ rec_id ->
+ let
+ env1_id_set = fv_stmts `minusVarSet` rec_id_set
+ env1_ids = varSetElems env1_id_set
+ env1_ty = mkTupleType env1_ids
+ in_pair_ty = mkCorePairTy env1_ty rec_ty
+ core_body = mkBigCoreTup (map selectVar env_ids)
+ where
+ selectVar v
+ | v `elemVarSet` rec_id_set
+ = mkTupleSelector rec_ids v rec_id (Var rec_id)
+ | otherwise = Var v
+ in
+ matchEnvStack env1_ids [rec_id] core_body
+ `thenDs` \ squash_pair_fn ->
+
+ -- loop (arr squash_pair_fn >>> ss >>> arr mk_pair_fn)
+
+ let
+ env_ty = mkTupleType env_ids
+ core_loop = do_loop ids env1_ty later_ty rec_ty
+ (do_map_arrow ids in_pair_ty env_ty out_pair_ty
+ squash_pair_fn
+ (do_compose ids env_ty out_ty out_pair_ty
+ core_stmts
+ (do_arr ids out_ty out_pair_ty mk_pair_fn)))
+ in
+ returnDs (core_loop, env1_id_set, env1_ids)
+
+\end{code}
+A sequence of statements (as in a rec) is desugared to an arrow between
+two environments
+\begin{code}
+
+dsfixCmdStmts
+ :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this statement
+ -> [Id] -- output vars of these statements
+ -> [LStmt Id] -- statements to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet, -- set of local vars that occur free
+ [Id]) -- input vars
+
+dsfixCmdStmts ids local_vars out_ids stmts
+ = fixDs (\ ~(_,_,env_ids) ->
+ dsCmdStmts ids local_vars env_ids out_ids stmts
+ `thenDs` \ (core_stmts, fv_stmts) ->
+ returnDs (core_stmts, fv_stmts, varSetElems fv_stmts))
+
+dsCmdStmts
+ :: DsCmdEnv -- arrow combinators
+ -> IdSet -- set of local vars available to this statement
+ -> [Id] -- list of vars in the input to these statements
+ -> [Id] -- output vars of these statements
+ -> [LStmt Id] -- statements to desugar
+ -> DsM (CoreExpr, -- desugared expression
+ IdSet) -- set of local vars that occur free
+
+dsCmdStmts ids local_vars env_ids out_ids [stmt]
+ = dsCmdLStmt ids local_vars env_ids out_ids stmt
+
+dsCmdStmts ids local_vars env_ids out_ids (stmt:stmts)
+ = let
+ bound_vars = mkVarSet (map unLoc (collectLStmtBinders stmt))
+ local_vars' = local_vars `unionVarSet` bound_vars
+ in
+ dsfixCmdStmts ids local_vars' out_ids stmts
+ `thenDs` \ (core_stmts, fv_stmts, env_ids') ->
+ dsCmdLStmt ids local_vars env_ids env_ids' stmt
+ `thenDs` \ (core_stmt, fv_stmt) ->
+ returnDs (do_compose ids
+ (mkTupleType env_ids)
+ (mkTupleType env_ids')
+ (mkTupleType out_ids)
+ core_stmt
+ core_stmts,
+ fv_stmt)
+
+\end{code}
+
+Match a list of expressions against a list of patterns, left-to-right.
+
+\begin{code}
+matchSimplys :: [CoreExpr] -- Scrutinees
+ -> HsMatchContext Name -- Match kind
+ -> [LPat Id] -- Patterns they should match
+ -> CoreExpr -- Return this if they all match
+ -> CoreExpr -- Return this if they don't
+ -> DsM CoreExpr
+matchSimplys [] _ctxt [] result_expr _fail_expr = returnDs result_expr
+matchSimplys (exp:exps) ctxt (pat:pats) result_expr fail_expr
+ = matchSimplys exps ctxt pats result_expr fail_expr
+ `thenDs` \ match_code ->
+ matchSimply exp ctxt pat match_code fail_expr
+\end{code}
+
+List of leaf expressions, with set of variables bound in each
+
+\begin{code}
+leavesMatch :: LMatch Id -> [(LHsExpr Id, IdSet)]
+leavesMatch (L _ (Match pats _ (GRHSs grhss binds)))
+ = let
+ defined_vars = mkVarSet (collectPatsBinders pats)
+ `unionVarSet`
+ mkVarSet (map unLoc (collectLocalBinders binds))
+ in
+ [(expr,
+ mkVarSet (map unLoc (collectLStmtsBinders stmts))
+ `unionVarSet` defined_vars)
+ | L _ (GRHS stmts expr) <- grhss]
+\end{code}
+
+Replace the leaf commands in a match
+
+\begin{code}
+replaceLeavesMatch
+ :: Type -- new result type
+ -> [LHsExpr Id] -- replacement leaf expressions of that type
+ -> LMatch Id -- the matches of a case command
+ -> ([LHsExpr Id],-- remaining leaf expressions
+ LMatch Id) -- updated match
+replaceLeavesMatch res_ty leaves (L loc (Match pat mt (GRHSs grhss binds)))
+ = let
+ (leaves', grhss') = mapAccumL replaceLeavesGRHS leaves grhss
+ in
+ (leaves', L loc (Match pat mt (GRHSs grhss' binds)))
+
+replaceLeavesGRHS
+ :: [LHsExpr Id] -- replacement leaf expressions of that type
+ -> LGRHS Id -- rhss of a case command
+ -> ([LHsExpr Id],-- remaining leaf expressions
+ LGRHS Id) -- updated GRHS
+replaceLeavesGRHS (leaf:leaves) (L loc (GRHS stmts rhs))
+ = (leaves, L loc (GRHS stmts leaf))
+\end{code}
+
+Balanced fold of a non-empty list.
+
+\begin{code}
+foldb :: (a -> a -> a) -> [a] -> a
+foldb _ [] = error "foldb of empty list"
+foldb _ [x] = x
+foldb f xs = foldb f (fold_pairs xs)
+ where
+ fold_pairs [] = []
+ fold_pairs [x] = [x]
+ fold_pairs (x1:x2:xs) = f x1 x2:fold_pairs xs
+\end{code}