summaryrefslogtreecommitdiff
path: root/compiler/deSugar
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/deSugar')
-rw-r--r--compiler/deSugar/Check.lhs698
-rw-r--r--compiler/deSugar/Desugar.lhs298
-rw-r--r--compiler/deSugar/DsArrows.lhs1055
-rw-r--r--compiler/deSugar/DsBinds.lhs417
-rw-r--r--compiler/deSugar/DsCCall.lhs456
-rw-r--r--compiler/deSugar/DsExpr.hi-boot-55
-rw-r--r--compiler/deSugar/DsExpr.hi-boot-66
-rw-r--r--compiler/deSugar/DsExpr.lhs781
-rw-r--r--compiler/deSugar/DsExpr.lhs-boot11
-rw-r--r--compiler/deSugar/DsForeign.lhs646
-rw-r--r--compiler/deSugar/DsGRHSs.lhs128
-rw-r--r--compiler/deSugar/DsListComp.lhs516
-rw-r--r--compiler/deSugar/DsMeta.hs1732
-rw-r--r--compiler/deSugar/DsMonad.lhs285
-rw-r--r--compiler/deSugar/DsUtils.lhs884
-rw-r--r--compiler/deSugar/Match.hi-boot-56
-rw-r--r--compiler/deSugar/Match.hi-boot-627
-rw-r--r--compiler/deSugar/Match.lhs740
-rw-r--r--compiler/deSugar/Match.lhs-boot35
-rw-r--r--compiler/deSugar/MatchCon.lhs174
-rw-r--r--compiler/deSugar/MatchLit.lhs329
-rw-r--r--compiler/deSugar/deSugar.tex23
22 files changed, 9252 insertions, 0 deletions
diff --git a/compiler/deSugar/Check.lhs b/compiler/deSugar/Check.lhs
new file mode 100644
index 0000000000..9aac5ce777
--- /dev/null
+++ b/compiler/deSugar/Check.lhs
@@ -0,0 +1,698 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1997-1998
+%
+% Author: Juan J. Quintela <quintela@krilin.dc.fi.udc.es>
+\section{Module @Check@ in @deSugar@}
+
+\begin{code}
+
+
+module Check ( check , ExhaustivePat ) where
+
+
+import HsSyn
+import TcHsSyn ( hsPatType, mkVanillaTuplePat )
+import TcType ( tcTyConAppTyCon )
+import DsUtils ( EquationInfo(..), MatchResult(..),
+ CanItFail(..), firstPat )
+import MatchLit ( tidyLitPat, tidyNPat )
+import Id ( Id, idType )
+import DataCon ( DataCon, dataConTyCon, dataConOrigArgTys, dataConFieldLabels )
+import Name ( Name, mkInternalName, getOccName, isDataSymOcc,
+ getName, mkVarOccFS )
+import TysWiredIn
+import PrelNames ( unboundKey )
+import TyCon ( tyConDataCons, tupleTyConBoxity, isTupleTyCon )
+import BasicTypes ( Boxity(..) )
+import SrcLoc ( noSrcLoc, Located(..), unLoc, noLoc )
+import UniqSet
+import Util ( takeList, splitAtList, notNull )
+import Outputable
+import FastString
+
+#include "HsVersions.h"
+\end{code}
+
+This module performs checks about if one list of equations are:
+\begin{itemize}
+\item Overlapped
+\item Non exhaustive
+\end{itemize}
+To discover that we go through the list of equations in a tree-like fashion.
+
+If you like theory, a similar algorithm is described in:
+\begin{quotation}
+ {\em Two Techniques for Compiling Lazy Pattern Matching},
+ Luc Maranguet,
+ INRIA Rocquencourt (RR-2385, 1994)
+\end{quotation}
+The algorithm is based on the first technique, but there are some differences:
+\begin{itemize}
+\item We don't generate code
+\item We have constructors and literals (not only literals as in the
+ article)
+\item We don't use directions, we must select the columns from
+ left-to-right
+\end{itemize}
+(By the way the second technique is really similar to the one used in
+ @Match.lhs@ to generate code)
+
+This function takes the equations of a pattern and returns:
+\begin{itemize}
+\item The patterns that are not recognized
+\item The equations that are not overlapped
+\end{itemize}
+It simplify the patterns and then call @check'@ (the same semantics), and it
+needs to reconstruct the patterns again ....
+
+The problem appear with things like:
+\begin{verbatim}
+ f [x,y] = ....
+ f (x:xs) = .....
+\end{verbatim}
+We want to put the two patterns with the same syntax, (prefix form) and
+then all the constructors are equal:
+\begin{verbatim}
+ f (: x (: y [])) = ....
+ f (: x xs) = .....
+\end{verbatim}
+(more about that in @simplify_eqns@)
+
+We would prefer to have a @WarningPat@ of type @String@, but Strings and the
+Pretty Printer are not friends.
+
+We use @InPat@ in @WarningPat@ instead of @OutPat@
+because we need to print the
+warning messages in the same way they are introduced, i.e. if the user
+wrote:
+\begin{verbatim}
+ f [x,y] = ..
+\end{verbatim}
+He don't want a warning message written:
+\begin{verbatim}
+ f (: x (: y [])) ........
+\end{verbatim}
+Then we need to use InPats.
+\begin{quotation}
+ Juan Quintela 5 JUL 1998\\
+ User-friendliness and compiler writers are no friends.
+\end{quotation}
+
+\begin{code}
+type WarningPat = InPat Name
+type ExhaustivePat = ([WarningPat], [(Name, [HsLit])])
+type EqnNo = Int
+type EqnSet = UniqSet EqnNo
+
+
+check :: [EquationInfo] -> ([ExhaustivePat], [EquationInfo])
+ -- Second result is the shadowed equations
+check qs = (untidy_warns, shadowed_eqns)
+ where
+ (warns, used_nos) = check' ([1..] `zip` map simplify_eqn qs)
+ untidy_warns = map untidy_exhaustive warns
+ shadowed_eqns = [eqn | (eqn,i) <- qs `zip` [1..],
+ not (i `elementOfUniqSet` used_nos)]
+
+untidy_exhaustive :: ExhaustivePat -> ExhaustivePat
+untidy_exhaustive ([pat], messages) =
+ ([untidy_no_pars pat], map untidy_message messages)
+untidy_exhaustive (pats, messages) =
+ (map untidy_pars pats, map untidy_message messages)
+
+untidy_message :: (Name, [HsLit]) -> (Name, [HsLit])
+untidy_message (string, lits) = (string, map untidy_lit lits)
+\end{code}
+
+The function @untidy@ does the reverse work of the @simplify_pat@ funcion.
+
+\begin{code}
+
+type NeedPars = Bool
+
+untidy_no_pars :: WarningPat -> WarningPat
+untidy_no_pars p = untidy False p
+
+untidy_pars :: WarningPat -> WarningPat
+untidy_pars p = untidy True p
+
+untidy :: NeedPars -> WarningPat -> WarningPat
+untidy b (L loc p) = L loc (untidy' b p)
+ where
+ untidy' _ p@(WildPat _) = p
+ untidy' _ p@(VarPat name) = p
+ untidy' _ (LitPat lit) = LitPat (untidy_lit lit)
+ untidy' _ p@(ConPatIn name (PrefixCon [])) = p
+ untidy' b (ConPatIn name ps) = pars b (L loc (ConPatIn name (untidy_con ps)))
+ untidy' _ (ListPat pats ty) = ListPat (map untidy_no_pars pats) ty
+ untidy' _ (TuplePat pats box ty) = TuplePat (map untidy_no_pars pats) box ty
+ untidy' _ (PArrPat _ _) = panic "Check.untidy: Shouldn't get a parallel array here!"
+ untidy' _ (SigPatIn _ _) = panic "Check.untidy: SigPat"
+
+untidy_con (PrefixCon pats) = PrefixCon (map untidy_pars pats)
+untidy_con (InfixCon p1 p2) = InfixCon (untidy_pars p1) (untidy_pars p2)
+untidy_con (RecCon bs) = RecCon [(f,untidy_pars p) | (f,p) <- bs]
+
+pars :: NeedPars -> WarningPat -> Pat Name
+pars True p = ParPat p
+pars _ p = unLoc p
+
+untidy_lit :: HsLit -> HsLit
+untidy_lit (HsCharPrim c) = HsChar c
+untidy_lit lit = lit
+\end{code}
+
+This equation is the same that check, the only difference is that the
+boring work is done, that work needs to be done only once, this is
+the reason top have two functions, check is the external interface,
+@check'@ is called recursively.
+
+There are several cases:
+
+\begin{itemize}
+\item There are no equations: Everything is OK.
+\item There are only one equation, that can fail, and all the patterns are
+ variables. Then that equation is used and the same equation is
+ non-exhaustive.
+\item All the patterns are variables, and the match can fail, there are
+ more equations then the results is the result of the rest of equations
+ and this equation is used also.
+
+\item The general case, if all the patterns are variables (here the match
+ can't fail) then the result is that this equation is used and this
+ equation doesn't generate non-exhaustive cases.
+
+\item In the general case, there can exist literals ,constructors or only
+ vars in the first column, we actuate in consequence.
+
+\end{itemize}
+
+
+\begin{code}
+
+check' :: [(EqnNo, EquationInfo)]
+ -> ([ExhaustivePat], -- Pattern scheme that might not be matched at all
+ EqnSet) -- Eqns that are used (others are overlapped)
+
+check' [] = ([([],[])],emptyUniqSet)
+
+check' ((n, EqnInfo { eqn_pats = ps, eqn_rhs = MatchResult can_fail _ }) : rs)
+ | first_eqn_all_vars && case can_fail of { CantFail -> True; CanFail -> False }
+ = ([], unitUniqSet n) -- One eqn, which can't fail
+
+ | first_eqn_all_vars && null rs -- One eqn, but it can fail
+ = ([(takeList ps (repeat nlWildPat),[])], unitUniqSet n)
+
+ | first_eqn_all_vars -- Several eqns, first can fail
+ = (pats, addOneToUniqSet indexs n)
+ where
+ first_eqn_all_vars = all_vars ps
+ (pats,indexs) = check' rs
+
+check' qs
+ | literals = split_by_literals qs
+ | constructors = split_by_constructor qs
+ | only_vars = first_column_only_vars qs
+ | otherwise = pprPanic "Check.check': Not implemented :-(" (ppr first_pats)
+ where
+ -- Note: RecPats will have been simplified to ConPats
+ -- at this stage.
+ first_pats = ASSERT2( okGroup qs, pprGroup qs ) map firstPatN qs
+ constructors = any is_con first_pats
+ literals = any is_lit first_pats
+ only_vars = all is_var first_pats
+\end{code}
+
+Here begins the code to deal with literals, we need to split the matrix
+in different matrix beginning by each literal and a last matrix with the
+rest of values.
+
+\begin{code}
+split_by_literals :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat], EqnSet)
+split_by_literals qs = process_literals used_lits qs
+ where
+ used_lits = get_used_lits qs
+\end{code}
+
+@process_explicit_literals@ is a function that process each literal that appears
+in the column of the matrix.
+
+\begin{code}
+process_explicit_literals :: [HsLit] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+process_explicit_literals lits qs = (concat pats, unionManyUniqSets indexs)
+ where
+ pats_indexs = map (\x -> construct_literal_matrix x qs) lits
+ (pats,indexs) = unzip pats_indexs
+\end{code}
+
+
+@process_literals@ calls @process_explicit_literals@ to deal with the literals
+that appears in the matrix and deal also with the rest of the cases. It
+must be one Variable to be complete.
+
+\begin{code}
+
+process_literals :: [HsLit] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+process_literals used_lits qs
+ | null default_eqns = ([make_row_vars used_lits (head qs)] ++ pats,indexs)
+ | otherwise = (pats_default,indexs_default)
+ where
+ (pats,indexs) = process_explicit_literals used_lits qs
+ default_eqns = ASSERT2( okGroup qs, pprGroup qs )
+ [remove_var q | q <- qs, is_var (firstPatN q)]
+ (pats',indexs') = check' default_eqns
+ pats_default = [(nlWildPat:ps,constraints) | (ps,constraints) <- (pats')] ++ pats
+ indexs_default = unionUniqSets indexs' indexs
+\end{code}
+
+Here we have selected the literal and we will select all the equations that
+begins for that literal and create a new matrix.
+
+\begin{code}
+construct_literal_matrix :: HsLit -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+construct_literal_matrix lit qs =
+ (map (\ (xs,ys) -> (new_lit:xs,ys)) pats,indexs)
+ where
+ (pats,indexs) = (check' (remove_first_column_lit lit qs))
+ new_lit = nlLitPat lit
+
+remove_first_column_lit :: HsLit
+ -> [(EqnNo, EquationInfo)]
+ -> [(EqnNo, EquationInfo)]
+remove_first_column_lit lit qs
+ = ASSERT2( okGroup qs, pprGroup qs )
+ [(n, shift_pat eqn) | q@(n,eqn) <- qs, is_var_lit lit (firstPatN q)]
+ where
+ shift_pat eqn@(EqnInfo { eqn_pats = _:ps}) = eqn { eqn_pats = ps }
+ shift_pat eqn@(EqnInfo { eqn_pats = []}) = panic "Check.shift_var: no patterns"
+\end{code}
+
+This function splits the equations @qs@ in groups that deal with the
+same constructor.
+
+\begin{code}
+split_by_constructor :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat], EqnSet)
+split_by_constructor qs
+ | notNull unused_cons = need_default_case used_cons unused_cons qs
+ | otherwise = no_need_default_case used_cons qs
+ where
+ used_cons = get_used_cons qs
+ unused_cons = get_unused_cons used_cons
+\end{code}
+
+The first column of the patterns matrix only have vars, then there is
+nothing to do.
+
+\begin{code}
+first_column_only_vars :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+first_column_only_vars qs = (map (\ (xs,ys) -> (nlWildPat:xs,ys)) pats,indexs)
+ where
+ (pats, indexs) = check' (map remove_var qs)
+\end{code}
+
+This equation takes a matrix of patterns and split the equations by
+constructor, using all the constructors that appears in the first column
+of the pattern matching.
+
+We can need a default clause or not ...., it depends if we used all the
+constructors or not explicitly. The reasoning is similar to @process_literals@,
+the difference is that here the default case is not always needed.
+
+\begin{code}
+no_need_default_case :: [Pat Id] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+no_need_default_case cons qs = (concat pats, unionManyUniqSets indexs)
+ where
+ pats_indexs = map (\x -> construct_matrix x qs) cons
+ (pats,indexs) = unzip pats_indexs
+
+need_default_case :: [Pat Id] -> [DataCon] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+need_default_case used_cons unused_cons qs
+ | null default_eqns = (pats_default_no_eqns,indexs)
+ | otherwise = (pats_default,indexs_default)
+ where
+ (pats,indexs) = no_need_default_case used_cons qs
+ default_eqns = ASSERT2( okGroup qs, pprGroup qs )
+ [remove_var q | q <- qs, is_var (firstPatN q)]
+ (pats',indexs') = check' default_eqns
+ pats_default = [(make_whole_con c:ps,constraints) |
+ c <- unused_cons, (ps,constraints) <- pats'] ++ pats
+ new_wilds = make_row_vars_for_constructor (head qs)
+ pats_default_no_eqns = [(make_whole_con c:new_wilds,[]) | c <- unused_cons] ++ pats
+ indexs_default = unionUniqSets indexs' indexs
+
+construct_matrix :: Pat Id -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)
+construct_matrix con qs =
+ (map (make_con con) pats,indexs)
+ where
+ (pats,indexs) = (check' (remove_first_column con qs))
+\end{code}
+
+Here remove first column is more difficult that with literals due to the fact
+that constructors can have arguments.
+
+For instance, the matrix
+\begin{verbatim}
+ (: x xs) y
+ z y
+\end{verbatim}
+is transformed in:
+\begin{verbatim}
+ x xs y
+ _ _ y
+\end{verbatim}
+
+\begin{code}
+remove_first_column :: Pat Id -- Constructor
+ -> [(EqnNo, EquationInfo)]
+ -> [(EqnNo, EquationInfo)]
+remove_first_column (ConPatOut (L _ con) _ _ _ (PrefixCon con_pats) _) qs
+ = ASSERT2( okGroup qs, pprGroup qs )
+ [(n, shift_var eqn) | q@(n, eqn) <- qs, is_var_con con (firstPatN q)]
+ where
+ new_wilds = [WildPat (hsPatType arg_pat) | arg_pat <- con_pats]
+ shift_var eqn@(EqnInfo { eqn_pats = ConPatOut _ _ _ _ (PrefixCon ps') _ : ps})
+ = eqn { eqn_pats = map unLoc ps' ++ ps }
+ shift_var eqn@(EqnInfo { eqn_pats = WildPat _ : ps })
+ = eqn { eqn_pats = new_wilds ++ ps }
+ shift_var _ = panic "Check.Shift_var:No done"
+
+make_row_vars :: [HsLit] -> (EqnNo, EquationInfo) -> ExhaustivePat
+make_row_vars used_lits (_, EqnInfo { eqn_pats = pats})
+ = (nlVarPat new_var:takeList (tail pats) (repeat nlWildPat),[(new_var,used_lits)])
+ where
+ new_var = hash_x
+
+hash_x = mkInternalName unboundKey {- doesn't matter much -}
+ (mkVarOccFS FSLIT("#x"))
+ noSrcLoc
+
+make_row_vars_for_constructor :: (EqnNo, EquationInfo) -> [WarningPat]
+make_row_vars_for_constructor (_, EqnInfo { eqn_pats = pats})
+ = takeList (tail pats) (repeat nlWildPat)
+
+compare_cons :: Pat Id -> Pat Id -> Bool
+compare_cons (ConPatOut (L _ id1) _ _ _ _ _) (ConPatOut (L _ id2) _ _ _ _ _) = id1 == id2
+
+remove_dups :: [Pat Id] -> [Pat Id]
+remove_dups [] = []
+remove_dups (x:xs) | or (map (\y -> compare_cons x y) xs) = remove_dups xs
+ | otherwise = x : remove_dups xs
+
+get_used_cons :: [(EqnNo, EquationInfo)] -> [Pat Id]
+get_used_cons qs = remove_dups [pat | q <- qs, let pat = firstPatN q,
+ isConPatOut pat]
+
+isConPatOut (ConPatOut {}) = True
+isConPatOut other = False
+
+remove_dups' :: [HsLit] -> [HsLit]
+remove_dups' [] = []
+remove_dups' (x:xs) | x `elem` xs = remove_dups' xs
+ | otherwise = x : remove_dups' xs
+
+
+get_used_lits :: [(EqnNo, EquationInfo)] -> [HsLit]
+get_used_lits qs = remove_dups' all_literals
+ where
+ all_literals = get_used_lits' qs
+
+get_used_lits' :: [(EqnNo, EquationInfo)] -> [HsLit]
+get_used_lits' [] = []
+get_used_lits' (q:qs)
+ | Just lit <- get_lit (firstPatN q) = lit : get_used_lits' qs
+ | otherwise = get_used_lits qs
+
+get_lit :: Pat id -> Maybe HsLit
+-- Get a representative HsLit to stand for the OverLit
+-- It doesn't matter which one, because they will only be compared
+-- with other HsLits gotten in the same way
+get_lit (LitPat lit) = Just lit
+get_lit (NPat (HsIntegral i _) mb _ _) = Just (HsIntPrim (mb_neg mb i))
+get_lit (NPat (HsFractional f _) mb _ _) = Just (HsFloatPrim (mb_neg mb f))
+get_lit other_pat = Nothing
+
+mb_neg :: Num a => Maybe b -> a -> a
+mb_neg Nothing v = v
+mb_neg (Just _) v = -v
+
+get_unused_cons :: [Pat Id] -> [DataCon]
+get_unused_cons used_cons = unused_cons
+ where
+ (ConPatOut _ _ _ _ _ ty) = head used_cons
+ ty_con = tcTyConAppTyCon ty -- Newtype observable
+ all_cons = tyConDataCons ty_con
+ used_cons_as_id = map (\ (ConPatOut (L _ d) _ _ _ _ _) -> d) used_cons
+ unused_cons = uniqSetToList
+ (mkUniqSet all_cons `minusUniqSet` mkUniqSet used_cons_as_id)
+
+all_vars :: [Pat Id] -> Bool
+all_vars [] = True
+all_vars (WildPat _:ps) = all_vars ps
+all_vars _ = False
+
+remove_var :: (EqnNo, EquationInfo) -> (EqnNo, EquationInfo)
+remove_var (n, eqn@(EqnInfo { eqn_pats = WildPat _ : ps})) = (n, eqn { eqn_pats = ps })
+remove_var _ = panic "Check.remove_var: equation does not begin with a variable"
+
+-----------------------
+eqnPats :: (EqnNo, EquationInfo) -> [Pat Id]
+eqnPats (_, eqn) = eqn_pats eqn
+
+okGroup :: [(EqnNo, EquationInfo)] -> Bool
+-- True if all equations have at least one pattern, and
+-- all have the same number of patterns
+okGroup [] = True
+okGroup (e:es) = n_pats > 0 && and [length (eqnPats e) == n_pats | e <- es]
+ where
+ n_pats = length (eqnPats e)
+
+-- Half-baked print
+pprGroup es = vcat (map pprEqnInfo es)
+pprEqnInfo e = ppr (eqnPats e)
+
+
+firstPatN :: (EqnNo, EquationInfo) -> Pat Id
+firstPatN (_, eqn) = firstPat eqn
+
+is_con :: Pat Id -> Bool
+is_con (ConPatOut _ _ _ _ _ _) = True
+is_con _ = False
+
+is_lit :: Pat Id -> Bool
+is_lit (LitPat _) = True
+is_lit (NPat _ _ _ _) = True
+is_lit _ = False
+
+is_var :: Pat Id -> Bool
+is_var (WildPat _) = True
+is_var _ = False
+
+is_var_con :: DataCon -> Pat Id -> Bool
+is_var_con con (WildPat _) = True
+is_var_con con (ConPatOut (L _ id) _ _ _ _ _) | id == con = True
+is_var_con con _ = False
+
+is_var_lit :: HsLit -> Pat Id -> Bool
+is_var_lit lit (WildPat _) = True
+is_var_lit lit pat
+ | Just lit' <- get_lit pat = lit == lit'
+ | otherwise = False
+\end{code}
+
+The difference beteewn @make_con@ and @make_whole_con@ is that
+@make_wole_con@ creates a new constructor with all their arguments, and
+@make_con@ takes a list of argumntes, creates the contructor getting their
+arguments from the list. See where \fbox{\ ???\ } are used for details.
+
+We need to reconstruct the patterns (make the constructors infix and
+similar) at the same time that we create the constructors.
+
+You can tell tuple constructors using
+\begin{verbatim}
+ Id.isTupleCon
+\end{verbatim}
+You can see if one constructor is infix with this clearer code :-))))))))))
+\begin{verbatim}
+ Lex.isLexConSym (Name.occNameString (Name.getOccName con))
+\end{verbatim}
+
+ Rather clumsy but it works. (Simon Peyton Jones)
+
+
+We don't mind the @nilDataCon@ because it doesn't change the way to
+print the messsage, we are searching only for things like: @[1,2,3]@,
+not @x:xs@ ....
+
+In @reconstruct_pat@ we want to ``undo'' the work
+that we have done in @simplify_pat@.
+In particular:
+\begin{tabular}{lll}
+ @((,) x y)@ & returns to be & @(x, y)@
+\\ @((:) x xs)@ & returns to be & @(x:xs)@
+\\ @(x:(...:[])@ & returns to be & @[x,...]@
+\end{tabular}
+%
+The difficult case is the third one becouse we need to follow all the
+contructors until the @[]@ to know that we need to use the second case,
+not the second. \fbox{\ ???\ }
+%
+\begin{code}
+isInfixCon con = isDataSymOcc (getOccName con)
+
+is_nil (ConPatIn con (PrefixCon [])) = unLoc con == getName nilDataCon
+is_nil _ = False
+
+is_list (ListPat _ _) = True
+is_list _ = False
+
+return_list id q = id == consDataCon && (is_nil q || is_list q)
+
+make_list p q | is_nil q = ListPat [p] placeHolderType
+make_list p (ListPat ps ty) = ListPat (p:ps) ty
+make_list _ _ = panic "Check.make_list: Invalid argument"
+
+make_con :: Pat Id -> ExhaustivePat -> ExhaustivePat
+make_con (ConPatOut (L _ id) _ _ _ _ _) (lp:lq:ps, constraints)
+ | return_list id q = (noLoc (make_list lp q) : ps, constraints)
+ | isInfixCon id = (nlInfixConPat (getName id) lp lq : ps, constraints)
+ where q = unLoc lq
+
+make_con (ConPatOut (L _ id) _ _ _ (PrefixCon pats) ty) (ps, constraints)
+ | isTupleTyCon tc = (noLoc (TuplePat pats_con (tupleTyConBoxity tc) ty) : rest_pats, constraints)
+ | isPArrFakeCon id = (noLoc (PArrPat pats_con placeHolderType) : rest_pats, constraints)
+ | otherwise = (nlConPat name pats_con : rest_pats, constraints)
+ where
+ name = getName id
+ (pats_con, rest_pats) = splitAtList pats ps
+ tc = dataConTyCon id
+
+-- reconstruct parallel array pattern
+--
+-- * don't check for the type only; we need to make sure that we are really
+-- dealing with one of the fake constructors and not with the real
+-- representation
+
+make_whole_con :: DataCon -> WarningPat
+make_whole_con con | isInfixCon con = nlInfixConPat name nlWildPat nlWildPat
+ | otherwise = nlConPat name pats
+ where
+ name = getName con
+ pats = [nlWildPat | t <- dataConOrigArgTys con]
+\end{code}
+
+This equation makes the same thing as @tidy@ in @Match.lhs@, the
+difference is that here we can do all the tidy in one place and in the
+@Match@ tidy it must be done one column each time due to bookkeeping
+constraints.
+
+\begin{code}
+
+simplify_eqn :: EquationInfo -> EquationInfo
+simplify_eqn eqn = eqn { eqn_pats = map simplify_pat (eqn_pats eqn),
+ eqn_rhs = simplify_rhs (eqn_rhs eqn) }
+ where
+ -- Horrible hack. The simplify_pat stuff converts NPlusK pats to WildPats
+ -- which of course loses the info that they can fail to match. So we
+ -- stick in a CanFail as if it were a guard.
+ -- The Right Thing to do is for the whole system to treat NPlusK pats properly
+ simplify_rhs (MatchResult can_fail body)
+ | any has_nplusk_pat (eqn_pats eqn) = MatchResult CanFail body
+ | otherwise = MatchResult can_fail body
+
+has_nplusk_lpat :: LPat Id -> Bool
+has_nplusk_lpat (L _ p) = has_nplusk_pat p
+
+has_nplusk_pat :: Pat Id -> Bool
+has_nplusk_pat (NPlusKPat _ _ _ _) = True
+has_nplusk_pat (ParPat p) = has_nplusk_lpat p
+has_nplusk_pat (AsPat _ p) = has_nplusk_lpat p
+has_nplusk_pat (SigPatOut p _ ) = has_nplusk_lpat p
+has_nplusk_pat (ConPatOut _ _ _ _ ps ty) = any has_nplusk_lpat (hsConArgs ps)
+has_nplusk_pat (ListPat ps _) = any has_nplusk_lpat ps
+has_nplusk_pat (TuplePat ps _ _) = any has_nplusk_lpat ps
+has_nplusk_pat (PArrPat ps _) = any has_nplusk_lpat ps
+has_nplusk_pat (LazyPat p) = False -- Why?
+has_nplusk_pat (BangPat p) = has_nplusk_lpat p -- I think
+has_nplusk_pat p = False -- VarPat, VarPatOut, WildPat, LitPat, NPat, TypePat, DictPat
+
+simplify_lpat :: LPat Id -> LPat Id
+simplify_lpat p = fmap simplify_pat p
+
+simplify_pat :: Pat Id -> Pat Id
+simplify_pat pat@(WildPat gt) = pat
+simplify_pat (VarPat id) = WildPat (idType id)
+simplify_pat (VarPatOut id _) = WildPat (idType id) -- Ignore the bindings
+simplify_pat (ParPat p) = unLoc (simplify_lpat p)
+simplify_pat (LazyPat p) = unLoc (simplify_lpat p)
+simplify_pat (BangPat p) = unLoc (simplify_lpat p)
+simplify_pat (AsPat id p) = unLoc (simplify_lpat p)
+simplify_pat (SigPatOut p _) = unLoc (simplify_lpat p) -- I'm not sure this is right
+
+simplify_pat (ConPatOut (L loc id) tvs dicts binds ps ty)
+ = ConPatOut (L loc id) tvs dicts binds (simplify_con id ps) ty
+
+simplify_pat (ListPat ps ty) =
+ unLoc $ foldr (\ x y -> mkPrefixConPat consDataCon [x,y] list_ty)
+ (mkNilPat list_ty)
+ (map simplify_lpat ps)
+ where list_ty = mkListTy ty
+
+-- introduce fake parallel array constructors to be able to handle parallel
+-- arrays with the existing machinery for constructor pattern
+--
+simplify_pat (PArrPat ps ty)
+ = mk_simple_con_pat (parrFakeCon (length ps))
+ (PrefixCon (map simplify_lpat ps))
+ (mkPArrTy ty)
+
+simplify_pat (TuplePat ps boxity ty)
+ = mk_simple_con_pat (tupleCon boxity arity)
+ (PrefixCon (map simplify_lpat ps))
+ ty
+ where
+ arity = length ps
+
+-- unpack string patterns fully, so we can see when they overlap with
+-- each other, or even explicit lists of Chars.
+simplify_pat pat@(LitPat (HsString s)) =
+ foldr (\c pat -> mk_simple_con_pat consDataCon (PrefixCon [mk_char_lit c,noLoc pat]) stringTy)
+ (mk_simple_con_pat nilDataCon (PrefixCon []) stringTy) (unpackFS s)
+ where
+ mk_char_lit c = noLoc (mk_simple_con_pat charDataCon (PrefixCon [nlLitPat (HsCharPrim c)]) charTy)
+
+simplify_pat pat@(LitPat lit) = unLoc (tidyLitPat lit (noLoc pat))
+
+simplify_pat pat@(NPat lit mb_neg _ lit_ty) = unLoc (tidyNPat lit mb_neg lit_ty (noLoc pat))
+
+simplify_pat (NPlusKPat id hslit hsexpr1 hsexpr2)
+ = WildPat (idType (unLoc id))
+
+simplify_pat (DictPat dicts methods)
+ = case num_of_d_and_ms of
+ 0 -> simplify_pat (TuplePat [] Boxed unitTy)
+ 1 -> simplify_pat (head dict_and_method_pats)
+ _ -> simplify_pat (mkVanillaTuplePat (map noLoc dict_and_method_pats) Boxed)
+ where
+ num_of_d_and_ms = length dicts + length methods
+ dict_and_method_pats = map VarPat (dicts ++ methods)
+
+mk_simple_con_pat con args ty = ConPatOut (noLoc con) [] [] emptyLHsBinds args ty
+
+-----------------
+simplify_con con (PrefixCon ps) = PrefixCon (map simplify_lpat ps)
+simplify_con con (InfixCon p1 p2) = PrefixCon [simplify_lpat p1, simplify_lpat p2]
+simplify_con con (RecCon fs)
+ | null fs = PrefixCon [nlWildPat | t <- dataConOrigArgTys con]
+ -- Special case for null patterns; maybe not a record at all
+ | otherwise = PrefixCon (map (simplify_lpat.snd) all_pats)
+ where
+ -- pad out all the missing fields with WildPats.
+ field_pats = map (\ f -> (f, nlWildPat)) (dataConFieldLabels con)
+ all_pats = foldr (\ (id,p) acc -> insertNm (getName (unLoc id)) p acc)
+ field_pats fs
+
+ insertNm nm p [] = [(nm,p)]
+ insertNm nm p (x@(n,_):xs)
+ | nm == n = (nm,p):xs
+ | otherwise = x : insertNm nm p xs
+\end{code}
diff --git a/compiler/deSugar/Desugar.lhs b/compiler/deSugar/Desugar.lhs
new file mode 100644
index 0000000000..45dc113cc1
--- /dev/null
+++ b/compiler/deSugar/Desugar.lhs
@@ -0,0 +1,298 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[Desugar]{@deSugar@: the main function}
+
+\begin{code}
+module Desugar ( deSugar, deSugarExpr ) where
+
+#include "HsVersions.h"
+
+import DynFlags ( DynFlag(..), DynFlags(..), dopt, GhcMode(..) )
+import StaticFlags ( opt_SccProfilingOn )
+import DriverPhases ( isHsBoot )
+import HscTypes ( ModGuts(..), HscEnv(..),
+ Dependencies(..), ForeignStubs(..), TypeEnv, IsBootInterface )
+import HsSyn ( RuleDecl(..), RuleBndr(..), LHsExpr, LRuleDecl )
+import TcRnTypes ( TcGblEnv(..), ImportAvails(..) )
+import MkIface ( mkUsageInfo )
+import Id ( Id, setIdExported, idName )
+import Name ( Name, isExternalName, nameIsLocalOrFrom, nameOccName )
+import CoreSyn
+import PprCore ( pprRules, pprCoreExpr )
+import DsMonad
+import DsExpr ( dsLExpr )
+import DsBinds ( dsTopLHsBinds, decomposeRuleLhs, AutoScc(..) )
+import DsForeign ( dsForeigns )
+import DsExpr () -- Forces DsExpr to be compiled; DsBinds only
+ -- depends on DsExpr.hi-boot.
+import Module ( Module, moduleEnvElts, delModuleEnv, moduleFS )
+import RdrName ( GlobalRdrEnv )
+import NameSet
+import VarSet
+import Bag ( Bag, isEmptyBag, emptyBag )
+import Rules ( roughTopNames )
+import CoreLint ( showPass, endPass )
+import CoreFVs ( ruleRhsFreeVars, exprsFreeNames )
+import Packages ( PackageState(thPackageId), PackageIdH(..) )
+import ErrUtils ( doIfSet, dumpIfSet_dyn, printBagOfWarnings,
+ errorsFound, WarnMsg )
+import ListSetOps ( insertList )
+import Outputable
+import UniqSupply ( mkSplitUniqSupply )
+import SrcLoc ( Located(..) )
+import DATA_IOREF ( readIORef )
+import Maybes ( catMaybes )
+import FastString
+import Util ( sortLe )
+\end{code}
+
+%************************************************************************
+%* *
+%* The main function: deSugar
+%* *
+%************************************************************************
+
+\begin{code}
+deSugar :: HscEnv -> TcGblEnv -> IO (Bag WarnMsg, Maybe ModGuts)
+-- Can modify PCS by faulting in more declarations
+
+deSugar hsc_env
+ tcg_env@(TcGblEnv { tcg_mod = mod,
+ tcg_src = hsc_src,
+ tcg_type_env = type_env,
+ tcg_imports = imports,
+ tcg_home_mods = home_mods,
+ tcg_exports = exports,
+ tcg_dus = dus,
+ tcg_inst_uses = dfun_uses_var,
+ tcg_th_used = th_var,
+ tcg_keep = keep_var,
+ tcg_rdr_env = rdr_env,
+ tcg_fix_env = fix_env,
+ tcg_deprecs = deprecs,
+ tcg_binds = binds,
+ tcg_fords = fords,
+ tcg_rules = rules,
+ tcg_insts = insts })
+ = do { showPass dflags "Desugar"
+
+ -- Desugar the program
+ ; ((all_prs, ds_rules, ds_fords), warns)
+ <- case ghcMode (hsc_dflags hsc_env) of
+ JustTypecheck -> return (([], [], NoStubs), emptyBag)
+ _ -> initDs hsc_env mod rdr_env type_env $ do
+ { core_prs <- dsTopLHsBinds auto_scc binds
+ ; (ds_fords, foreign_prs) <- dsForeigns fords
+ ; let all_prs = foreign_prs ++ core_prs
+ local_bndrs = mkVarSet (map fst all_prs)
+ ; ds_rules <- mappM (dsRule mod local_bndrs) rules
+ ; return (all_prs, catMaybes ds_rules, ds_fords)
+ }
+
+ -- If warnings are considered errors, leave.
+ ; if errorsFound dflags (warns, emptyBag)
+ then return (warns, Nothing)
+ else do
+
+ { -- Add export flags to bindings
+ keep_alive <- readIORef keep_var
+ ; let final_prs = addExportFlags ghci_mode exports keep_alive
+ all_prs ds_rules
+ ds_binds = [Rec final_prs]
+ -- Notice that we put the whole lot in a big Rec, even the foreign binds
+ -- When compiling PrelFloat, which defines data Float = F# Float#
+ -- we want F# to be in scope in the foreign marshalling code!
+ -- You might think it doesn't matter, but the simplifier brings all top-level
+ -- things into the in-scope set before simplifying; so we get no unfolding for F#!
+
+ -- Lint result if necessary
+ ; endPass dflags "Desugar" Opt_D_dump_ds ds_binds
+
+ -- Dump output
+ ; doIfSet (dopt Opt_D_dump_ds dflags)
+ (printDump (ppr_ds_rules ds_rules))
+
+ ; dfun_uses <- readIORef dfun_uses_var -- What dfuns are used
+ ; th_used <- readIORef th_var -- Whether TH is used
+ ; let used_names = allUses dus `unionNameSets` dfun_uses
+ thPackage = thPackageId (pkgState dflags)
+ pkgs | ExtPackage th_id <- thPackage, th_used
+ = insertList th_id (imp_dep_pkgs imports)
+ | otherwise
+ = imp_dep_pkgs imports
+
+ dep_mods = moduleEnvElts (delModuleEnv (imp_dep_mods imports) mod)
+ -- M.hi-boot can be in the imp_dep_mods, but we must remove
+ -- it before recording the modules on which this one depends!
+ -- (We want to retain M.hi-boot in imp_dep_mods so that
+ -- loadHiBootInterface can see if M's direct imports depend
+ -- on M.hi-boot, and hence that we should do the hi-boot consistency
+ -- check.)
+
+ dir_imp_mods = imp_mods imports
+
+ ; usages <- mkUsageInfo hsc_env home_mods dir_imp_mods dep_mods used_names
+
+ ; let
+ -- Modules don't compare lexicographically usually,
+ -- but we want them to do so here.
+ le_mod :: Module -> Module -> Bool
+ le_mod m1 m2 = moduleFS m1 <= moduleFS m2
+ le_dep_mod :: (Module, IsBootInterface) -> (Module, IsBootInterface) -> Bool
+ le_dep_mod (m1,_) (m2,_) = m1 `le_mod` m2
+
+ deps = Deps { dep_mods = sortLe le_dep_mod dep_mods,
+ dep_pkgs = sortLe (<=) pkgs,
+ dep_orphs = sortLe le_mod (imp_orphs imports) }
+ -- sort to get into canonical order
+
+ mod_guts = ModGuts {
+ mg_module = mod,
+ mg_boot = isHsBoot hsc_src,
+ mg_exports = exports,
+ mg_deps = deps,
+ mg_home_mods = home_mods,
+ mg_usages = usages,
+ mg_dir_imps = [m | (m,_,_) <- moduleEnvElts dir_imp_mods],
+ mg_rdr_env = rdr_env,
+ mg_fix_env = fix_env,
+ mg_deprecs = deprecs,
+ mg_types = type_env,
+ mg_insts = insts,
+ mg_rules = ds_rules,
+ mg_binds = ds_binds,
+ mg_foreign = ds_fords }
+
+ ; return (warns, Just mod_guts)
+ }}
+
+ where
+ dflags = hsc_dflags hsc_env
+ ghci_mode = ghcMode (hsc_dflags hsc_env)
+ auto_scc | opt_SccProfilingOn = TopLevel
+ | otherwise = NoSccs
+
+deSugarExpr :: HscEnv
+ -> Module -> GlobalRdrEnv -> TypeEnv
+ -> LHsExpr Id
+ -> IO CoreExpr
+deSugarExpr hsc_env this_mod rdr_env type_env tc_expr
+ = do { showPass dflags "Desugar"
+ ; us <- mkSplitUniqSupply 'd'
+
+ -- Do desugaring
+ ; (core_expr, ds_warns) <- initDs hsc_env this_mod rdr_env type_env $
+ dsLExpr tc_expr
+
+ -- Display any warnings
+ -- Note: if -Werror is used, we don't signal an error here.
+ ; doIfSet (not (isEmptyBag ds_warns))
+ (printBagOfWarnings dflags ds_warns)
+
+ -- Dump output
+ ; dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (pprCoreExpr core_expr)
+
+ ; return core_expr
+ }
+ where
+ dflags = hsc_dflags hsc_env
+
+
+-- addExportFlags
+-- Set the no-discard flag if either
+-- a) the Id is exported
+-- b) it's mentioned in the RHS of an orphan rule
+-- c) it's in the keep-alive set
+--
+-- It means that the binding won't be discarded EVEN if the binding
+-- ends up being trivial (v = w) -- the simplifier would usually just
+-- substitute w for v throughout, but we don't apply the substitution to
+-- the rules (maybe we should?), so this substitution would make the rule
+-- bogus.
+
+-- You might wonder why exported Ids aren't already marked as such;
+-- it's just because the type checker is rather busy already and
+-- I didn't want to pass in yet another mapping.
+
+addExportFlags ghci_mode exports keep_alive prs rules
+ = [(add_export bndr, rhs) | (bndr,rhs) <- prs]
+ where
+ add_export bndr
+ | dont_discard bndr = setIdExported bndr
+ | otherwise = bndr
+
+ orph_rhs_fvs = unionVarSets [ ruleRhsFreeVars rule
+ | rule <- rules,
+ not (isLocalRule rule) ]
+ -- A non-local rule keeps alive the free vars of its right-hand side.
+ -- (A "non-local" is one whose head function is not locally defined.)
+ -- Local rules are (later, after gentle simplification)
+ -- attached to the Id, and that keeps the rhs free vars alive.
+
+ dont_discard bndr = is_exported name
+ || name `elemNameSet` keep_alive
+ || bndr `elemVarSet` orph_rhs_fvs
+ where
+ name = idName bndr
+
+ -- In interactive mode, we don't want to discard any top-level
+ -- entities at all (eg. do not inline them away during
+ -- simplification), and retain them all in the TypeEnv so they are
+ -- available from the command line.
+ --
+ -- isExternalName separates the user-defined top-level names from those
+ -- introduced by the type checker.
+ is_exported :: Name -> Bool
+ is_exported | ghci_mode == Interactive = isExternalName
+ | otherwise = (`elemNameSet` exports)
+
+ppr_ds_rules [] = empty
+ppr_ds_rules rules
+ = text "" $$ text "-------------- DESUGARED RULES -----------------" $$
+ pprRules rules
+\end{code}
+
+
+
+%************************************************************************
+%* *
+%* Desugaring transformation rules
+%* *
+%************************************************************************
+
+\begin{code}
+dsRule :: Module -> IdSet -> LRuleDecl Id -> DsM (Maybe CoreRule)
+dsRule mod in_scope (L loc (HsRule name act vars lhs tv_lhs rhs fv_rhs))
+ = putSrcSpanDs loc $
+ do { let bndrs = [var | RuleBndr (L _ var) <- vars]
+ ; lhs' <- dsLExpr lhs
+ ; rhs' <- dsLExpr rhs
+
+ ; case decomposeRuleLhs bndrs lhs' of {
+ Nothing -> do { dsWarn msg; return Nothing } ;
+ Just (bndrs', fn_id, args) -> do
+
+ -- Substitute the dict bindings eagerly,
+ -- and take the body apart into a (f args) form
+ { let local_rule = nameIsLocalOrFrom mod fn_name
+ -- NB we can't use isLocalId in the orphan test,
+ -- because isLocalId isn't true of class methods
+ fn_name = idName fn_id
+ lhs_names = fn_name : nameSetToList (exprsFreeNames args)
+ -- No need to delete bndrs, because
+ -- exprsFreeNames finds only External names
+ orph = case filter (nameIsLocalOrFrom mod) lhs_names of
+ (n:ns) -> Just (nameOccName n)
+ [] -> Nothing
+
+ rule = Rule { ru_name = name, ru_fn = fn_name, ru_act = act,
+ ru_bndrs = bndrs', ru_args = args, ru_rhs = rhs',
+ ru_rough = roughTopNames args,
+ ru_local = local_rule, ru_orph = orph }
+ ; return (Just rule)
+ } } }
+ where
+ msg = hang (ptext SLIT("RULE left-hand side too complicated to desugar; ignored"))
+ 2 (ppr lhs)
+\end{code}
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}
diff --git a/compiler/deSugar/DsBinds.lhs b/compiler/deSugar/DsBinds.lhs
new file mode 100644
index 0000000000..8f3006d0f3
--- /dev/null
+++ b/compiler/deSugar/DsBinds.lhs
@@ -0,0 +1,417 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsBinds]{Pattern-matching bindings (HsBinds and MonoBinds)}
+
+Handles @HsBinds@; those at the top level require different handling,
+in that the @Rec@/@NonRec@/etc structure is thrown away (whereas at
+lower levels it is preserved with @let@/@letrec@s).
+
+\begin{code}
+module DsBinds ( dsTopLHsBinds, dsLHsBinds, decomposeRuleLhs,
+ dsCoercion,
+ AutoScc(..)
+ ) where
+
+#include "HsVersions.h"
+
+
+import {-# SOURCE #-} DsExpr( dsLExpr, dsExpr )
+import {-# SOURCE #-} Match( matchWrapper )
+
+import DsMonad
+import DsGRHSs ( dsGuarded )
+import DsUtils
+
+import HsSyn -- lots of things
+import CoreSyn -- lots of things
+import CoreUtils ( exprType, mkInlineMe, mkSCC )
+
+import StaticFlags ( opt_AutoSccsOnAllToplevs,
+ opt_AutoSccsOnExportedToplevs )
+import OccurAnal ( occurAnalyseExpr )
+import CostCentre ( mkAutoCC, IsCafCC(..) )
+import Id ( Id, DictId, idType, idName, isExportedId, mkLocalId, setInlinePragma )
+import Rules ( addIdSpecialisations, mkLocalRule )
+import Var ( TyVar, Var, isGlobalId, setIdNotExported )
+import VarEnv
+import Type ( mkTyVarTy, substTyWith )
+import TysWiredIn ( voidTy )
+import Outputable
+import SrcLoc ( Located(..) )
+import Maybes ( isJust, catMaybes, orElse )
+import Bag ( bagToList )
+import BasicTypes ( Activation(..), InlineSpec(..), isAlwaysActive, defaultInlineSpec )
+import Monad ( foldM )
+import FastString ( mkFastString )
+import List ( (\\) )
+import Util ( mapSnd )
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[dsMonoBinds]{Desugaring a @MonoBinds@}
+%* *
+%************************************************************************
+
+\begin{code}
+dsTopLHsBinds :: AutoScc -> LHsBinds Id -> DsM [(Id,CoreExpr)]
+dsTopLHsBinds auto_scc binds = ds_lhs_binds auto_scc binds
+
+dsLHsBinds :: LHsBinds Id -> DsM [(Id,CoreExpr)]
+dsLHsBinds binds = ds_lhs_binds NoSccs binds
+
+
+------------------------
+ds_lhs_binds :: AutoScc -> LHsBinds Id -> DsM [(Id,CoreExpr)]
+ -- scc annotation policy (see below)
+ds_lhs_binds auto_scc binds = foldM (dsLHsBind auto_scc) [] (bagToList binds)
+
+dsLHsBind :: AutoScc
+ -> [(Id,CoreExpr)] -- Put this on the end (avoid quadratic append)
+ -> LHsBind Id
+ -> DsM [(Id,CoreExpr)] -- Result
+dsLHsBind auto_scc rest (L loc bind)
+ = putSrcSpanDs loc $ dsHsBind auto_scc rest bind
+
+dsHsBind :: AutoScc
+ -> [(Id,CoreExpr)] -- Put this on the end (avoid quadratic append)
+ -> HsBind Id
+ -> DsM [(Id,CoreExpr)] -- Result
+
+dsHsBind auto_scc rest (VarBind var expr)
+ = dsLExpr expr `thenDs` \ core_expr ->
+
+ -- Dictionary bindings are always VarMonoBinds, so
+ -- we only need do this here
+ addDictScc var core_expr `thenDs` \ core_expr' ->
+ returnDs ((var, core_expr') : rest)
+
+dsHsBind auto_scc rest (FunBind { fun_id = L _ fun, fun_matches = matches, fun_co_fn = co_fn })
+ = matchWrapper (FunRhs (idName fun)) matches `thenDs` \ (args, body) ->
+ dsCoercion co_fn (return (mkLams args body)) `thenDs` \ rhs ->
+ addAutoScc auto_scc (fun, rhs) `thenDs` \ pair ->
+ returnDs (pair : rest)
+
+dsHsBind auto_scc rest (PatBind { pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty })
+ = dsGuarded grhss ty `thenDs` \ body_expr ->
+ mkSelectorBinds pat body_expr `thenDs` \ sel_binds ->
+ mappM (addAutoScc auto_scc) sel_binds `thenDs` \ sel_binds ->
+ returnDs (sel_binds ++ rest)
+
+ -- Common special case: no type or dictionary abstraction
+ -- For the (rare) case when there are some mixed-up
+ -- dictionary bindings (for which a Rec is convenient)
+ -- we reply on the enclosing dsBind to wrap a Rec around.
+dsHsBind auto_scc rest (AbsBinds [] [] exports binds)
+ = ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs ->
+ let
+ core_prs' = addLocalInlines exports core_prs
+ exports' = [(global, Var local) | (_, global, local, _) <- exports]
+ in
+ returnDs (core_prs' ++ exports' ++ rest)
+
+ -- Another common case: one exported variable
+ -- Non-recursive bindings come through this way
+dsHsBind auto_scc rest
+ (AbsBinds all_tyvars dicts exports@[(tyvars, global, local, prags)] binds)
+ = ASSERT( all (`elem` tyvars) all_tyvars )
+ ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs ->
+ let
+ -- Always treat the binds as recursive, because the typechecker
+ -- makes rather mixed-up dictionary bindings
+ core_bind = Rec core_prs
+ in
+ mappM (dsSpec all_tyvars dicts tyvars global local core_bind)
+ prags `thenDs` \ mb_specs ->
+ let
+ (spec_binds, rules) = unzip (catMaybes mb_specs)
+ global' = addIdSpecialisations global rules
+ rhs' = mkLams tyvars $ mkLams dicts $ Let core_bind (Var local)
+ inl = case [inl | InlinePrag inl <- prags] of
+ [] -> defaultInlineSpec
+ (inl:_) -> inl
+ in
+ returnDs (addInlineInfo inl global' rhs' : spec_binds ++ rest)
+
+dsHsBind auto_scc rest (AbsBinds all_tyvars dicts exports binds)
+ = ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs ->
+ let
+ -- Rec because of mixed-up dictionary bindings
+ core_bind = Rec (addLocalInlines exports core_prs)
+
+ tup_expr = mkTupleExpr locals
+ tup_ty = exprType tup_expr
+ poly_tup_expr = mkLams all_tyvars $ mkLams dicts $
+ Let core_bind tup_expr
+ locals = [local | (_, _, local, _) <- exports]
+ local_tys = map idType locals
+ in
+ newSysLocalDs (exprType poly_tup_expr) `thenDs` \ poly_tup_id ->
+ let
+ dict_args = map Var dicts
+
+ mk_bind ((tyvars, global, local, prags), n) -- locals !! n == local
+ = -- Need to make fresh locals to bind in the selector, because
+ -- some of the tyvars will be bound to voidTy
+ newSysLocalsDs (map substitute local_tys) `thenDs` \ locals' ->
+ newSysLocalDs (substitute tup_ty) `thenDs` \ tup_id ->
+ mapM (dsSpec all_tyvars dicts tyvars global local core_bind)
+ prags `thenDs` \ mb_specs ->
+ let
+ (spec_binds, rules) = unzip (catMaybes mb_specs)
+ global' = addIdSpecialisations global rules
+ rhs = mkLams tyvars $ mkLams dicts $
+ mkTupleSelector locals' (locals' !! n) tup_id $
+ mkApps (mkTyApps (Var poly_tup_id) ty_args) dict_args
+ in
+ returnDs ((global', rhs) : spec_binds)
+ where
+ mk_ty_arg all_tyvar | all_tyvar `elem` tyvars = mkTyVarTy all_tyvar
+ | otherwise = voidTy
+ ty_args = map mk_ty_arg all_tyvars
+ substitute = substTyWith all_tyvars ty_args
+ in
+ mappM mk_bind (exports `zip` [0..]) `thenDs` \ export_binds_s ->
+ -- don't scc (auto-)annotate the tuple itself.
+
+ returnDs ((poly_tup_id, poly_tup_expr) : (concat export_binds_s ++ rest))
+
+dsSpec :: [TyVar] -> [DictId] -> [TyVar]
+ -> Id -> Id -- Global, local
+ -> CoreBind -> Prag
+ -> DsM (Maybe ((Id,CoreExpr), -- Binding for specialised Id
+ CoreRule)) -- Rule for the Global Id
+
+-- Example:
+-- f :: (Eq a, Ix b) => a -> b -> b
+-- {-# SPECIALISE f :: Ix b => Int -> b -> b #-}
+--
+-- AbsBinds [ab] [d1,d2] [([ab], f, f_mono, prags)] binds
+--
+-- SpecPrag (/\b.\(d:Ix b). f Int b dInt d)
+-- (forall b. Ix b => Int -> b -> b)
+--
+-- Rule: forall b,(d:Ix b). f Int b dInt d = f_spec b d
+--
+-- Spec bind: f_spec = Let f = /\ab \(d1:Eq a)(d2:Ix b). let binds in f_mono
+-- /\b.\(d:Ix b). in f Int b dInt d
+-- The idea is that f occurs just once, so it'll be
+-- inlined and specialised
+
+dsSpec all_tvs dicts tvs poly_id mono_id mono_bind (InlinePrag {})
+ = return Nothing
+
+dsSpec all_tvs dicts tvs poly_id mono_id mono_bind
+ (SpecPrag spec_expr spec_ty const_dicts inl)
+ = do { let poly_name = idName poly_id
+ ; spec_name <- newLocalName poly_name
+ ; ds_spec_expr <- dsExpr spec_expr
+ ; let (bndrs, body) = collectBinders ds_spec_expr
+ mb_lhs = decomposeRuleLhs (bndrs ++ const_dicts) body
+
+ ; case mb_lhs of
+ Nothing -> do { dsWarn msg; return Nothing }
+
+ Just (bndrs', var, args) -> return (Just (addInlineInfo inl spec_id spec_rhs, rule))
+ where
+ local_poly = setIdNotExported poly_id
+ -- Very important to make the 'f' non-exported,
+ -- else it won't be inlined!
+ spec_id = mkLocalId spec_name spec_ty
+ spec_rhs = Let (NonRec local_poly poly_f_body) ds_spec_expr
+ poly_f_body = mkLams (tvs ++ dicts) $
+ fix_up (Let mono_bind (Var mono_id))
+
+ -- Quantify over constant dicts on the LHS, since
+ -- their value depends only on their type
+ -- The ones we are interested in may even be imported
+ -- e.g. GHC.Base.dEqInt
+
+ rule = mkLocalRule (mkFastString ("SPEC " ++ showSDoc (ppr poly_name)))
+ AlwaysActive poly_name
+ bndrs' -- Includes constant dicts
+ args
+ (mkVarApps (Var spec_id) bndrs)
+ }
+ where
+ -- Bind to voidTy any of all_ptvs that aren't
+ -- relevant for this particular function
+ fix_up body | null void_tvs = body
+ | otherwise = mkTyApps (mkLams void_tvs body)
+ (map (const voidTy) void_tvs)
+ void_tvs = all_tvs \\ tvs
+
+ msg = hang (ptext SLIT("Specialisation too complicated to desugar; ignored"))
+ 2 (ppr spec_expr)
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Adding inline pragmas}
+%* *
+%************************************************************************
+
+\begin{code}
+decomposeRuleLhs :: [Var] -> CoreExpr -> Maybe ([Var], Id, [CoreExpr])
+-- Returns Nothing if the LHS isn't of the expected shape
+-- The argument 'all_bndrs' includes the "constant dicts" of the LHS,
+-- and they may be GlobalIds, which we can't forall-ify.
+-- So we substitute them out instead
+decomposeRuleLhs all_bndrs lhs
+ = go init_env (occurAnalyseExpr lhs) -- Occurrence analysis sorts out the dict
+ -- bindings so we know if they are recursive
+ where
+
+ -- all_bndrs may include top-level imported dicts,
+ -- imported things with a for-all.
+ -- So we localise them and subtitute them out
+ bndr_prs = [ (id, Var (localise id)) | id <- all_bndrs, isGlobalId id ]
+ localise d = mkLocalId (idName d) (idType d)
+
+ init_env = mkVarEnv bndr_prs
+ all_bndrs' = map subst_bndr all_bndrs
+ subst_bndr bndr = case lookupVarEnv init_env bndr of
+ Just (Var bndr') -> bndr'
+ Just other -> panic "decomposeRuleLhs"
+ Nothing -> bndr
+
+ -- Substitute dicts in the LHS args, so that there
+ -- aren't any lets getting in the way
+ -- Note that we substitute the function too; we might have this as
+ -- a LHS: let f71 = M.f Int in f71
+ go env (Let (NonRec dict rhs) body)
+ = go (extendVarEnv env dict (simpleSubst env rhs)) body
+ go env body
+ = case collectArgs (simpleSubst env body) of
+ (Var fn, args) -> Just (all_bndrs', fn, args)
+ other -> Nothing
+
+simpleSubst :: IdEnv CoreExpr -> CoreExpr -> CoreExpr
+-- Similar to CoreSubst.substExpr, except that
+-- (a) takes no account of capture; dictionary bindings use new names
+-- (b) can have a GlobalId (imported) in its domain
+-- (c) Ids only; no types are substituted
+
+simpleSubst subst expr
+ = go expr
+ where
+ go (Var v) = lookupVarEnv subst v `orElse` Var v
+ go (Type ty) = Type ty
+ go (Lit lit) = Lit lit
+ go (App fun arg) = App (go fun) (go arg)
+ go (Note note e) = Note note (go e)
+ go (Lam bndr body) = Lam bndr (go body)
+ go (Let (NonRec bndr rhs) body) = Let (NonRec bndr (go rhs)) (go body)
+ go (Let (Rec pairs) body) = Let (Rec (mapSnd go pairs)) (go body)
+ go (Case scrut bndr ty alts) = Case (go scrut) bndr ty
+ [(c,bs,go r) | (c,bs,r) <- alts]
+
+addLocalInlines exports core_prs
+ = map add_inline core_prs
+ where
+ add_inline (bndr,rhs) | Just inl <- lookupVarEnv inline_env bndr
+ = addInlineInfo inl bndr rhs
+ | otherwise
+ = (bndr,rhs)
+ inline_env = mkVarEnv [(mono_id, prag)
+ | (_, _, mono_id, prags) <- exports,
+ InlinePrag prag <- prags]
+
+addInlineInfo :: InlineSpec -> Id -> CoreExpr -> (Id,CoreExpr)
+addInlineInfo (Inline phase is_inline) bndr rhs
+ = (attach_phase bndr phase, wrap_inline is_inline rhs)
+ where
+ attach_phase bndr phase
+ | isAlwaysActive phase = bndr -- Default phase
+ | otherwise = bndr `setInlinePragma` phase
+
+ wrap_inline True body = mkInlineMe body
+ wrap_inline False body = body
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[addAutoScc]{Adding automatic sccs}
+%* *
+%************************************************************************
+
+\begin{code}
+data AutoScc
+ = TopLevel
+ | TopLevelAddSccs (Id -> Maybe Id)
+ | NoSccs
+
+addSccs :: AutoScc -> [(a,Id,Id,[Prag])] -> AutoScc
+addSccs auto_scc@(TopLevelAddSccs _) exports = auto_scc
+addSccs NoSccs exports = NoSccs
+addSccs TopLevel exports
+ = TopLevelAddSccs (\id -> case [ exp | (_,exp,loc,_) <- exports, loc == id ] of
+ (exp:_) | opt_AutoSccsOnAllToplevs ||
+ (isExportedId exp &&
+ opt_AutoSccsOnExportedToplevs)
+ -> Just exp
+ _ -> Nothing)
+
+addAutoScc :: AutoScc -- if needs be, decorate toplevs?
+ -> (Id, CoreExpr)
+ -> DsM (Id, CoreExpr)
+
+addAutoScc (TopLevelAddSccs auto_scc_fn) pair@(bndr, core_expr)
+ | do_auto_scc
+ = getModuleDs `thenDs` \ mod ->
+ returnDs (bndr, mkSCC (mkAutoCC top_bndr mod NotCafCC) core_expr)
+ where do_auto_scc = isJust maybe_auto_scc
+ maybe_auto_scc = auto_scc_fn bndr
+ (Just top_bndr) = maybe_auto_scc
+
+addAutoScc _ pair
+ = returnDs pair
+\end{code}
+
+If profiling and dealing with a dict binding,
+wrap the dict in @_scc_ DICT <dict>@:
+
+\begin{code}
+addDictScc var rhs = returnDs rhs
+
+{- DISABLED for now (need to somehow make up a name for the scc) -- SDM
+ | not ( opt_SccProfilingOn && opt_AutoSccsOnDicts)
+ || not (isDictId var)
+ = returnDs rhs -- That's easy: do nothing
+
+ | otherwise
+ = getModuleAndGroupDs `thenDs` \ (mod, grp) ->
+ -- ToDo: do -dicts-all flag (mark dict things with individual CCs)
+ returnDs (Note (SCC (mkAllDictsCC mod grp False)) rhs)
+-}
+\end{code}
+
+
+%************************************************************************
+%* *
+ Desugaring coercions
+%* *
+%************************************************************************
+
+
+\begin{code}
+dsCoercion :: ExprCoFn -> DsM CoreExpr -> DsM CoreExpr
+dsCoercion CoHole thing_inside = thing_inside
+dsCoercion (CoCompose c1 c2) thing_inside = dsCoercion c1 (dsCoercion c2 thing_inside)
+dsCoercion (CoLams ids c) thing_inside = do { expr <- dsCoercion c thing_inside
+ ; return (mkLams ids expr) }
+dsCoercion (CoTyLams tvs c) thing_inside = do { expr <- dsCoercion c thing_inside
+ ; return (mkLams tvs expr) }
+dsCoercion (CoApps c ids) thing_inside = do { expr <- dsCoercion c thing_inside
+ ; return (mkVarApps expr ids) }
+dsCoercion (CoTyApps c tys) thing_inside = do { expr <- dsCoercion c thing_inside
+ ; return (mkTyApps expr tys) }
+dsCoercion (CoLet bs c) thing_inside = do { prs <- dsLHsBinds bs
+ ; expr <- dsCoercion c thing_inside
+ ; return (Let (Rec prs) expr) }
+\end{code}
+
+
diff --git a/compiler/deSugar/DsCCall.lhs b/compiler/deSugar/DsCCall.lhs
new file mode 100644
index 0000000000..3554197fb8
--- /dev/null
+++ b/compiler/deSugar/DsCCall.lhs
@@ -0,0 +1,456 @@
+%
+% (c) The AQUA Project, Glasgow University, 1994-1998
+%
+\section[DsCCall]{Desugaring C calls}
+
+\begin{code}
+module DsCCall
+ ( dsCCall
+ , mkFCall
+ , unboxArg
+ , boxResult
+ , resultWrapper
+ ) where
+
+#include "HsVersions.h"
+
+
+import CoreSyn
+
+import DsMonad
+
+import CoreUtils ( exprType, coreAltType, mkCoerce2 )
+import Id ( Id, mkWildId )
+import MkId ( mkFCallId, realWorldPrimId, mkPrimOpId )
+import Maybes ( maybeToBool )
+import ForeignCall ( ForeignCall(..), CCallSpec(..), CCallTarget(..), Safety,
+ CCallConv(..), CLabelString )
+import DataCon ( splitProductType_maybe, dataConSourceArity, dataConWrapId )
+
+import TcType ( tcSplitTyConApp_maybe )
+import Type ( Type, isUnLiftedType, mkFunTys, mkFunTy,
+ tyVarsOfType, mkForAllTys, mkTyConApp,
+ isPrimitiveType, splitTyConApp_maybe,
+ splitRecNewType_maybe, splitForAllTy_maybe,
+ isUnboxedTupleType
+ )
+
+import PrimOp ( PrimOp(..) )
+import TysPrim ( realWorldStatePrimTy, intPrimTy,
+ byteArrayPrimTyCon, mutableByteArrayPrimTyCon,
+ addrPrimTy
+ )
+import TyCon ( TyCon, tyConDataCons, tyConName )
+import TysWiredIn ( unitDataConId,
+ unboxedSingletonDataCon, unboxedPairDataCon,
+ unboxedSingletonTyCon, unboxedPairTyCon,
+ trueDataCon, falseDataCon,
+ trueDataConId, falseDataConId,
+ listTyCon, charTyCon, boolTy,
+ tupleTyCon, tupleCon
+ )
+import BasicTypes ( Boxity(..) )
+import Literal ( mkMachInt )
+import PrelNames ( Unique, hasKey, ioTyConKey, boolTyConKey, unitTyConKey,
+ int8TyConKey, int16TyConKey, int32TyConKey,
+ word8TyConKey, word16TyConKey, word32TyConKey
+ -- dotnet interop
+ , marshalStringName, unmarshalStringName
+ , marshalObjectName, unmarshalObjectName
+ , objectTyConName
+ )
+import VarSet ( varSetElems )
+import Constants ( wORD_SIZE)
+import Outputable
+
+#ifdef DEBUG
+import TypeRep
+#endif
+
+\end{code}
+
+Desugaring of @ccall@s consists of adding some state manipulation,
+unboxing any boxed primitive arguments and boxing the result if
+desired.
+
+The state stuff just consists of adding in
+@PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
+
+The unboxing is straightforward, as all information needed to unbox is
+available from the type. For each boxed-primitive argument, we
+transform:
+\begin{verbatim}
+ _ccall_ foo [ r, t1, ... tm ] e1 ... em
+ |
+ |
+ V
+ case e1 of { T1# x1# ->
+ ...
+ case em of { Tm# xm# -> xm#
+ ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
+ } ... }
+\end{verbatim}
+
+The reboxing of a @_ccall_@ result is a bit tricker: the types don't
+contain information about the state-pairing functions so we have to
+keep a list of \tr{(type, s-p-function)} pairs. We transform as
+follows:
+\begin{verbatim}
+ ccall# foo [ r, t1#, ... tm# ] e1# ... em#
+ |
+ |
+ V
+ \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
+ (StateAnd<r># result# state#) -> (R# result#, realWorld#)
+\end{verbatim}
+
+\begin{code}
+dsCCall :: CLabelString -- C routine to invoke
+ -> [CoreExpr] -- Arguments (desugared)
+ -> Safety -- Safety of the call
+ -> Type -- Type of the result: IO t
+ -> DsM CoreExpr
+
+dsCCall lbl args may_gc result_ty
+ = mapAndUnzipDs unboxArg args `thenDs` \ (unboxed_args, arg_wrappers) ->
+ boxResult id Nothing result_ty `thenDs` \ (ccall_result_ty, res_wrapper) ->
+ newUnique `thenDs` \ uniq ->
+ let
+ target = StaticTarget lbl
+ the_fcall = CCall (CCallSpec target CCallConv may_gc)
+ the_prim_app = mkFCall uniq the_fcall unboxed_args ccall_result_ty
+ in
+ returnDs (foldr ($) (res_wrapper the_prim_app) arg_wrappers)
+
+mkFCall :: Unique -> ForeignCall
+ -> [CoreExpr] -- Args
+ -> Type -- Result type
+ -> CoreExpr
+-- Construct the ccall. The only tricky bit is that the ccall Id should have
+-- no free vars, so if any of the arg tys do we must give it a polymorphic type.
+-- [I forget *why* it should have no free vars!]
+-- For example:
+-- mkCCall ... [s::StablePtr (a->b), x::Addr, c::Char]
+--
+-- Here we build a ccall thus
+-- (ccallid::(forall a b. StablePtr (a -> b) -> Addr -> Char -> IO Addr))
+-- a b s x c
+mkFCall uniq the_fcall val_args res_ty
+ = mkApps (mkVarApps (Var the_fcall_id) tyvars) val_args
+ where
+ arg_tys = map exprType val_args
+ body_ty = (mkFunTys arg_tys res_ty)
+ tyvars = varSetElems (tyVarsOfType body_ty)
+ ty = mkForAllTys tyvars body_ty
+ the_fcall_id = mkFCallId uniq the_fcall ty
+\end{code}
+
+\begin{code}
+unboxArg :: CoreExpr -- The supplied argument
+ -> DsM (CoreExpr, -- To pass as the actual argument
+ CoreExpr -> CoreExpr -- Wrapper to unbox the arg
+ )
+-- Example: if the arg is e::Int, unboxArg will return
+-- (x#::Int#, \W. case x of I# x# -> W)
+-- where W is a CoreExpr that probably mentions x#
+
+unboxArg arg
+ -- Primtive types: nothing to unbox
+ | isPrimitiveType arg_ty
+ = returnDs (arg, \body -> body)
+
+ -- Recursive newtypes
+ | Just rep_ty <- splitRecNewType_maybe arg_ty
+ = unboxArg (mkCoerce2 rep_ty arg_ty arg)
+
+ -- Booleans
+ | Just (tc,_) <- splitTyConApp_maybe arg_ty,
+ tc `hasKey` boolTyConKey
+ = newSysLocalDs intPrimTy `thenDs` \ prim_arg ->
+ returnDs (Var prim_arg,
+ \ body -> Case (Case arg (mkWildId arg_ty) intPrimTy
+ [(DataAlt falseDataCon,[],mkIntLit 0),
+ (DataAlt trueDataCon, [],mkIntLit 1)])
+ -- In increasing tag order!
+ prim_arg
+ (exprType body)
+ [(DEFAULT,[],body)])
+
+ -- Data types with a single constructor, which has a single, primitive-typed arg
+ -- This deals with Int, Float etc; also Ptr, ForeignPtr
+ | is_product_type && data_con_arity == 1
+ = ASSERT2(isUnLiftedType data_con_arg_ty1, pprType arg_ty)
+ -- Typechecker ensures this
+ newSysLocalDs arg_ty `thenDs` \ case_bndr ->
+ newSysLocalDs data_con_arg_ty1 `thenDs` \ prim_arg ->
+ returnDs (Var prim_arg,
+ \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,[prim_arg],body)]
+ )
+
+ -- Byte-arrays, both mutable and otherwise; hack warning
+ -- We're looking for values of type ByteArray, MutableByteArray
+ -- data ByteArray ix = ByteArray ix ix ByteArray#
+ -- data MutableByteArray s ix = MutableByteArray ix ix (MutableByteArray# s)
+ | is_product_type &&
+ data_con_arity == 3 &&
+ maybeToBool maybe_arg3_tycon &&
+ (arg3_tycon == byteArrayPrimTyCon ||
+ arg3_tycon == mutableByteArrayPrimTyCon)
+ = newSysLocalDs arg_ty `thenDs` \ case_bndr ->
+ newSysLocalsDs data_con_arg_tys `thenDs` \ vars@[l_var, r_var, arr_cts_var] ->
+ returnDs (Var arr_cts_var,
+ \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,vars,body)]
+
+ )
+
+ | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
+ tc == listTyCon,
+ Just (cc,[]) <- splitTyConApp_maybe arg_ty,
+ cc == charTyCon
+ -- String; dotnet only
+ = dsLookupGlobalId marshalStringName `thenDs` \ unpack_id ->
+ newSysLocalDs addrPrimTy `thenDs` \ prim_string ->
+ returnDs (Var prim_string,
+ \ body ->
+ let
+ io_ty = exprType body
+ (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
+ in
+ mkApps (Var unpack_id)
+ [ Type io_arg
+ , arg
+ , Lam prim_string body
+ ])
+ | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
+ tyConName tc == objectTyConName
+ -- Object; dotnet only
+ = dsLookupGlobalId marshalObjectName `thenDs` \ unpack_id ->
+ newSysLocalDs addrPrimTy `thenDs` \ prim_obj ->
+ returnDs (Var prim_obj,
+ \ body ->
+ let
+ io_ty = exprType body
+ (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
+ in
+ mkApps (Var unpack_id)
+ [ Type io_arg
+ , arg
+ , Lam prim_obj body
+ ])
+
+ | otherwise
+ = getSrcSpanDs `thenDs` \ l ->
+ pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
+ where
+ arg_ty = exprType arg
+ maybe_product_type = splitProductType_maybe arg_ty
+ is_product_type = maybeToBool maybe_product_type
+ Just (_, _, data_con, data_con_arg_tys) = maybe_product_type
+ data_con_arity = dataConSourceArity data_con
+ (data_con_arg_ty1 : _) = data_con_arg_tys
+
+ (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys
+ maybe_arg3_tycon = splitTyConApp_maybe data_con_arg_ty3
+ Just (arg3_tycon,_) = maybe_arg3_tycon
+\end{code}
+
+
+\begin{code}
+boxResult :: ((Maybe Type, CoreExpr -> CoreExpr) -> (Maybe Type, CoreExpr -> CoreExpr))
+ -> Maybe Id
+ -> Type
+ -> DsM (Type, CoreExpr -> CoreExpr)
+
+-- Takes the result of the user-level ccall:
+-- either (IO t),
+-- or maybe just t for an side-effect-free call
+-- Returns a wrapper for the primitive ccall itself, along with the
+-- type of the result of the primitive ccall. This result type
+-- will be of the form
+-- State# RealWorld -> (# State# RealWorld, t' #)
+-- where t' is the unwrapped form of t. If t is simply (), then
+-- the result type will be
+-- State# RealWorld -> (# State# RealWorld #)
+
+boxResult augment mbTopCon result_ty
+ = case tcSplitTyConApp_maybe result_ty of
+ -- This split absolutely has to be a tcSplit, because we must
+ -- see the IO type; and it's a newtype which is transparent to splitTyConApp.
+
+ -- The result is IO t, so wrap the result in an IO constructor
+ Just (io_tycon, [io_res_ty]) | io_tycon `hasKey` ioTyConKey
+ -> resultWrapper io_res_ty `thenDs` \ res ->
+ let aug_res = augment res
+ extra_result_tys =
+ case aug_res of
+ (Just ty,_)
+ | isUnboxedTupleType ty ->
+ let (Just (_, ls)) = splitTyConApp_maybe ty in tail ls
+ _ -> []
+ in
+ mk_alt (return_result extra_result_tys) aug_res
+ `thenDs` \ (ccall_res_ty, the_alt) ->
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
+ let
+ io_data_con = head (tyConDataCons io_tycon)
+ toIOCon =
+ case mbTopCon of
+ Nothing -> dataConWrapId io_data_con
+ Just x -> x
+ wrap = \ the_call ->
+ mkApps (Var toIOCon)
+ [ Type io_res_ty,
+ Lam state_id $
+ Case (App the_call (Var state_id))
+ (mkWildId ccall_res_ty)
+ (coreAltType the_alt)
+ [the_alt]
+ ]
+ in
+ returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
+ where
+ return_result ts state anss
+ = mkConApp (tupleCon Unboxed (2 + length ts))
+ (Type realWorldStatePrimTy : Type io_res_ty : map Type ts ++
+ state : anss)
+ -- It isn't, so do unsafePerformIO
+ -- It's not conveniently available, so we inline it
+ other -> resultWrapper result_ty `thenDs` \ res ->
+ mk_alt return_result (augment res) `thenDs` \ (ccall_res_ty, the_alt) ->
+ let
+ wrap = \ the_call -> Case (App the_call (Var realWorldPrimId))
+ (mkWildId ccall_res_ty)
+ (coreAltType the_alt)
+ [the_alt]
+ in
+ returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
+ where
+ return_result state [ans] = ans
+ return_result _ _ = panic "return_result: expected single result"
+ where
+ mk_alt return_result (Nothing, wrap_result)
+ = -- The ccall returns ()
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
+ let
+ the_rhs = return_result (Var state_id)
+ [wrap_result (panic "boxResult")]
+
+ ccall_res_ty = mkTyConApp unboxedSingletonTyCon [realWorldStatePrimTy]
+ the_alt = (DataAlt unboxedSingletonDataCon, [state_id], the_rhs)
+ in
+ returnDs (ccall_res_ty, the_alt)
+
+ mk_alt return_result (Just prim_res_ty, wrap_result)
+ -- The ccall returns a non-() value
+ | isUnboxedTupleType prim_res_ty
+ = let
+ Just (_, ls) = splitTyConApp_maybe prim_res_ty
+ arity = 1 + length ls
+ in
+ mappM newSysLocalDs ls `thenDs` \ args_ids@(result_id:as) ->
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
+ let
+ the_rhs = return_result (Var state_id)
+ (wrap_result (Var result_id) : map Var as)
+ ccall_res_ty = mkTyConApp (tupleTyCon Unboxed arity)
+ (realWorldStatePrimTy : ls)
+ the_alt = ( DataAlt (tupleCon Unboxed arity)
+ , (state_id : args_ids)
+ , the_rhs
+ )
+ in
+ returnDs (ccall_res_ty, the_alt)
+ | otherwise
+ = newSysLocalDs prim_res_ty `thenDs` \ result_id ->
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
+ let
+ the_rhs = return_result (Var state_id)
+ [wrap_result (Var result_id)]
+
+ ccall_res_ty = mkTyConApp unboxedPairTyCon [realWorldStatePrimTy, prim_res_ty]
+ the_alt = (DataAlt unboxedPairDataCon, [state_id, result_id], the_rhs)
+ in
+ returnDs (ccall_res_ty, the_alt)
+
+
+resultWrapper :: Type
+ -> DsM (Maybe Type, -- Type of the expected result, if any
+ CoreExpr -> CoreExpr) -- Wrapper for the result
+resultWrapper result_ty
+ -- Base case 1: primitive types
+ | isPrimitiveType result_ty
+ = returnDs (Just result_ty, \e -> e)
+
+ -- Base case 2: the unit type ()
+ | Just (tc,_) <- maybe_tc_app, tc `hasKey` unitTyConKey
+ = returnDs (Nothing, \e -> Var unitDataConId)
+
+ -- Base case 3: the boolean type
+ | Just (tc,_) <- maybe_tc_app, tc `hasKey` boolTyConKey
+ = returnDs
+ (Just intPrimTy, \e -> Case e (mkWildId intPrimTy)
+ boolTy
+ [(DEFAULT ,[],Var trueDataConId ),
+ (LitAlt (mkMachInt 0),[],Var falseDataConId)])
+
+ -- Recursive newtypes
+ | Just rep_ty <- splitRecNewType_maybe result_ty
+ = resultWrapper rep_ty `thenDs` \ (maybe_ty, wrapper) ->
+ returnDs (maybe_ty, \e -> mkCoerce2 result_ty rep_ty (wrapper e))
+
+ -- The type might contain foralls (eg. for dummy type arguments,
+ -- referring to 'Ptr a' is legal).
+ | Just (tyvar, rest) <- splitForAllTy_maybe result_ty
+ = resultWrapper rest `thenDs` \ (maybe_ty, wrapper) ->
+ returnDs (maybe_ty, \e -> Lam tyvar (wrapper e))
+
+ -- Data types with a single constructor, which has a single arg
+ -- This includes types like Ptr and ForeignPtr
+ | Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) <- splitProductType_maybe result_ty,
+ dataConSourceArity data_con == 1
+ = let
+ (unwrapped_res_ty : _) = data_con_arg_tys
+ narrow_wrapper = maybeNarrow tycon
+ in
+ resultWrapper unwrapped_res_ty `thenDs` \ (maybe_ty, wrapper) ->
+ returnDs
+ (maybe_ty, \e -> mkApps (Var (dataConWrapId data_con))
+ (map Type tycon_arg_tys ++ [wrapper (narrow_wrapper e)]))
+
+ -- Strings; 'dotnet' only.
+ | Just (tc, [arg_ty]) <- maybe_tc_app, tc == listTyCon,
+ Just (cc,[]) <- splitTyConApp_maybe arg_ty, cc == charTyCon
+ = dsLookupGlobalId unmarshalStringName `thenDs` \ pack_id ->
+ returnDs (Just addrPrimTy,
+ \ e -> App (Var pack_id) e)
+
+ -- Objects; 'dotnet' only.
+ | Just (tc, [arg_ty]) <- maybe_tc_app,
+ tyConName tc == objectTyConName
+ = dsLookupGlobalId unmarshalObjectName `thenDs` \ pack_id ->
+ returnDs (Just addrPrimTy,
+ \ e -> App (Var pack_id) e)
+
+ | otherwise
+ = pprPanic "resultWrapper" (ppr result_ty)
+ where
+ maybe_tc_app = splitTyConApp_maybe result_ty
+
+-- When the result of a foreign call is smaller than the word size, we
+-- need to sign- or zero-extend the result up to the word size. The C
+-- standard appears to say that this is the responsibility of the
+-- caller, not the callee.
+
+maybeNarrow :: TyCon -> (CoreExpr -> CoreExpr)
+maybeNarrow tycon
+ | tycon `hasKey` int8TyConKey = \e -> App (Var (mkPrimOpId Narrow8IntOp)) e
+ | tycon `hasKey` int16TyConKey = \e -> App (Var (mkPrimOpId Narrow16IntOp)) e
+ | tycon `hasKey` int32TyConKey
+ && wORD_SIZE > 4 = \e -> App (Var (mkPrimOpId Narrow32IntOp)) e
+
+ | tycon `hasKey` word8TyConKey = \e -> App (Var (mkPrimOpId Narrow8WordOp)) e
+ | tycon `hasKey` word16TyConKey = \e -> App (Var (mkPrimOpId Narrow16WordOp)) e
+ | tycon `hasKey` word32TyConKey
+ && wORD_SIZE > 4 = \e -> App (Var (mkPrimOpId Narrow32WordOp)) e
+ | otherwise = id
+\end{code}
diff --git a/compiler/deSugar/DsExpr.hi-boot-5 b/compiler/deSugar/DsExpr.hi-boot-5
new file mode 100644
index 0000000000..7e5bbaab7f
--- /dev/null
+++ b/compiler/deSugar/DsExpr.hi-boot-5
@@ -0,0 +1,5 @@
+__interface DsExpr 1 0 where
+__export DsExpr dsExpr dsLet;
+1 dsExpr :: HsExpr.HsExpr Var.Id -> DsMonad.DsM CoreSyn.CoreExpr ;
+1 dsLExpr :: HsExpr.HsLExpr Var.Id -> DsMonad.DsM CoreSyn.CoreExpr ;
+1 dsLet :: [HsBinds.HsBindGroup Var.Id] -> CoreSyn.CoreExpr -> DsMonad.DsM CoreSyn.CoreExpr ;
diff --git a/compiler/deSugar/DsExpr.hi-boot-6 b/compiler/deSugar/DsExpr.hi-boot-6
new file mode 100644
index 0000000000..c7ddb2ddfd
--- /dev/null
+++ b/compiler/deSugar/DsExpr.hi-boot-6
@@ -0,0 +1,6 @@
+module DsExpr where
+
+dsExpr :: HsExpr.HsExpr Var.Id -> DsMonad.DsM CoreSyn.CoreExpr
+dsLExpr :: HsExpr.LHsExpr Var.Id -> DsMonad.DsM CoreSyn.CoreExpr
+dsLocalBinds :: HsBinds.HsLocalBinds Var.Id -> CoreSyn.CoreExpr -> DsMonad.DsM CoreSyn.CoreExpr
+dsValBinds :: HsBinds.HsValBinds Var.Id -> CoreSyn.CoreExpr -> DsMonad.DsM CoreSyn.CoreExpr
diff --git a/compiler/deSugar/DsExpr.lhs b/compiler/deSugar/DsExpr.lhs
new file mode 100644
index 0000000000..e8e9e7b370
--- /dev/null
+++ b/compiler/deSugar/DsExpr.lhs
@@ -0,0 +1,781 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsExpr]{Matching expressions (Exprs)}
+
+\begin{code}
+module DsExpr ( dsExpr, dsLExpr, dsLocalBinds, dsValBinds, dsLit ) where
+
+#include "HsVersions.h"
+#if defined(GHCI) && defined(BREAKPOINT)
+import Foreign.StablePtr ( newStablePtr, castStablePtrToPtr )
+import GHC.Exts ( Ptr(..), Int(..), addr2Int# )
+import IOEnv ( ioToIOEnv )
+import PrelNames ( breakpointJumpName )
+import TysWiredIn ( unitTy )
+import TypeRep ( Type(..) )
+#endif
+
+import Match ( matchWrapper, matchSinglePat, matchEquations )
+import MatchLit ( dsLit, dsOverLit )
+import DsBinds ( dsLHsBinds, dsCoercion )
+import DsGRHSs ( dsGuarded )
+import DsListComp ( dsListComp, dsPArrComp )
+import DsUtils ( mkErrorAppDs, mkStringExpr, mkConsExpr, mkNilExpr,
+ extractMatchResult, cantFailMatchResult, matchCanFail,
+ mkCoreTupTy, selectSimpleMatchVarL, lookupEvidence, selectMatchVar )
+import DsArrows ( dsProcExpr )
+import DsMonad
+
+#ifdef GHCI
+ -- Template Haskell stuff iff bootstrapped
+import DsMeta ( dsBracket )
+#endif
+
+import HsSyn
+import TcHsSyn ( hsPatType, mkVanillaTuplePat )
+
+-- 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 TcType ( tcSplitAppTy, tcSplitFunTys, tcTyConAppTyCon,
+ tcTyConAppArgs, isUnLiftedType, Type, mkAppTy )
+import Type ( funArgTy, splitFunTys, isUnboxedTupleType, mkFunTy )
+import CoreSyn
+import CoreUtils ( exprType, mkIfThenElse, bindNonRec )
+
+import CostCentre ( mkUserCC )
+import Id ( Id, idType, idName, idDataCon )
+import PrelInfo ( rEC_CON_ERROR_ID, iRREFUT_PAT_ERROR_ID )
+import DataCon ( DataCon, dataConWrapId, dataConFieldLabels, dataConInstOrigArgTys )
+import DataCon ( isVanillaDataCon )
+import TyCon ( FieldLabel, tyConDataCons )
+import TysWiredIn ( tupleCon )
+import BasicTypes ( RecFlag(..), Boxity(..), ipNameName )
+import PrelNames ( toPName,
+ returnMName, bindMName, thenMName, failMName,
+ mfixName )
+import SrcLoc ( Located(..), unLoc, getLoc, noLoc )
+import Util ( zipEqual, zipWithEqual )
+import Bag ( bagToList )
+import Outputable
+import FastString
+\end{code}
+
+
+%************************************************************************
+%* *
+ dsLocalBinds, dsValBinds
+%* *
+%************************************************************************
+
+\begin{code}
+dsLocalBinds :: HsLocalBinds Id -> CoreExpr -> DsM CoreExpr
+dsLocalBinds EmptyLocalBinds body = return body
+dsLocalBinds (HsValBinds binds) body = dsValBinds binds body
+dsLocalBinds (HsIPBinds binds) body = dsIPBinds binds body
+
+-------------------------
+dsValBinds :: HsValBinds Id -> CoreExpr -> DsM CoreExpr
+dsValBinds (ValBindsOut binds _) body = foldrDs ds_val_bind body binds
+
+-------------------------
+dsIPBinds (IPBinds ip_binds dict_binds) body
+ = do { prs <- dsLHsBinds dict_binds
+ ; let inner = foldr (\(x,r) e -> Let (NonRec x r) e) body prs
+ ; foldrDs ds_ip_bind inner ip_binds }
+ where
+ ds_ip_bind (L _ (IPBind n e)) body
+ = dsLExpr e `thenDs` \ e' ->
+ returnDs (Let (NonRec (ipNameName n) e') body)
+
+-------------------------
+ds_val_bind :: (RecFlag, LHsBinds Id) -> CoreExpr -> DsM CoreExpr
+-- Special case for bindings which bind unlifted variables
+-- We need to do a case right away, rather than building
+-- a tuple and doing selections.
+-- Silently ignore INLINE and SPECIALISE pragmas...
+ds_val_bind (NonRecursive, hsbinds) body
+ | [L _ (AbsBinds [] [] exports binds)] <- bagToList hsbinds,
+ (L loc bind : null_binds) <- bagToList binds,
+ isBangHsBind bind
+ || isUnboxedTupleBind bind
+ || or [isUnLiftedType (idType g) | (_, g, _, _) <- exports]
+ = let
+ body_w_exports = foldr bind_export body exports
+ bind_export (tvs, g, l, _) body = ASSERT( null tvs )
+ bindNonRec g (Var l) body
+ in
+ ASSERT (null null_binds)
+ -- Non-recursive, non-overloaded bindings only come in ones
+ -- ToDo: in some bizarre case it's conceivable that there
+ -- could be dict binds in the 'binds'. (See the notes
+ -- below. Then pattern-match would fail. Urk.)
+ putSrcSpanDs loc $
+ case bind of
+ FunBind { fun_id = L _ fun, fun_matches = matches, fun_co_fn = co_fn }
+ -> matchWrapper (FunRhs (idName fun)) matches `thenDs` \ (args, rhs) ->
+ ASSERT( null args ) -- Functions aren't lifted
+ ASSERT( isIdCoercion co_fn )
+ returnDs (bindNonRec fun rhs body_w_exports)
+
+ PatBind {pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty }
+ -> -- let C x# y# = rhs in body
+ -- ==> case rhs of C x# y# -> body
+ putSrcSpanDs loc $
+ do { rhs <- dsGuarded grhss ty
+ ; let upat = unLoc pat
+ eqn = EqnInfo { eqn_wrap = idWrapper, eqn_pats = [upat],
+ eqn_rhs = cantFailMatchResult body_w_exports }
+ ; var <- selectMatchVar upat ty
+ ; result <- matchEquations PatBindRhs [var] [eqn] (exprType body)
+ ; return (scrungleMatch var rhs result) }
+
+ other -> pprPanic "dsLet: unlifted" (pprLHsBinds hsbinds $$ ppr body)
+
+
+-- Ordinary case for bindings; none should be unlifted
+ds_val_bind (is_rec, binds) body
+ = do { prs <- dsLHsBinds binds
+ ; ASSERT( not (any (isUnLiftedType . idType . fst) prs) )
+ case prs of
+ [] -> return body
+ other -> return (Let (Rec prs) body) }
+ -- Use a Rec regardless of is_rec.
+ -- Why? Because it allows the binds to be all
+ -- mixed up, which is what happens in one rare case
+ -- Namely, for an AbsBind with no tyvars and no dicts,
+ -- but which does have dictionary bindings.
+ -- See notes with TcSimplify.inferLoop [NO TYVARS]
+ -- It turned out that wrapping a Rec here was the easiest solution
+ --
+ -- NB The previous case dealt with unlifted bindings, so we
+ -- only have to deal with lifted ones now; so Rec is ok
+
+isUnboxedTupleBind :: HsBind Id -> Bool
+isUnboxedTupleBind (PatBind { pat_rhs_ty = ty }) = isUnboxedTupleType ty
+isUnboxedTupleBind other = False
+
+scrungleMatch :: Id -> CoreExpr -> CoreExpr -> CoreExpr
+-- Returns something like (let var = scrut in body)
+-- but if var is an unboxed-tuple type, it inlines it in a fragile way
+-- Special case to handle unboxed tuple patterns; they can't appear nested
+-- The idea is that
+-- case e of (# p1, p2 #) -> rhs
+-- should desugar to
+-- case e of (# x1, x2 #) -> ... match p1, p2 ...
+-- NOT
+-- let x = e in case x of ....
+--
+-- But there may be a big
+-- let fail = ... in case e of ...
+-- wrapping the whole case, which complicates matters slightly
+-- It all seems a bit fragile. Test is dsrun013.
+
+scrungleMatch var scrut body
+ | isUnboxedTupleType (idType var) = scrungle body
+ | otherwise = bindNonRec var scrut body
+ where
+ scrungle (Case (Var x) bndr ty alts)
+ | x == var = Case scrut bndr ty alts
+ scrungle (Let binds body) = Let binds (scrungle body)
+ scrungle other = panic ("scrungleMatch: tuple pattern:\n" ++ showSDoc (ppr other))
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[DsExpr-vars-and-cons]{Variables, constructors, literals}
+%* *
+%************************************************************************
+
+\begin{code}
+dsLExpr :: LHsExpr Id -> DsM CoreExpr
+dsLExpr (L loc e) = putSrcSpanDs loc $ dsExpr e
+
+dsExpr :: HsExpr Id -> DsM CoreExpr
+
+dsExpr (HsPar e) = dsLExpr e
+dsExpr (ExprWithTySigOut e _) = dsLExpr e
+dsExpr (HsVar var) = returnDs (Var var)
+dsExpr (HsIPVar ip) = returnDs (Var (ipNameName ip))
+dsExpr (HsLit lit) = dsLit lit
+dsExpr (HsOverLit lit) = dsOverLit lit
+
+dsExpr (NegApp expr neg_expr)
+ = do { core_expr <- dsLExpr expr
+ ; core_neg <- dsExpr neg_expr
+ ; return (core_neg `App` core_expr) }
+
+dsExpr expr@(HsLam a_Match)
+ = matchWrapper LambdaExpr a_Match `thenDs` \ (binders, matching_code) ->
+ returnDs (mkLams binders matching_code)
+
+#if defined(GHCI) && defined(BREAKPOINT)
+dsExpr (HsApp (L _ (HsApp realFun@(L _ (HsCoerce _ fun)) (L loc arg))) _)
+ | HsVar funId <- fun
+ , idName funId == breakpointJumpName
+ , ids <- filter (not.hasTyVar.idType) (extractIds arg)
+ = do dsWarn (text "Extracted ids:" <+> ppr ids <+> ppr (map idType ids))
+ stablePtr <- ioToIOEnv $ newStablePtr ids
+ -- Yes, I know... I'm gonna burn in hell.
+ let Ptr addr# = castStablePtrToPtr stablePtr
+ funCore <- dsLExpr realFun
+ argCore <- dsLExpr (L loc (HsLit (HsInt (fromIntegral (I# (addr2Int# addr#))))))
+ hvalCore <- dsLExpr (L loc (extractHVals ids))
+ return ((funCore `App` argCore) `App` hvalCore)
+ where extractIds :: HsExpr Id -> [Id]
+ extractIds (HsApp fn arg)
+ | HsVar argId <- unLoc arg
+ = argId:extractIds (unLoc fn)
+ | TyApp arg' ts <- unLoc arg
+ , HsVar argId <- unLoc arg'
+ = error (showSDoc (ppr ts)) -- argId:extractIds (unLoc fn)
+ extractIds x = []
+ extractHVals ids = ExplicitList unitTy (map (L loc . HsVar) ids)
+ hasTyVar (TyVarTy _) = True
+ hasTyVar (FunTy a b) = hasTyVar a || hasTyVar b
+ hasTyVar (NoteTy _ t) = hasTyVar t
+ hasTyVar (AppTy a b) = hasTyVar a || hasTyVar b
+ hasTyVar (TyConApp _ ts) = any hasTyVar ts
+ hasTyVar _ = False
+#endif
+
+dsExpr expr@(HsApp fun arg)
+ = dsLExpr fun `thenDs` \ core_fun ->
+ dsLExpr arg `thenDs` \ core_arg ->
+ returnDs (core_fun `App` core_arg)
+\end{code}
+
+Operator sections. At first it looks as if we can convert
+\begin{verbatim}
+ (expr op)
+\end{verbatim}
+to
+\begin{verbatim}
+ \x -> op expr x
+\end{verbatim}
+
+But no! expr might be a redex, and we can lose laziness badly this
+way. Consider
+\begin{verbatim}
+ map (expr op) xs
+\end{verbatim}
+for example. So we convert instead to
+\begin{verbatim}
+ let y = expr in \x -> op y x
+\end{verbatim}
+If \tr{expr} is actually just a variable, say, then the simplifier
+will sort it out.
+
+\begin{code}
+dsExpr (OpApp e1 op _ e2)
+ = dsLExpr op `thenDs` \ core_op ->
+ -- for the type of y, we need the type of op's 2nd argument
+ dsLExpr e1 `thenDs` \ x_core ->
+ dsLExpr e2 `thenDs` \ y_core ->
+ returnDs (mkApps core_op [x_core, y_core])
+
+dsExpr (SectionL expr op)
+ = dsLExpr op `thenDs` \ core_op ->
+ -- for the type of y, we need the type of op's 2nd argument
+ let
+ (x_ty:y_ty:_, _) = splitFunTys (exprType core_op)
+ -- Must look through an implicit-parameter type;
+ -- newtype impossible; hence Type.splitFunTys
+ in
+ dsLExpr expr `thenDs` \ x_core ->
+ newSysLocalDs x_ty `thenDs` \ x_id ->
+ newSysLocalDs y_ty `thenDs` \ y_id ->
+
+ returnDs (bindNonRec x_id x_core $
+ Lam y_id (mkApps core_op [Var x_id, Var y_id]))
+
+-- dsLExpr (SectionR op expr) -- \ x -> op x expr
+dsExpr (SectionR op expr)
+ = dsLExpr op `thenDs` \ core_op ->
+ -- for the type of x, we need the type of op's 2nd argument
+ let
+ (x_ty:y_ty:_, _) = splitFunTys (exprType core_op)
+ -- See comment with SectionL
+ in
+ dsLExpr expr `thenDs` \ y_core ->
+ newSysLocalDs x_ty `thenDs` \ x_id ->
+ newSysLocalDs y_ty `thenDs` \ y_id ->
+
+ returnDs (bindNonRec y_id y_core $
+ Lam x_id (mkApps core_op [Var x_id, Var y_id]))
+
+dsExpr (HsSCC cc expr)
+ = dsLExpr expr `thenDs` \ core_expr ->
+ getModuleDs `thenDs` \ mod_name ->
+ returnDs (Note (SCC (mkUserCC cc mod_name)) core_expr)
+
+
+-- hdaume: core annotation
+
+dsExpr (HsCoreAnn fs expr)
+ = dsLExpr expr `thenDs` \ core_expr ->
+ returnDs (Note (CoreNote $ unpackFS fs) core_expr)
+
+dsExpr (HsCase discrim matches)
+ = dsLExpr discrim `thenDs` \ core_discrim ->
+ matchWrapper CaseAlt matches `thenDs` \ ([discrim_var], matching_code) ->
+ returnDs (scrungleMatch discrim_var core_discrim matching_code)
+
+dsExpr (HsLet binds body)
+ = dsLExpr body `thenDs` \ body' ->
+ dsLocalBinds binds body'
+
+-- We need the `ListComp' form to use `deListComp' (rather than the "do" form)
+-- because the interpretation of `stmts' depends on what sort of thing it is.
+--
+dsExpr (HsDo ListComp stmts body result_ty)
+ = -- Special case for list comprehensions
+ dsListComp stmts body elt_ty
+ where
+ [elt_ty] = tcTyConAppArgs result_ty
+
+dsExpr (HsDo DoExpr stmts body result_ty)
+ = dsDo stmts body result_ty
+
+dsExpr (HsDo (MDoExpr tbl) stmts body result_ty)
+ = dsMDo tbl stmts body result_ty
+
+dsExpr (HsDo PArrComp stmts body result_ty)
+ = -- Special case for array comprehensions
+ dsPArrComp (map unLoc stmts) body elt_ty
+ where
+ [elt_ty] = tcTyConAppArgs result_ty
+
+dsExpr (HsIf guard_expr then_expr else_expr)
+ = dsLExpr guard_expr `thenDs` \ core_guard ->
+ dsLExpr then_expr `thenDs` \ core_then ->
+ dsLExpr else_expr `thenDs` \ core_else ->
+ returnDs (mkIfThenElse core_guard core_then core_else)
+\end{code}
+
+
+\noindent
+\underline{\bf Type lambda and application}
+% ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\begin{code}
+dsExpr (TyLam tyvars expr)
+ = dsLExpr expr `thenDs` \ core_expr ->
+ returnDs (mkLams tyvars core_expr)
+
+dsExpr (TyApp expr tys)
+ = dsLExpr expr `thenDs` \ core_expr ->
+ returnDs (mkTyApps core_expr tys)
+\end{code}
+
+
+\noindent
+\underline{\bf Various data construction things}
+% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\begin{code}
+dsExpr (ExplicitList ty xs)
+ = go xs
+ where
+ go [] = returnDs (mkNilExpr ty)
+ go (x:xs) = dsLExpr x `thenDs` \ core_x ->
+ go xs `thenDs` \ core_xs ->
+ returnDs (mkConsExpr ty core_x core_xs)
+
+-- we create a list from the array elements and convert them into a list using
+-- `PrelPArr.toP'
+--
+-- * the main disadvantage to this scheme is that `toP' traverses the list
+-- twice: once to determine the length and a second time to put to elements
+-- into the array; this inefficiency could be avoided by exposing some of
+-- the innards of `PrelPArr' to the compiler (ie, have a `PrelPArrBase') so
+-- that we can exploit the fact that we already know the length of the array
+-- here at compile time
+--
+dsExpr (ExplicitPArr ty xs)
+ = dsLookupGlobalId toPName `thenDs` \toP ->
+ dsExpr (ExplicitList ty xs) `thenDs` \coreList ->
+ returnDs (mkApps (Var toP) [Type ty, coreList])
+
+dsExpr (ExplicitTuple expr_list boxity)
+ = mappM dsLExpr expr_list `thenDs` \ core_exprs ->
+ returnDs (mkConApp (tupleCon boxity (length expr_list))
+ (map (Type . exprType) core_exprs ++ core_exprs))
+
+dsExpr (ArithSeq expr (From from))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ returnDs (App expr2 from2)
+
+dsExpr (ArithSeq expr (FromTo from two))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ dsLExpr two `thenDs` \ two2 ->
+ returnDs (mkApps expr2 [from2, two2])
+
+dsExpr (ArithSeq expr (FromThen from thn))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ dsLExpr thn `thenDs` \ thn2 ->
+ returnDs (mkApps expr2 [from2, thn2])
+
+dsExpr (ArithSeq expr (FromThenTo from thn two))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ dsLExpr thn `thenDs` \ thn2 ->
+ dsLExpr two `thenDs` \ two2 ->
+ returnDs (mkApps expr2 [from2, thn2, two2])
+
+dsExpr (PArrSeq expr (FromTo from two))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ dsLExpr two `thenDs` \ two2 ->
+ returnDs (mkApps expr2 [from2, two2])
+
+dsExpr (PArrSeq expr (FromThenTo from thn two))
+ = dsExpr expr `thenDs` \ expr2 ->
+ dsLExpr from `thenDs` \ from2 ->
+ dsLExpr thn `thenDs` \ thn2 ->
+ dsLExpr two `thenDs` \ two2 ->
+ returnDs (mkApps expr2 [from2, thn2, two2])
+
+dsExpr (PArrSeq expr _)
+ = panic "DsExpr.dsExpr: Infinite parallel array!"
+ -- the parser shouldn't have generated it and the renamer and typechecker
+ -- shouldn't have let it through
+\end{code}
+
+\noindent
+\underline{\bf Record construction and update}
+% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For record construction we do this (assuming T has three arguments)
+\begin{verbatim}
+ T { op2 = e }
+==>
+ let err = /\a -> recConErr a
+ T (recConErr t1 "M.lhs/230/op1")
+ e
+ (recConErr t1 "M.lhs/230/op3")
+\end{verbatim}
+@recConErr@ then converts its arugment string into a proper message
+before printing it as
+\begin{verbatim}
+ M.lhs, line 230: missing field op1 was evaluated
+\end{verbatim}
+
+We also handle @C{}@ as valid construction syntax for an unlabelled
+constructor @C@, setting all of @C@'s fields to bottom.
+
+\begin{code}
+dsExpr (RecordCon (L _ data_con_id) con_expr rbinds)
+ = dsExpr con_expr `thenDs` \ con_expr' ->
+ let
+ (arg_tys, _) = tcSplitFunTys (exprType con_expr')
+ -- A newtype in the corner should be opaque;
+ -- hence TcType.tcSplitFunTys
+
+ mk_arg (arg_ty, lbl) -- Selector id has the field label as its name
+ = case [rhs | (L _ sel_id, rhs) <- rbinds, lbl == idName sel_id] of
+ (rhs:rhss) -> ASSERT( null rhss )
+ dsLExpr rhs
+ [] -> mkErrorAppDs rEC_CON_ERROR_ID arg_ty (showSDoc (ppr lbl))
+ unlabelled_bottom arg_ty = mkErrorAppDs rEC_CON_ERROR_ID arg_ty ""
+
+ labels = dataConFieldLabels (idDataCon data_con_id)
+ -- The data_con_id is guaranteed to be the wrapper id of the constructor
+ in
+
+ (if null labels
+ then mappM unlabelled_bottom arg_tys
+ else mappM mk_arg (zipEqual "dsExpr:RecordCon" arg_tys labels))
+ `thenDs` \ con_args ->
+
+ returnDs (mkApps con_expr' con_args)
+\end{code}
+
+Record update is a little harder. Suppose we have the decl:
+\begin{verbatim}
+ data T = T1 {op1, op2, op3 :: Int}
+ | T2 {op4, op2 :: Int}
+ | T3
+\end{verbatim}
+Then we translate as follows:
+\begin{verbatim}
+ r { op2 = e }
+===>
+ let op2 = e in
+ case r of
+ T1 op1 _ op3 -> T1 op1 op2 op3
+ T2 op4 _ -> T2 op4 op2
+ other -> recUpdError "M.lhs/230"
+\end{verbatim}
+It's important that we use the constructor Ids for @T1@, @T2@ etc on the
+RHSs, and do not generate a Core constructor application directly, because the constructor
+might do some argument-evaluation first; and may have to throw away some
+dictionaries.
+
+\begin{code}
+dsExpr (RecordUpd record_expr [] record_in_ty record_out_ty)
+ = dsLExpr record_expr
+
+dsExpr expr@(RecordUpd record_expr rbinds record_in_ty record_out_ty)
+ = dsLExpr record_expr `thenDs` \ record_expr' ->
+
+ -- Desugar the rbinds, and generate let-bindings if
+ -- necessary so that we don't lose sharing
+
+ let
+ in_inst_tys = tcTyConAppArgs record_in_ty -- Newtype opaque
+ out_inst_tys = tcTyConAppArgs record_out_ty -- Newtype opaque
+ in_out_ty = mkFunTy record_in_ty record_out_ty
+
+ mk_val_arg field old_arg_id
+ = case [rhs | (L _ sel_id, rhs) <- rbinds, field == idName sel_id] of
+ (rhs:rest) -> ASSERT(null rest) rhs
+ [] -> nlHsVar old_arg_id
+
+ mk_alt con
+ = newSysLocalsDs (dataConInstOrigArgTys con in_inst_tys) `thenDs` \ arg_ids ->
+ -- This call to dataConInstOrigArgTys won't work for existentials
+ -- but existentials don't have record types anyway
+ let
+ val_args = zipWithEqual "dsExpr:RecordUpd" mk_val_arg
+ (dataConFieldLabels con) arg_ids
+ rhs = foldl (\a b -> nlHsApp a b)
+ (noLoc $ TyApp (nlHsVar (dataConWrapId con))
+ out_inst_tys)
+ val_args
+ in
+ returnDs (mkSimpleMatch [noLoc $ ConPatOut (noLoc con) [] [] emptyLHsBinds
+ (PrefixCon (map nlVarPat arg_ids)) record_in_ty]
+ rhs)
+ in
+ -- Record stuff doesn't work for existentials
+ -- The type checker checks for this, but we need
+ -- worry only about the constructors that are to be updated
+ ASSERT2( all isVanillaDataCon cons_to_upd, ppr expr )
+
+ -- It's important to generate the match with matchWrapper,
+ -- and the right hand sides with applications of the wrapper Id
+ -- so that everything works when we are doing fancy unboxing on the
+ -- constructor aguments.
+ mappM mk_alt cons_to_upd `thenDs` \ alts ->
+ matchWrapper RecUpd (MatchGroup alts in_out_ty) `thenDs` \ ([discrim_var], matching_code) ->
+
+ returnDs (bindNonRec discrim_var record_expr' matching_code)
+
+ where
+ updated_fields :: [FieldLabel]
+ updated_fields = [ idName sel_id | (L _ sel_id,_) <- rbinds]
+
+ -- Get the type constructor from the record_in_ty
+ -- so that we are sure it'll have all its DataCons
+ -- (In GHCI, it's possible that some TyCons may not have all
+ -- their constructors, in a module-loop situation.)
+ tycon = tcTyConAppTyCon record_in_ty
+ data_cons = tyConDataCons tycon
+ cons_to_upd = filter has_all_fields data_cons
+
+ has_all_fields :: DataCon -> Bool
+ has_all_fields con_id
+ = all (`elem` con_fields) updated_fields
+ where
+ con_fields = dataConFieldLabels con_id
+\end{code}
+
+
+\noindent
+\underline{\bf Dictionary lambda and application}
+% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@DictLam@ and @DictApp@ turn into the regular old things.
+(OLD:) @DictFunApp@ also becomes a curried application, albeit slightly more
+complicated; reminiscent of fully-applied constructors.
+\begin{code}
+dsExpr (DictLam dictvars expr)
+ = dsLExpr expr `thenDs` \ core_expr ->
+ returnDs (mkLams dictvars core_expr)
+
+------------------
+
+dsExpr (DictApp expr dicts) -- becomes a curried application
+ = dsLExpr expr `thenDs` \ core_expr ->
+ returnDs (foldl (\f d -> f `App` (Var d)) core_expr dicts)
+
+dsExpr (HsCoerce co_fn e) = dsCoercion co_fn (dsExpr e)
+\end{code}
+
+Here is where we desugar the Template Haskell brackets and escapes
+
+\begin{code}
+-- Template Haskell stuff
+
+#ifdef GHCI /* Only if bootstrapping */
+dsExpr (HsBracketOut x ps) = dsBracket x ps
+dsExpr (HsSpliceE s) = pprPanic "dsExpr:splice" (ppr s)
+#endif
+
+-- Arrow notation extension
+dsExpr (HsProc pat cmd) = dsProcExpr pat cmd
+\end{code}
+
+
+\begin{code}
+
+#ifdef DEBUG
+-- HsSyn constructs that just shouldn't be here:
+dsExpr (ExprWithTySig _ _) = panic "dsExpr:ExprWithTySig"
+#endif
+
+\end{code}
+
+%--------------------------------------------------------------------
+
+Desugar 'do' and 'mdo' expressions (NOT list comprehensions, they're
+handled in DsListComp). Basically does the translation given in the
+Haskell 98 report:
+
+\begin{code}
+dsDo :: [LStmt Id]
+ -> LHsExpr Id
+ -> Type -- Type of the whole expression
+ -> DsM CoreExpr
+
+dsDo stmts body result_ty
+ = go (map unLoc stmts)
+ where
+ go [] = dsLExpr body
+
+ go (ExprStmt rhs then_expr _ : stmts)
+ = do { rhs2 <- dsLExpr rhs
+ ; then_expr2 <- dsExpr then_expr
+ ; rest <- go stmts
+ ; returnDs (mkApps then_expr2 [rhs2, rest]) }
+
+ go (LetStmt binds : stmts)
+ = do { rest <- go stmts
+ ; dsLocalBinds binds rest }
+
+ go (BindStmt pat rhs bind_op fail_op : stmts)
+ = do { body <- go stmts
+ ; var <- selectSimpleMatchVarL pat
+ ; match <- matchSinglePat (Var var) (StmtCtxt DoExpr) pat
+ result_ty (cantFailMatchResult body)
+ ; match_code <- handle_failure pat match fail_op
+ ; rhs' <- dsLExpr rhs
+ ; bind_op' <- dsExpr bind_op
+ ; returnDs (mkApps bind_op' [rhs', Lam var match_code]) }
+
+ -- In a do expression, pattern-match failure just calls
+ -- the monadic 'fail' rather than throwing an exception
+ handle_failure pat match fail_op
+ | matchCanFail match
+ = do { fail_op' <- dsExpr fail_op
+ ; fail_msg <- mkStringExpr (mk_fail_msg pat)
+ ; extractMatchResult match (App fail_op' fail_msg) }
+ | otherwise
+ = extractMatchResult match (error "It can't fail")
+
+mk_fail_msg pat = "Pattern match failure in do expression at " ++
+ showSDoc (ppr (getLoc pat))
+\end{code}
+
+Translation for RecStmt's:
+-----------------------------
+We turn (RecStmt [v1,..vn] stmts) into:
+
+ (v1,..,vn) <- mfix (\~(v1,..vn). do stmts
+ return (v1,..vn))
+
+\begin{code}
+dsMDo :: PostTcTable
+ -> [LStmt Id]
+ -> LHsExpr Id
+ -> Type -- Type of the whole expression
+ -> DsM CoreExpr
+
+dsMDo tbl stmts body result_ty
+ = go (map unLoc stmts)
+ where
+ (m_ty, b_ty) = tcSplitAppTy result_ty -- result_ty must be of the form (m b)
+ mfix_id = lookupEvidence tbl mfixName
+ return_id = lookupEvidence tbl returnMName
+ bind_id = lookupEvidence tbl bindMName
+ then_id = lookupEvidence tbl thenMName
+ fail_id = lookupEvidence tbl failMName
+ ctxt = MDoExpr tbl
+
+ go [] = dsLExpr body
+
+ go (LetStmt binds : stmts)
+ = do { rest <- go stmts
+ ; dsLocalBinds binds rest }
+
+ go (ExprStmt rhs _ rhs_ty : stmts)
+ = do { rhs2 <- dsLExpr rhs
+ ; rest <- go stmts
+ ; returnDs (mkApps (Var then_id) [Type rhs_ty, Type b_ty, rhs2, rest]) }
+
+ go (BindStmt pat rhs _ _ : stmts)
+ = do { body <- go stmts
+ ; var <- selectSimpleMatchVarL pat
+ ; match <- matchSinglePat (Var var) (StmtCtxt ctxt) pat
+ result_ty (cantFailMatchResult body)
+ ; fail_msg <- mkStringExpr (mk_fail_msg pat)
+ ; let fail_expr = mkApps (Var fail_id) [Type b_ty, fail_msg]
+ ; match_code <- extractMatchResult match fail_expr
+
+ ; rhs' <- dsLExpr rhs
+ ; returnDs (mkApps (Var bind_id) [Type (hsPatType pat), Type b_ty,
+ rhs', Lam var match_code]) }
+
+ go (RecStmt rec_stmts later_ids rec_ids rec_rets binds : stmts)
+ = ASSERT( length rec_ids > 0 )
+ ASSERT( length rec_ids == length rec_rets )
+ go (new_bind_stmt : let_stmt : stmts)
+ where
+ new_bind_stmt = mkBindStmt (mk_tup_pat later_pats) mfix_app
+ let_stmt = LetStmt (HsValBinds (ValBindsOut [(Recursive, binds)] []))
+
+
+ -- Remove the later_ids that appear (without fancy coercions)
+ -- in rec_rets, because there's no need to knot-tie them separately
+ -- See Note [RecStmt] in HsExpr
+ later_ids' = filter (`notElem` mono_rec_ids) later_ids
+ mono_rec_ids = [ id | HsVar id <- rec_rets ]
+
+ mfix_app = nlHsApp (noLoc $ TyApp (nlHsVar mfix_id) [tup_ty]) mfix_arg
+ mfix_arg = noLoc $ HsLam (MatchGroup [mkSimpleMatch [mfix_pat] body]
+ (mkFunTy tup_ty body_ty))
+
+ -- The rec_tup_pat must bind the rec_ids only; remember that the
+ -- trimmed_laters may share the same Names
+ -- Meanwhile, the later_pats must bind the later_vars
+ rec_tup_pats = map mk_wild_pat later_ids' ++ map nlVarPat rec_ids
+ later_pats = map nlVarPat later_ids' ++ map mk_later_pat rec_ids
+ rets = map nlHsVar later_ids' ++ map noLoc rec_rets
+
+ mfix_pat = noLoc $ LazyPat $ mk_tup_pat rec_tup_pats
+ body = noLoc $ HsDo ctxt rec_stmts return_app body_ty
+ body_ty = mkAppTy m_ty tup_ty
+ tup_ty = mkCoreTupTy (map idType (later_ids' ++ rec_ids))
+ -- mkCoreTupTy deals with singleton case
+
+ return_app = nlHsApp (noLoc $ TyApp (nlHsVar return_id) [tup_ty])
+ (mk_ret_tup rets)
+
+ mk_wild_pat :: Id -> LPat Id
+ mk_wild_pat v = noLoc $ WildPat $ idType v
+
+ mk_later_pat :: Id -> LPat Id
+ mk_later_pat v | v `elem` later_ids' = mk_wild_pat v
+ | otherwise = nlVarPat v
+
+ mk_tup_pat :: [LPat Id] -> LPat Id
+ mk_tup_pat [p] = p
+ mk_tup_pat ps = noLoc $ mkVanillaTuplePat ps Boxed
+
+ mk_ret_tup :: [LHsExpr Id] -> LHsExpr Id
+ mk_ret_tup [r] = r
+ mk_ret_tup rs = noLoc $ ExplicitTuple rs Boxed
+\end{code}
diff --git a/compiler/deSugar/DsExpr.lhs-boot b/compiler/deSugar/DsExpr.lhs-boot
new file mode 100644
index 0000000000..c65e99d80d
--- /dev/null
+++ b/compiler/deSugar/DsExpr.lhs-boot
@@ -0,0 +1,11 @@
+\begin{code}
+module DsExpr where
+import HsSyn ( HsExpr, LHsExpr, HsLocalBinds )
+import Var ( Id )
+import DsMonad ( DsM )
+import CoreSyn ( CoreExpr )
+
+dsExpr :: HsExpr Id -> DsM CoreExpr
+dsLExpr :: LHsExpr Id -> DsM CoreExpr
+dsLocalBinds :: HsLocalBinds Id -> CoreExpr -> DsM CoreExpr
+\end{code}
diff --git a/compiler/deSugar/DsForeign.lhs b/compiler/deSugar/DsForeign.lhs
new file mode 100644
index 0000000000..52956a09ff
--- /dev/null
+++ b/compiler/deSugar/DsForeign.lhs
@@ -0,0 +1,646 @@
+%
+% (c) The AQUA Project, Glasgow University, 1998
+%
+\section[DsCCall]{Desugaring \tr{foreign} declarations}
+
+Expanding out @foreign import@ and @foreign export@ declarations.
+
+\begin{code}
+module DsForeign ( dsForeigns ) where
+
+#include "HsVersions.h"
+import TcRnMonad -- temp
+
+import CoreSyn
+
+import DsCCall ( dsCCall, mkFCall, boxResult, unboxArg, resultWrapper )
+import DsMonad
+
+import HsSyn ( ForeignDecl(..), ForeignExport(..), LForeignDecl,
+ ForeignImport(..), CImportSpec(..) )
+import DataCon ( splitProductType_maybe )
+#ifdef DEBUG
+import DataCon ( dataConSourceArity )
+import Type ( isUnLiftedType )
+#endif
+import MachOp ( machRepByteWidth, MachRep(..) )
+import SMRep ( argMachRep, typeCgRep )
+import CoreUtils ( exprType, mkInlineMe )
+import Id ( Id, idType, idName, mkSysLocal, setInlinePragma )
+import Literal ( Literal(..), mkStringLit )
+import Module ( moduleFS )
+import Name ( getOccString, NamedThing(..) )
+import Type ( repType, coreEqType )
+import TcType ( Type, mkFunTys, mkForAllTys, mkTyConApp,
+ mkFunTy, tcSplitTyConApp_maybe,
+ tcSplitForAllTys, tcSplitFunTys, tcTyConAppArgs,
+ )
+
+import BasicTypes ( Boxity(..) )
+import HscTypes ( ForeignStubs(..) )
+import ForeignCall ( ForeignCall(..), CCallSpec(..),
+ Safety(..), playSafe,
+ CExportSpec(..), CLabelString,
+ CCallConv(..), ccallConvToInt,
+ ccallConvAttribute
+ )
+import TysWiredIn ( unitTy, tupleTyCon )
+import TysPrim ( addrPrimTy, mkStablePtrPrimTy, alphaTy )
+import PrelNames ( hasKey, ioTyConKey, stablePtrTyConName, newStablePtrName, bindIOName,
+ checkDotnetResName )
+import BasicTypes ( Activation( NeverActive ) )
+import SrcLoc ( Located(..), unLoc )
+import Outputable
+import Maybe ( fromJust, isNothing )
+import FastString
+\end{code}
+
+Desugaring of @foreign@ declarations is naturally split up into
+parts, an @import@ and an @export@ part. A @foreign import@
+declaration
+\begin{verbatim}
+ foreign import cc nm f :: prim_args -> IO prim_res
+\end{verbatim}
+is the same as
+\begin{verbatim}
+ f :: prim_args -> IO prim_res
+ f a1 ... an = _ccall_ nm cc a1 ... an
+\end{verbatim}
+so we reuse the desugaring code in @DsCCall@ to deal with these.
+
+\begin{code}
+type Binding = (Id, CoreExpr) -- No rec/nonrec structure;
+ -- the occurrence analyser will sort it all out
+
+dsForeigns :: [LForeignDecl Id]
+ -> DsM (ForeignStubs, [Binding])
+dsForeigns []
+ = returnDs (NoStubs, [])
+dsForeigns fos
+ = foldlDs combine (ForeignStubs empty empty [] [], []) fos
+ where
+ combine stubs (L loc decl) = putSrcSpanDs loc (combine1 stubs decl)
+
+ combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f)
+ (ForeignImport id _ spec depr)
+ = traceIf (text "fi start" <+> ppr id) `thenDs` \ _ ->
+ dsFImport (unLoc id) spec `thenDs` \ (bs, h, c, mbhd) ->
+ warnDepr depr `thenDs` \ _ ->
+ traceIf (text "fi end" <+> ppr id) `thenDs` \ _ ->
+ returnDs (ForeignStubs (h $$ acc_h)
+ (c $$ acc_c)
+ (addH mbhd acc_hdrs)
+ acc_feb,
+ bs ++ acc_f)
+
+ combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f)
+ (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv)) depr)
+ = dsFExport id (idType id)
+ ext_nm cconv False `thenDs` \(h, c, _, _) ->
+ warnDepr depr `thenDs` \_ ->
+ returnDs (ForeignStubs (h $$ acc_h) (c $$ acc_c) acc_hdrs (id:acc_feb),
+ acc_f)
+
+ addH Nothing ls = ls
+ addH (Just e) ls
+ | e `elem` ls = ls
+ | otherwise = e:ls
+
+ warnDepr False = returnDs ()
+ warnDepr True = dsWarn msg
+ where
+ msg = ptext SLIT("foreign declaration uses deprecated non-standard syntax")
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Foreign import}
+%* *
+%************************************************************************
+
+Desugaring foreign imports is just the matter of creating a binding
+that on its RHS unboxes its arguments, performs the external call
+(using the @CCallOp@ primop), before boxing the result up and returning it.
+
+However, we create a worker/wrapper pair, thus:
+
+ foreign import f :: Int -> IO Int
+==>
+ f x = IO ( \s -> case x of { I# x# ->
+ case fw s x# of { (# s1, y# #) ->
+ (# s1, I# y# #)}})
+
+ fw s x# = ccall f s x#
+
+The strictness/CPR analyser won't do this automatically because it doesn't look
+inside returned tuples; but inlining this wrapper is a Really Good Idea
+because it exposes the boxing to the call site.
+
+\begin{code}
+dsFImport :: Id
+ -> ForeignImport
+ -> DsM ([Binding], SDoc, SDoc, Maybe FastString)
+dsFImport id (CImport cconv safety header lib spec)
+ = dsCImport id spec cconv safety no_hdrs `thenDs` \(ids, h, c) ->
+ returnDs (ids, h, c, if no_hdrs then Nothing else Just header)
+ where
+ no_hdrs = nullFS header
+
+ -- FIXME: the `lib' field is needed for .NET ILX generation when invoking
+ -- routines that are external to the .NET runtime, but GHC doesn't
+ -- support such calls yet; if `nullFastString lib', the value was not given
+dsFImport id (DNImport spec)
+ = dsFCall id (DNCall spec) True {- No headers -} `thenDs` \(ids, h, c) ->
+ returnDs (ids, h, c, Nothing)
+
+dsCImport :: Id
+ -> CImportSpec
+ -> CCallConv
+ -> Safety
+ -> Bool -- True <=> no headers in the f.i decl
+ -> DsM ([Binding], SDoc, SDoc)
+dsCImport id (CLabel cid) _ _ no_hdrs
+ = resultWrapper (idType id) `thenDs` \ (resTy, foRhs) ->
+ ASSERT(fromJust resTy `coreEqType` addrPrimTy) -- typechecker ensures this
+ let rhs = foRhs (mkLit (MachLabel cid Nothing)) in
+ returnDs ([(setImpInline no_hdrs id, rhs)], empty, empty)
+dsCImport id (CFunction target) cconv safety no_hdrs
+ = dsFCall id (CCall (CCallSpec target cconv safety)) no_hdrs
+dsCImport id CWrapper cconv _ _
+ = dsFExportDynamic id cconv
+
+setImpInline :: Bool -- True <=> No #include headers
+ -- in the foreign import declaration
+ -> Id -> Id
+-- If there is a #include header in the foreign import
+-- we make the worker non-inlinable, because we currently
+-- don't keep the #include stuff in the CCallId, and hence
+-- it won't be visible in the importing module, which can be
+-- fatal.
+-- (The #include stuff is just collected from the foreign import
+-- decls in a module.)
+-- If you want to do cross-module inlining of the c-calls themselves,
+-- put the #include stuff in the package spec, not the foreign
+-- import decl.
+setImpInline True id = id
+setImpInline False id = id `setInlinePragma` NeverActive
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Foreign calls}
+%* *
+%************************************************************************
+
+\begin{code}
+dsFCall fn_id fcall no_hdrs
+ = let
+ ty = idType fn_id
+ (tvs, fun_ty) = tcSplitForAllTys ty
+ (arg_tys, io_res_ty) = tcSplitFunTys fun_ty
+ -- Must use tcSplit* functions because we want to
+ -- see that (IO t) in the corner
+ in
+ newSysLocalsDs arg_tys `thenDs` \ args ->
+ mapAndUnzipDs unboxArg (map Var args) `thenDs` \ (val_args, arg_wrappers) ->
+
+ let
+ work_arg_ids = [v | Var v <- val_args] -- All guaranteed to be vars
+
+ forDotnet =
+ case fcall of
+ DNCall{} -> True
+ _ -> False
+
+ topConDs
+ | forDotnet =
+ dsLookupGlobalId checkDotnetResName `thenDs` \ check_id ->
+ return (Just check_id)
+ | otherwise = return Nothing
+
+ augmentResultDs
+ | forDotnet =
+ newSysLocalDs addrPrimTy `thenDs` \ err_res ->
+ returnDs (\ (mb_res_ty, resWrap) ->
+ case mb_res_ty of
+ Nothing -> (Just (mkTyConApp (tupleTyCon Unboxed 1)
+ [ addrPrimTy ]),
+ resWrap)
+ Just x -> (Just (mkTyConApp (tupleTyCon Unboxed 2)
+ [ x, addrPrimTy ]),
+ resWrap))
+ | otherwise = returnDs id
+ in
+ augmentResultDs `thenDs` \ augment ->
+ topConDs `thenDs` \ topCon ->
+ boxResult augment topCon io_res_ty `thenDs` \ (ccall_result_ty, res_wrapper) ->
+
+ newUnique `thenDs` \ ccall_uniq ->
+ newUnique `thenDs` \ work_uniq ->
+ let
+ -- Build the worker
+ worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
+ the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty
+ work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)
+ work_id = setImpInline no_hdrs $ -- See comments with setImpInline
+ mkSysLocal FSLIT("$wccall") work_uniq worker_ty
+
+ -- Build the wrapper
+ work_app = mkApps (mkVarApps (Var work_id) tvs) val_args
+ wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers
+ wrap_rhs = mkInlineMe (mkLams (tvs ++ args) wrapper_body)
+ in
+ returnDs ([(work_id, work_rhs), (fn_id, wrap_rhs)], empty, empty)
+
+unsafe_call (CCall (CCallSpec _ _ safety)) = playSafe safety
+unsafe_call (DNCall _) = False
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Foreign export}
+%* *
+%************************************************************************
+
+The function that does most of the work for `@foreign export@' declarations.
+(see below for the boilerplate code a `@foreign export@' declaration expands
+ into.)
+
+For each `@foreign export foo@' in a module M we generate:
+\begin{itemize}
+\item a C function `@foo@', which calls
+\item a Haskell stub `@M.$ffoo@', which calls
+\end{itemize}
+the user-written Haskell function `@M.foo@'.
+
+\begin{code}
+dsFExport :: Id -- Either the exported Id,
+ -- or the foreign-export-dynamic constructor
+ -> Type -- The type of the thing callable from C
+ -> CLabelString -- The name to export to C land
+ -> CCallConv
+ -> Bool -- True => foreign export dynamic
+ -- so invoke IO action that's hanging off
+ -- the first argument's stable pointer
+ -> DsM ( SDoc -- contents of Module_stub.h
+ , SDoc -- contents of Module_stub.c
+ , [MachRep] -- primitive arguments expected by stub function
+ , Int -- size of args to stub function
+ )
+
+dsFExport fn_id ty ext_name cconv isDyn
+ =
+ let
+ (_tvs,sans_foralls) = tcSplitForAllTys ty
+ (fe_arg_tys', orig_res_ty) = tcSplitFunTys sans_foralls
+ -- We must use tcSplits here, because we want to see
+ -- the (IO t) in the corner of the type!
+ fe_arg_tys | isDyn = tail fe_arg_tys'
+ | otherwise = fe_arg_tys'
+ in
+ -- Look at the result type of the exported function, orig_res_ty
+ -- If it's IO t, return (t, True)
+ -- If it's plain t, return (t, False)
+ (case tcSplitTyConApp_maybe orig_res_ty of
+ -- We must use tcSplit here so that we see the (IO t) in
+ -- the type. [IO t is transparent to plain splitTyConApp.]
+
+ Just (ioTyCon, [res_ty])
+ -> ASSERT( ioTyCon `hasKey` ioTyConKey )
+ -- The function already returns IO t
+ returnDs (res_ty, True)
+
+ other -> -- The function returns t
+ returnDs (orig_res_ty, False)
+ )
+ `thenDs` \ (res_ty, -- t
+ is_IO_res_ty) -> -- Bool
+ returnDs $
+ mkFExportCBits ext_name
+ (if isDyn then Nothing else Just fn_id)
+ fe_arg_tys res_ty is_IO_res_ty cconv
+\end{code}
+
+@foreign export dynamic@ lets you dress up Haskell IO actions
+of some fixed type behind an externally callable interface (i.e.,
+as a C function pointer). Useful for callbacks and stuff.
+
+\begin{verbatim}
+foreign export dynamic f :: (Addr -> Int -> IO Int) -> IO Addr
+
+-- Haskell-visible constructor, which is generated from the above:
+-- SUP: No check for NULL from createAdjustor anymore???
+
+f :: (Addr -> Int -> IO Int) -> IO Addr
+f cback =
+ bindIO (newStablePtr cback)
+ (\StablePtr sp# -> IO (\s1# ->
+ case _ccall_ createAdjustor cconv sp# ``f_helper'' s1# of
+ (# s2#, a# #) -> (# s2#, A# a# #)))
+
+foreign export "f_helper" f_helper :: StablePtr (Addr -> Int -> IO Int) -> Addr -> Int -> IO Int
+-- `special' foreign export that invokes the closure pointed to by the
+-- first argument.
+\end{verbatim}
+
+\begin{code}
+dsFExportDynamic :: Id
+ -> CCallConv
+ -> DsM ([Binding], SDoc, SDoc)
+dsFExportDynamic id cconv
+ = newSysLocalDs ty `thenDs` \ fe_id ->
+ getModuleDs `thenDs` \ mod_name ->
+ let
+ -- hack: need to get at the name of the C stub we're about to generate.
+ fe_nm = mkFastString (unpackFS (zEncodeFS (moduleFS mod_name)) ++ "_" ++ toCName fe_id)
+ in
+ newSysLocalDs arg_ty `thenDs` \ cback ->
+ dsLookupGlobalId newStablePtrName `thenDs` \ newStablePtrId ->
+ dsLookupTyCon stablePtrTyConName `thenDs` \ stable_ptr_tycon ->
+ let
+ mk_stbl_ptr_app = mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]
+ stable_ptr_ty = mkTyConApp stable_ptr_tycon [arg_ty]
+ export_ty = mkFunTy stable_ptr_ty arg_ty
+ in
+ dsLookupGlobalId bindIOName `thenDs` \ bindIOId ->
+ newSysLocalDs stable_ptr_ty `thenDs` \ stbl_value ->
+ dsFExport id export_ty fe_nm cconv True
+ `thenDs` \ (h_code, c_code, arg_reps, args_size) ->
+ let
+ stbl_app cont ret_ty = mkApps (Var bindIOId)
+ [ Type stable_ptr_ty
+ , Type ret_ty
+ , mk_stbl_ptr_app
+ , cont
+ ]
+ {-
+ The arguments to the external function which will
+ create a little bit of (template) code on the fly
+ for allowing the (stable pointed) Haskell closure
+ to be entered using an external calling convention
+ (stdcall, ccall).
+ -}
+ adj_args = [ mkIntLitInt (ccallConvToInt cconv)
+ , Var stbl_value
+ , mkLit (MachLabel fe_nm mb_sz_args)
+ , mkLit (mkStringLit arg_type_info)
+ ]
+ -- name of external entry point providing these services.
+ -- (probably in the RTS.)
+ adjustor = FSLIT("createAdjustor")
+
+ arg_type_info = map repCharCode arg_reps
+ repCharCode F32 = 'f'
+ repCharCode F64 = 'd'
+ repCharCode I64 = 'l'
+ repCharCode _ = 'i'
+
+ -- Determine the number of bytes of arguments to the stub function,
+ -- so that we can attach the '@N' suffix to its label if it is a
+ -- stdcall on Windows.
+ mb_sz_args = case cconv of
+ StdCallConv -> Just args_size
+ _ -> Nothing
+
+ in
+ dsCCall adjustor adj_args PlayRisky io_res_ty `thenDs` \ ccall_adj ->
+ -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback
+ let ccall_adj_ty = exprType ccall_adj
+ ccall_io_adj = mkLams [stbl_value] $
+ Note (Coerce io_res_ty ccall_adj_ty)
+ ccall_adj
+ io_app = mkLams tvs $
+ mkLams [cback] $
+ stbl_app ccall_io_adj res_ty
+ fed = (id `setInlinePragma` NeverActive, io_app)
+ -- Never inline the f.e.d. function, because the litlit
+ -- might not be in scope in other modules.
+ in
+ returnDs ([fed], h_code, c_code)
+
+ where
+ ty = idType id
+ (tvs,sans_foralls) = tcSplitForAllTys ty
+ ([arg_ty], io_res_ty) = tcSplitFunTys sans_foralls
+ [res_ty] = tcTyConAppArgs io_res_ty
+ -- Must use tcSplit* to see the (IO t), which is a newtype
+
+toCName :: Id -> String
+toCName i = showSDoc (pprCode CStyle (ppr (idName i)))
+\end{code}
+
+%*
+%
+\subsection{Generating @foreign export@ stubs}
+%
+%*
+
+For each @foreign export@ function, a C stub function is generated.
+The C stub constructs the application of the exported Haskell function
+using the hugs/ghc rts invocation API.
+
+\begin{code}
+mkFExportCBits :: FastString
+ -> Maybe Id -- Just==static, Nothing==dynamic
+ -> [Type]
+ -> Type
+ -> Bool -- True <=> returns an IO type
+ -> CCallConv
+ -> (SDoc,
+ SDoc,
+ [MachRep], -- the argument reps
+ Int -- total size of arguments
+ )
+mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
+ = (header_bits, c_bits,
+ [rep | (_,_,_,rep) <- arg_info], -- just the real args
+ sum [ machRepByteWidth rep | (_,_,_,rep) <- aug_arg_info] -- all the args
+ )
+ where
+ -- list the arguments to the C function
+ arg_info :: [(SDoc, -- arg name
+ SDoc, -- C type
+ Type, -- Haskell type
+ MachRep)] -- the MachRep
+ arg_info = [ (text ('a':show n), showStgType ty, ty,
+ typeMachRep (getPrimTyOf ty))
+ | (ty,n) <- zip arg_htys [1..] ]
+
+ -- add some auxiliary args; the stable ptr in the wrapper case, and
+ -- a slot for the dummy return address in the wrapper + ccall case
+ aug_arg_info
+ | isNothing maybe_target = stable_ptr_arg : insertRetAddr cc arg_info
+ | otherwise = arg_info
+
+ stable_ptr_arg =
+ (text "the_stableptr", text "StgStablePtr", undefined,
+ typeMachRep (mkStablePtrPrimTy alphaTy))
+
+ -- stuff to do with the return type of the C function
+ res_hty_is_unit = res_hty `coreEqType` unitTy -- Look through any newtypes
+
+ cResType | res_hty_is_unit = text "void"
+ | otherwise = showStgType res_hty
+
+ -- Now we can cook up the prototype for the exported function.
+ pprCconv = case cc of
+ CCallConv -> empty
+ StdCallConv -> text (ccallConvAttribute cc)
+
+ header_bits = ptext SLIT("extern") <+> fun_proto <> semi
+
+ fun_proto = cResType <+> pprCconv <+> ftext c_nm <>
+ parens (hsep (punctuate comma (map (\(nm,ty,_,_) -> ty <+> nm)
+ aug_arg_info)))
+
+ -- the target which will form the root of what we ask rts_evalIO to run
+ the_cfun
+ = case maybe_target of
+ Nothing -> text "(StgClosure*)deRefStablePtr(the_stableptr)"
+ Just hs_fn -> char '&' <> ppr hs_fn <> text "_closure"
+
+ cap = text "cap" <> comma
+
+ -- the expression we give to rts_evalIO
+ expr_to_run
+ = foldl appArg the_cfun arg_info -- NOT aug_arg_info
+ where
+ appArg acc (arg_cname, _, arg_hty, _)
+ = text "rts_apply"
+ <> parens (cap <> acc <> comma <> mkHObj arg_hty <> parens (cap <> arg_cname))
+
+ -- various other bits for inside the fn
+ declareResult = text "HaskellObj ret;"
+ declareCResult | res_hty_is_unit = empty
+ | otherwise = cResType <+> text "cret;"
+
+ assignCResult | res_hty_is_unit = empty
+ | otherwise =
+ text "cret=" <> unpackHObj res_hty <> parens (text "ret") <> semi
+
+ -- an extern decl for the fn being called
+ extern_decl
+ = case maybe_target of
+ Nothing -> empty
+ Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi
+
+
+ -- Initialise foreign exports by registering a stable pointer from an
+ -- __attribute__((constructor)) function.
+ -- The alternative is to do this from stginit functions generated in
+ -- codeGen/CodeGen.lhs; however, stginit functions have a negative impact
+ -- on binary sizes and link times because the static linker will think that
+ -- all modules that are imported directly or indirectly are actually used by
+ -- the program.
+ -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)
+
+ initialiser
+ = case maybe_target of
+ Nothing -> empty
+ Just hs_fn ->
+ vcat
+ [ text "static void stginit_export_" <> ppr hs_fn
+ <> text "() __attribute__((constructor));"
+ , text "static void stginit_export_" <> ppr hs_fn <> text "()"
+ , braces (text "getStablePtr"
+ <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
+ <> semi)
+ ]
+
+ -- finally, the whole darn thing
+ c_bits =
+ space $$
+ extern_decl $$
+ fun_proto $$
+ vcat
+ [ lbrace
+ , text "Capability *cap;"
+ , declareResult
+ , declareCResult
+ , text "cap = rts_lock();"
+ -- create the application + perform it.
+ , text "cap=rts_evalIO" <> parens (
+ cap <>
+ text "rts_apply" <> parens (
+ cap <>
+ text "(HaskellObj)"
+ <> text (if is_IO_res_ty
+ then "runIO_closure"
+ else "runNonIO_closure")
+ <> comma
+ <> expr_to_run
+ ) <+> comma
+ <> text "&ret"
+ ) <> semi
+ , text "rts_checkSchedStatus" <> parens (doubleQuotes (ftext c_nm)
+ <> comma <> text "cap") <> semi
+ , assignCResult
+ , text "rts_unlock(cap);"
+ , if res_hty_is_unit then empty
+ else text "return cret;"
+ , rbrace
+ ] $$
+ initialiser
+
+-- NB. the calculation here isn't strictly speaking correct.
+-- We have a primitive Haskell type (eg. Int#, Double#), and
+-- we want to know the size, when passed on the C stack, of
+-- the associated C type (eg. HsInt, HsDouble). We don't have
+-- this information to hand, but we know what GHC's conventions
+-- are for passing around the primitive Haskell types, so we
+-- use that instead. I hope the two coincide --SDM
+typeMachRep ty = argMachRep (typeCgRep ty)
+
+mkHObj :: Type -> SDoc
+mkHObj t = text "rts_mk" <> text (showFFIType t)
+
+unpackHObj :: Type -> SDoc
+unpackHObj t = text "rts_get" <> text (showFFIType t)
+
+showStgType :: Type -> SDoc
+showStgType t = text "Hs" <> text (showFFIType t)
+
+showFFIType :: Type -> String
+showFFIType t = getOccString (getName tc)
+ where
+ tc = case tcSplitTyConApp_maybe (repType t) of
+ Just (tc,_) -> tc
+ Nothing -> pprPanic "showFFIType" (ppr t)
+
+#if !defined(x86_64_TARGET_ARCH)
+insertRetAddr CCallConv args = ret_addr_arg : args
+insertRetAddr _ args = args
+#else
+-- On x86_64 we insert the return address after the 6th
+-- integer argument, because this is the point at which we
+-- need to flush a register argument to the stack (See rts/Adjustor.c for
+-- details).
+insertRetAddr CCallConv args = go 0 args
+ where go 6 args = ret_addr_arg : args
+ go n (arg@(_,_,_,rep):args)
+ | I64 <- rep = arg : go (n+1) args
+ | otherwise = arg : go n args
+ go n [] = []
+insertRetAddr _ args = args
+#endif
+
+ret_addr_arg = (text "original_return_addr", text "void*", undefined,
+ typeMachRep addrPrimTy)
+
+-- This function returns the primitive type associated with the boxed
+-- type argument to a foreign export (eg. Int ==> Int#). It assumes
+-- that all the types we are interested in have a single constructor
+-- with a single primitive-typed argument, which is true for all of the legal
+-- foreign export argument types (see TcType.legalFEArgTyCon).
+getPrimTyOf :: Type -> Type
+getPrimTyOf ty =
+ case splitProductType_maybe (repType ty) of
+ Just (_, _, data_con, [prim_ty]) ->
+ ASSERT(dataConSourceArity data_con == 1)
+ ASSERT2(isUnLiftedType prim_ty, ppr prim_ty)
+ prim_ty
+ _other -> pprPanic "DsForeign.getPrimTyOf" (ppr ty)
+\end{code}
diff --git a/compiler/deSugar/DsGRHSs.lhs b/compiler/deSugar/DsGRHSs.lhs
new file mode 100644
index 0000000000..eea61bafb2
--- /dev/null
+++ b/compiler/deSugar/DsGRHSs.lhs
@@ -0,0 +1,128 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsGRHSs]{Matching guarded right-hand-sides (GRHSs)}
+
+\begin{code}
+module DsGRHSs ( dsGuarded, dsGRHSs ) where
+
+#include "HsVersions.h"
+
+import {-# SOURCE #-} DsExpr ( dsLExpr, dsLocalBinds )
+import {-# SOURCE #-} Match ( matchSinglePat )
+
+import HsSyn ( Stmt(..), HsExpr(..), GRHSs(..), GRHS(..),
+ LHsExpr, HsMatchContext(..), Pat(..) )
+import CoreSyn ( CoreExpr )
+import Var ( Id )
+import Type ( Type )
+
+import DsMonad
+import DsUtils
+import Unique ( Uniquable(..) )
+import PrelInfo ( nON_EXHAUSTIVE_GUARDS_ERROR_ID )
+import TysWiredIn ( trueDataConId )
+import PrelNames ( otherwiseIdKey, hasKey )
+import Name ( Name )
+import SrcLoc ( unLoc, Located(..) )
+\end{code}
+
+@dsGuarded@ is used for both @case@ expressions and pattern bindings.
+It desugars:
+\begin{verbatim}
+ | g1 -> e1
+ ...
+ | gn -> en
+ where binds
+\end{verbatim}
+producing an expression with a runtime error in the corner if
+necessary. The type argument gives the type of the @ei@.
+
+\begin{code}
+dsGuarded :: GRHSs Id -> Type -> DsM CoreExpr
+
+dsGuarded grhss rhs_ty
+ = dsGRHSs PatBindRhs [] grhss rhs_ty `thenDs` \ match_result ->
+ mkErrorAppDs nON_EXHAUSTIVE_GUARDS_ERROR_ID rhs_ty "" `thenDs` \ error_expr ->
+ extractMatchResult match_result error_expr
+\end{code}
+
+In contrast, @dsGRHSs@ produces a @MatchResult@.
+
+\begin{code}
+dsGRHSs :: HsMatchContext Name -> [Pat Id] -- These are to build a MatchContext from
+ -> GRHSs Id -- Guarded RHSs
+ -> Type -- Type of RHS
+ -> DsM MatchResult
+
+dsGRHSs hs_ctx pats (GRHSs grhss binds) rhs_ty
+ = mappM (dsGRHS hs_ctx pats rhs_ty) grhss `thenDs` \ match_results ->
+ let
+ match_result1 = foldr1 combineMatchResults match_results
+ match_result2 = adjustMatchResultDs (dsLocalBinds binds) match_result1
+ -- NB: nested dsLet inside matchResult
+ in
+ returnDs match_result2
+
+dsGRHS hs_ctx pats rhs_ty (L loc (GRHS guards rhs))
+ = matchGuards (map unLoc guards) hs_ctx rhs rhs_ty
+\end{code}
+
+
+%************************************************************************
+%* *
+%* matchGuard : make a MatchResult from a guarded RHS *
+%* *
+%************************************************************************
+
+\begin{code}
+matchGuards :: [Stmt Id] -- Guard
+ -> HsMatchContext Name -- Context
+ -> LHsExpr Id -- RHS
+ -> Type -- Type of RHS of guard
+ -> DsM MatchResult
+
+-- See comments with HsExpr.Stmt re what an ExprStmt means
+-- Here we must be in a guard context (not do-expression, nor list-comp)
+
+matchGuards [] ctx rhs rhs_ty
+ = do { core_rhs <- dsLExpr rhs
+ ; return (cantFailMatchResult core_rhs) }
+
+ -- ExprStmts must be guards
+ -- Turn an "otherwise" guard is a no-op. This ensures that
+ -- you don't get a "non-exhaustive eqns" message when the guards
+ -- finish in "otherwise".
+ -- NB: The success of this clause depends on the typechecker not
+ -- wrapping the 'otherwise' in empty HsTyApp or HsCoerce constructors
+ -- If it does, you'll get bogus overlap warnings
+matchGuards (ExprStmt (L _ (HsVar v)) _ _ : stmts) ctx rhs rhs_ty
+ | v `hasKey` otherwiseIdKey
+ || v `hasKey` getUnique trueDataConId
+ -- trueDataConId doesn't have the same unique as trueDataCon
+ = matchGuards stmts ctx rhs rhs_ty
+
+matchGuards (ExprStmt expr _ _ : stmts) ctx rhs rhs_ty
+ = matchGuards stmts ctx rhs rhs_ty `thenDs` \ match_result ->
+ dsLExpr expr `thenDs` \ pred_expr ->
+ returnDs (mkGuardedMatchResult pred_expr match_result)
+
+matchGuards (LetStmt binds : stmts) ctx rhs rhs_ty
+ = matchGuards stmts ctx rhs rhs_ty `thenDs` \ match_result ->
+ returnDs (adjustMatchResultDs (dsLocalBinds binds) match_result)
+ -- NB the dsLet occurs inside the match_result
+ -- Reason: dsLet takes the body expression as its argument
+ -- so we can't desugar the bindings without the
+ -- body expression in hand
+
+matchGuards (BindStmt pat bind_rhs _ _ : stmts) ctx rhs rhs_ty
+ = matchGuards stmts ctx rhs rhs_ty `thenDs` \ match_result ->
+ dsLExpr bind_rhs `thenDs` \ core_rhs ->
+ matchSinglePat core_rhs ctx pat rhs_ty match_result
+\end{code}
+
+Should {\em fail} if @e@ returns @D@
+\begin{verbatim}
+f x | p <- e', let C y# = e, f y# = r1
+ | otherwise = r2
+\end{verbatim}
diff --git a/compiler/deSugar/DsListComp.lhs b/compiler/deSugar/DsListComp.lhs
new file mode 100644
index 0000000000..6bb41a92e4
--- /dev/null
+++ b/compiler/deSugar/DsListComp.lhs
@@ -0,0 +1,516 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsListComp]{Desugaring list comprehensions and array comprehensions}
+
+\begin{code}
+module DsListComp ( dsListComp, dsPArrComp ) where
+
+#include "HsVersions.h"
+
+import {-# SOURCE #-} DsExpr ( dsLExpr, dsLocalBinds )
+
+import BasicTypes ( Boxity(..) )
+import HsSyn
+import TcHsSyn ( hsPatType, mkVanillaTuplePat )
+import CoreSyn
+
+import DsMonad -- the monadery used in the desugarer
+import DsUtils
+
+import DynFlags ( DynFlag(..), dopt )
+import StaticFlags ( opt_RulesOff )
+import CoreUtils ( exprType, mkIfThenElse )
+import Id ( idType )
+import Var ( Id )
+import Type ( mkTyVarTy, mkFunTys, mkFunTy, Type,
+ splitTyConApp_maybe )
+import TysPrim ( alphaTyVar )
+import TysWiredIn ( nilDataCon, consDataCon, trueDataConId, falseDataConId,
+ unitDataConId, unitTy, mkListTy, parrTyCon )
+import Match ( matchSimply )
+import PrelNames ( foldrName, buildName, replicatePName, mapPName,
+ filterPName, zipPName, crossPName )
+import PrelInfo ( pAT_ERROR_ID )
+import SrcLoc ( noLoc, unLoc )
+import Panic ( panic )
+\end{code}
+
+List comprehensions may be desugared in one of two ways: ``ordinary''
+(as you would expect if you read SLPJ's book) and ``with foldr/build
+turned on'' (if you read Gill {\em et al.}'s paper on the subject).
+
+There will be at least one ``qualifier'' in the input.
+
+\begin{code}
+dsListComp :: [LStmt Id]
+ -> LHsExpr Id
+ -> Type -- Type of list elements
+ -> DsM CoreExpr
+dsListComp lquals body elt_ty
+ = getDOptsDs `thenDs` \dflags ->
+ let
+ quals = map unLoc lquals
+ in
+ if opt_RulesOff || dopt Opt_IgnoreInterfacePragmas dflags
+ -- Either rules are switched off, or we are ignoring what there are;
+ -- Either way foldr/build won't happen, so use the more efficient
+ -- Wadler-style desugaring
+ || isParallelComp quals
+ -- Foldr-style desugaring can't handle
+ -- parallel list comprehensions
+ then deListComp quals body (mkNilExpr elt_ty)
+
+ else -- Foldr/build should be enabled, so desugar
+ -- into foldrs and builds
+ newTyVarsDs [alphaTyVar] `thenDs` \ [n_tyvar] ->
+ let
+ n_ty = mkTyVarTy n_tyvar
+ c_ty = mkFunTys [elt_ty, n_ty] n_ty
+ in
+ newSysLocalsDs [c_ty,n_ty] `thenDs` \ [c, n] ->
+ dfListComp c n quals body `thenDs` \ result ->
+ dsLookupGlobalId buildName `thenDs` \ build_id ->
+ returnDs (Var build_id `App` Type elt_ty
+ `App` mkLams [n_tyvar, c, n] result)
+
+ where isParallelComp (ParStmt bndrstmtss : _) = True
+ isParallelComp _ = False
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[DsListComp-ordinary]{Ordinary desugaring of list comprehensions}
+%* *
+%************************************************************************
+
+Just as in Phil's chapter~7 in SLPJ, using the rules for
+optimally-compiled list comprehensions. This is what Kevin followed
+as well, and I quite happily do the same. The TQ translation scheme
+transforms a list of qualifiers (either boolean expressions or
+generators) into a single expression which implements the list
+comprehension. Because we are generating 2nd-order polymorphic
+lambda-calculus, calls to NIL and CONS must be applied to a type
+argument, as well as their usual value arguments.
+\begin{verbatim}
+TE << [ e | qs ] >> = TQ << [ e | qs ] ++ Nil (typeOf e) >>
+
+(Rule C)
+TQ << [ e | ] ++ L >> = Cons (typeOf e) TE <<e>> TE <<L>>
+
+(Rule B)
+TQ << [ e | b , qs ] ++ L >> =
+ if TE << b >> then TQ << [ e | qs ] ++ L >> else TE << L >>
+
+(Rule A')
+TQ << [ e | p <- L1, qs ] ++ L2 >> =
+ letrec
+ h = \ u1 ->
+ case u1 of
+ [] -> TE << L2 >>
+ (u2 : u3) ->
+ (( \ TE << p >> -> ( TQ << [e | qs] ++ (h u3) >> )) u2)
+ [] (h u3)
+ in
+ h ( TE << L1 >> )
+
+"h", "u1", "u2", and "u3" are new variables.
+\end{verbatim}
+
+@deListComp@ is the TQ translation scheme. Roughly speaking, @dsExpr@
+is the TE translation scheme. Note that we carry around the @L@ list
+already desugared. @dsListComp@ does the top TE rule mentioned above.
+
+To the above, we add an additional rule to deal with parallel list
+comprehensions. The translation goes roughly as follows:
+ [ e | p1 <- e11, let v1 = e12, p2 <- e13
+ | q1 <- e21, let v2 = e22, q2 <- e23]
+ =>
+ [ e | ((x1, .., xn), (y1, ..., ym)) <-
+ zip [(x1,..,xn) | p1 <- e11, let v1 = e12, p2 <- e13]
+ [(y1,..,ym) | q1 <- e21, let v2 = e22, q2 <- e23]]
+where (x1, .., xn) are the variables bound in p1, v1, p2
+ (y1, .., ym) are the variables bound in q1, v2, q2
+
+In the translation below, the ParStmt branch translates each parallel branch
+into a sub-comprehension, and desugars each independently. The resulting lists
+are fed to a zip function, we create a binding for all the variables bound in all
+the comprehensions, and then we hand things off the the desugarer for bindings.
+The zip function is generated here a) because it's small, and b) because then we
+don't have to deal with arbitrary limits on the number of zip functions in the
+prelude, nor which library the zip function came from.
+The introduced tuples are Boxed, but only because I couldn't get it to work
+with the Unboxed variety.
+
+\begin{code}
+deListComp :: [Stmt Id] -> LHsExpr Id -> CoreExpr -> DsM CoreExpr
+
+deListComp (ParStmt stmtss_w_bndrs : quals) body list
+ = mappM do_list_comp stmtss_w_bndrs `thenDs` \ exps ->
+ mkZipBind qual_tys `thenDs` \ (zip_fn, zip_rhs) ->
+
+ -- Deal with [e | pat <- zip l1 .. ln] in example above
+ deBindComp pat (Let (Rec [(zip_fn, zip_rhs)]) (mkApps (Var zip_fn) exps))
+ quals body list
+
+ where
+ bndrs_s = map snd stmtss_w_bndrs
+
+ -- pat is the pattern ((x1,..,xn), (y1,..,ym)) in the example above
+ pat = mkTuplePat pats
+ pats = map mk_hs_tuple_pat bndrs_s
+
+ -- Types of (x1,..,xn), (y1,..,yn) etc
+ qual_tys = map mk_bndrs_tys bndrs_s
+
+ do_list_comp (stmts, bndrs)
+ = dsListComp stmts (mk_hs_tuple_expr bndrs)
+ (mk_bndrs_tys bndrs)
+
+ mk_bndrs_tys bndrs = mkCoreTupTy (map idType bndrs)
+
+ -- Last: the one to return
+deListComp [] body list -- Figure 7.4, SLPJ, p 135, rule C above
+ = dsLExpr body `thenDs` \ core_body ->
+ returnDs (mkConsExpr (exprType core_body) core_body list)
+
+ -- Non-last: must be a guard
+deListComp (ExprStmt guard _ _ : quals) body list -- rule B above
+ = dsLExpr guard `thenDs` \ core_guard ->
+ deListComp quals body list `thenDs` \ core_rest ->
+ returnDs (mkIfThenElse core_guard core_rest list)
+
+-- [e | let B, qs] = let B in [e | qs]
+deListComp (LetStmt binds : quals) body list
+ = deListComp quals body list `thenDs` \ core_rest ->
+ dsLocalBinds binds core_rest
+
+deListComp (BindStmt pat list1 _ _ : quals) body core_list2 -- rule A' above
+ = dsLExpr list1 `thenDs` \ core_list1 ->
+ deBindComp pat core_list1 quals body core_list2
+\end{code}
+
+
+\begin{code}
+deBindComp pat core_list1 quals body core_list2
+ = let
+ u3_ty@u1_ty = exprType core_list1 -- two names, same thing
+
+ -- u1_ty is a [alpha] type, and u2_ty = alpha
+ u2_ty = hsPatType pat
+
+ res_ty = exprType core_list2
+ h_ty = u1_ty `mkFunTy` res_ty
+ in
+ newSysLocalsDs [h_ty, u1_ty, u2_ty, u3_ty] `thenDs` \ [h, u1, u2, u3] ->
+
+ -- the "fail" value ...
+ let
+ core_fail = App (Var h) (Var u3)
+ letrec_body = App (Var h) core_list1
+ in
+ deListComp quals body core_fail `thenDs` \ rest_expr ->
+ matchSimply (Var u2) (StmtCtxt ListComp) pat
+ rest_expr core_fail `thenDs` \ core_match ->
+ let
+ rhs = Lam u1 $
+ Case (Var u1) u1 res_ty
+ [(DataAlt nilDataCon, [], core_list2),
+ (DataAlt consDataCon, [u2, u3], core_match)]
+ -- Increasing order of tag
+ in
+ returnDs (Let (Rec [(h, rhs)]) letrec_body)
+\end{code}
+
+
+\begin{code}
+mkZipBind :: [Type] -> DsM (Id, CoreExpr)
+-- mkZipBind [t1, t2]
+-- = (zip, \as1:[t1] as2:[t2]
+-- -> case as1 of
+-- [] -> []
+-- (a1:as'1) -> case as2 of
+-- [] -> []
+-- (a2:as'2) -> (a2,a2) : zip as'1 as'2)]
+
+mkZipBind elt_tys
+ = mappM newSysLocalDs list_tys `thenDs` \ ass ->
+ mappM newSysLocalDs elt_tys `thenDs` \ as' ->
+ mappM newSysLocalDs list_tys `thenDs` \ as's ->
+ newSysLocalDs zip_fn_ty `thenDs` \ zip_fn ->
+ let
+ inner_rhs = mkConsExpr ret_elt_ty
+ (mkCoreTup (map Var as'))
+ (mkVarApps (Var zip_fn) as's)
+ zip_body = foldr mk_case inner_rhs (zip3 ass as' as's)
+ in
+ returnDs (zip_fn, mkLams ass zip_body)
+ where
+ list_tys = map mkListTy elt_tys
+ ret_elt_ty = mkCoreTupTy elt_tys
+ list_ret_ty = mkListTy ret_elt_ty
+ zip_fn_ty = mkFunTys list_tys list_ret_ty
+
+ mk_case (as, a', as') rest
+ = Case (Var as) as list_ret_ty
+ [(DataAlt nilDataCon, [], mkNilExpr ret_elt_ty),
+ (DataAlt consDataCon, [a', as'], rest)]
+ -- Increasing order of tag
+-- Helper functions that makes an HsTuple only for non-1-sized tuples
+mk_hs_tuple_expr :: [Id] -> LHsExpr Id
+mk_hs_tuple_expr [] = nlHsVar unitDataConId
+mk_hs_tuple_expr [id] = nlHsVar id
+mk_hs_tuple_expr ids = noLoc $ ExplicitTuple [ nlHsVar i | i <- ids ] Boxed
+
+mk_hs_tuple_pat :: [Id] -> LPat Id
+mk_hs_tuple_pat bs = mkTuplePat (map nlVarPat bs)
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[DsListComp-foldr-build]{Foldr/Build desugaring of list comprehensions}
+%* *
+%************************************************************************
+
+@dfListComp@ are the rules used with foldr/build turned on:
+
+\begin{verbatim}
+TE[ e | ] c n = c e n
+TE[ e | b , q ] c n = if b then TE[ e | q ] c n else n
+TE[ e | p <- l , q ] c n = let
+ f = \ x b -> case x of
+ p -> TE[ e | q ] c b
+ _ -> b
+ in
+ foldr f n l
+\end{verbatim}
+
+\begin{code}
+dfListComp :: Id -> Id -- 'c' and 'n'
+ -> [Stmt Id] -- the rest of the qual's
+ -> LHsExpr Id
+ -> DsM CoreExpr
+
+ -- Last: the one to return
+dfListComp c_id n_id [] body
+ = dsLExpr body `thenDs` \ core_body ->
+ returnDs (mkApps (Var c_id) [core_body, Var n_id])
+
+ -- Non-last: must be a guard
+dfListComp c_id n_id (ExprStmt guard _ _ : quals) body
+ = dsLExpr guard `thenDs` \ core_guard ->
+ dfListComp c_id n_id quals body `thenDs` \ core_rest ->
+ returnDs (mkIfThenElse core_guard core_rest (Var n_id))
+
+dfListComp c_id n_id (LetStmt binds : quals) body
+ -- new in 1.3, local bindings
+ = dfListComp c_id n_id quals body `thenDs` \ core_rest ->
+ dsLocalBinds binds core_rest
+
+dfListComp c_id n_id (BindStmt pat list1 _ _ : quals) body
+ -- evaluate the two lists
+ = dsLExpr list1 `thenDs` \ core_list1 ->
+
+ -- find the required type
+ let x_ty = hsPatType pat
+ b_ty = idType n_id
+ in
+
+ -- create some new local id's
+ newSysLocalsDs [b_ty,x_ty] `thenDs` \ [b,x] ->
+
+ -- build rest of the comprehesion
+ dfListComp c_id b quals body `thenDs` \ core_rest ->
+
+ -- build the pattern match
+ matchSimply (Var x) (StmtCtxt ListComp)
+ pat core_rest (Var b) `thenDs` \ core_expr ->
+
+ -- now build the outermost foldr, and return
+ dsLookupGlobalId foldrName `thenDs` \ foldr_id ->
+ returnDs (
+ Var foldr_id `App` Type x_ty
+ `App` Type b_ty
+ `App` mkLams [x, b] core_expr
+ `App` Var n_id
+ `App` core_list1
+ )
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[DsPArrComp]{Desugaring of array comprehensions}
+%* *
+%************************************************************************
+
+\begin{code}
+
+-- entry point for desugaring a parallel array comprehension
+--
+-- [:e | qss:] = <<[:e | qss:]>> () [:():]
+--
+dsPArrComp :: [Stmt Id]
+ -> LHsExpr Id
+ -> Type -- Don't use; called with `undefined' below
+ -> DsM CoreExpr
+dsPArrComp qs body _ =
+ dsLookupGlobalId replicatePName `thenDs` \repP ->
+ let unitArray = mkApps (Var repP) [Type unitTy,
+ mkIntExpr 1,
+ mkCoreTup []]
+ in
+ dePArrComp qs body (mkTuplePat []) unitArray
+
+-- the work horse
+--
+dePArrComp :: [Stmt Id]
+ -> LHsExpr Id
+ -> LPat Id -- the current generator pattern
+ -> CoreExpr -- the current generator expression
+ -> DsM CoreExpr
+--
+-- <<[:e' | :]>> pa ea = mapP (\pa -> e') ea
+--
+dePArrComp [] e' pa cea =
+ dsLookupGlobalId mapPName `thenDs` \mapP ->
+ let ty = parrElemType cea
+ in
+ deLambda ty pa e' `thenDs` \(clam,
+ ty'e') ->
+ returnDs $ mkApps (Var mapP) [Type ty, Type ty'e', clam, cea]
+--
+-- <<[:e' | b, qs:]>> pa ea = <<[:e' | qs:]>> pa (filterP (\pa -> b) ea)
+--
+dePArrComp (ExprStmt b _ _ : qs) body pa cea =
+ dsLookupGlobalId filterPName `thenDs` \filterP ->
+ let ty = parrElemType cea
+ in
+ deLambda ty pa b `thenDs` \(clam,_) ->
+ dePArrComp qs body pa (mkApps (Var filterP) [Type ty, clam, cea])
+--
+-- <<[:e' | p <- e, qs:]>> pa ea =
+-- let ef = filterP (\x -> case x of {p -> True; _ -> False}) e
+-- in
+-- <<[:e' | qs:]>> (pa, p) (crossP ea ef)
+--
+dePArrComp (BindStmt p e _ _ : qs) body pa cea =
+ dsLookupGlobalId filterPName `thenDs` \filterP ->
+ dsLookupGlobalId crossPName `thenDs` \crossP ->
+ dsLExpr e `thenDs` \ce ->
+ let ty'cea = parrElemType cea
+ ty'ce = parrElemType ce
+ false = Var falseDataConId
+ true = Var trueDataConId
+ in
+ newSysLocalDs ty'ce `thenDs` \v ->
+ matchSimply (Var v) (StmtCtxt PArrComp) p true false `thenDs` \pred ->
+ let cef = mkApps (Var filterP) [Type ty'ce, mkLams [v] pred, ce]
+ ty'cef = ty'ce -- filterP preserves the type
+ pa' = mkTuplePat [pa, p]
+ in
+ dePArrComp qs body pa' (mkApps (Var crossP) [Type ty'cea, Type ty'cef, cea, cef])
+--
+-- <<[:e' | let ds, qs:]>> pa ea =
+-- <<[:e' | qs:]>> (pa, (x_1, ..., x_n))
+-- (mapP (\v@pa -> (v, let ds in (x_1, ..., x_n))) ea)
+-- where
+-- {x_1, ..., x_n} = DV (ds) -- Defined Variables
+--
+dePArrComp (LetStmt ds : qs) body pa cea =
+ dsLookupGlobalId mapPName `thenDs` \mapP ->
+ let xs = map unLoc (collectLocalBinders ds)
+ ty'cea = parrElemType cea
+ in
+ newSysLocalDs ty'cea `thenDs` \v ->
+ dsLocalBinds ds (mkCoreTup (map Var xs)) `thenDs` \clet ->
+ newSysLocalDs (exprType clet) `thenDs` \let'v ->
+ let projBody = mkDsLet (NonRec let'v clet) $
+ mkCoreTup [Var v, Var let'v]
+ errTy = exprType projBody
+ errMsg = "DsListComp.dePArrComp: internal error!"
+ in
+ mkErrorAppDs pAT_ERROR_ID errTy errMsg `thenDs` \cerr ->
+ matchSimply (Var v) (StmtCtxt PArrComp) pa projBody cerr`thenDs` \ccase ->
+ let pa' = mkTuplePat [pa, mkTuplePat (map nlVarPat xs)]
+ proj = mkLams [v] ccase
+ in
+ dePArrComp qs body pa' (mkApps (Var mapP) [Type ty'cea, proj, cea])
+--
+-- <<[:e' | qs | qss:]>> pa ea =
+-- <<[:e' | qss:]>> (pa, (x_1, ..., x_n))
+-- (zipP ea <<[:(x_1, ..., x_n) | qs:]>>)
+-- where
+-- {x_1, ..., x_n} = DV (qs)
+--
+dePArrComp (ParStmt qss : qs) body pa cea =
+ dsLookupGlobalId crossPName `thenDs` \crossP ->
+ deParStmt qss `thenDs` \(pQss,
+ ceQss) ->
+ let ty'cea = parrElemType cea
+ ty'ceQss = parrElemType ceQss
+ pa' = mkTuplePat [pa, pQss]
+ in
+ dePArrComp qs body pa' (mkApps (Var crossP) [Type ty'cea, Type ty'ceQss,
+ cea, ceQss])
+ where
+ deParStmt [] =
+ -- empty parallel statement lists have not source representation
+ panic "DsListComp.dePArrComp: Empty parallel list comprehension"
+ deParStmt ((qs, xs):qss) = -- first statement
+ let res_expr = mkExplicitTuple (map nlHsVar xs)
+ in
+ dsPArrComp (map unLoc qs) res_expr undefined `thenDs` \cqs ->
+ parStmts qss (mkTuplePat (map nlVarPat xs)) cqs
+ ---
+ parStmts [] pa cea = return (pa, cea)
+ parStmts ((qs, xs):qss) pa cea = -- subsequent statements (zip'ed)
+ dsLookupGlobalId zipPName `thenDs` \zipP ->
+ let pa' = mkTuplePat [pa, mkTuplePat (map nlVarPat xs)]
+ ty'cea = parrElemType cea
+ res_expr = mkExplicitTuple (map nlHsVar xs)
+ in
+ dsPArrComp (map unLoc qs) res_expr undefined `thenDs` \cqs ->
+ let ty'cqs = parrElemType cqs
+ cea' = mkApps (Var zipP) [Type ty'cea, Type ty'cqs, cea, cqs]
+ in
+ parStmts qss pa' cea'
+
+-- generate Core corresponding to `\p -> e'
+--
+deLambda :: Type -- type of the argument
+ -> LPat Id -- argument pattern
+ -> LHsExpr Id -- body
+ -> DsM (CoreExpr, Type)
+deLambda ty p e =
+ newSysLocalDs ty `thenDs` \v ->
+ dsLExpr e `thenDs` \ce ->
+ let errTy = exprType ce
+ errMsg = "DsListComp.deLambda: internal error!"
+ in
+ mkErrorAppDs pAT_ERROR_ID errTy errMsg `thenDs` \cerr ->
+ matchSimply (Var v) (StmtCtxt PArrComp) p ce cerr `thenDs` \res ->
+ returnDs (mkLams [v] res, errTy)
+
+-- obtain the element type of the parallel array produced by the given Core
+-- expression
+--
+parrElemType :: CoreExpr -> Type
+parrElemType e =
+ case splitTyConApp_maybe (exprType e) of
+ Just (tycon, [ty]) | tycon == parrTyCon -> ty
+ _ -> panic
+ "DsListComp.parrElemType: not a parallel array type"
+
+-- Smart constructor for source tuple patterns
+--
+mkTuplePat :: [LPat Id] -> LPat Id
+mkTuplePat [lpat] = lpat
+mkTuplePat lpats = noLoc $ mkVanillaTuplePat lpats Boxed
+
+-- Smart constructor for source tuple expressions
+--
+mkExplicitTuple :: [LHsExpr id] -> LHsExpr id
+mkExplicitTuple [lexp] = lexp
+mkExplicitTuple lexps = noLoc $ ExplicitTuple lexps Boxed
+\end{code}
diff --git a/compiler/deSugar/DsMeta.hs b/compiler/deSugar/DsMeta.hs
new file mode 100644
index 0000000000..88b0ba9c8e
--- /dev/null
+++ b/compiler/deSugar/DsMeta.hs
@@ -0,0 +1,1732 @@
+-----------------------------------------------------------------------------
+-- The purpose of this module is to transform an HsExpr into a CoreExpr which
+-- when evaluated, returns a (Meta.Q Meta.Exp) computation analogous to the
+-- input HsExpr. We do this in the DsM monad, which supplies access to
+-- CoreExpr's of the "smart constructors" of the Meta.Exp datatype.
+--
+-- It also defines a bunch of knownKeyNames, in the same way as is done
+-- in prelude/PrelNames. It's much more convenient to do it here, becuase
+-- otherwise we have to recompile PrelNames whenever we add a Name, which is
+-- a Royal Pain (triggers other recompilation).
+-----------------------------------------------------------------------------
+
+
+module DsMeta( dsBracket,
+ templateHaskellNames, qTyConName, nameTyConName,
+ liftName, expQTyConName, decQTyConName, typeQTyConName,
+ decTyConName, typeTyConName, mkNameG_dName, mkNameG_vName, mkNameG_tcName
+ ) where
+
+#include "HsVersions.h"
+
+import {-# SOURCE #-} DsExpr ( dsExpr )
+
+import MatchLit ( dsLit )
+import DsUtils ( mkListExpr, mkStringExpr, mkCoreTup, mkIntExpr )
+import DsMonad
+
+import qualified Language.Haskell.TH as TH
+
+import HsSyn
+import Class (FunDep)
+import PrelNames ( rationalTyConName, integerTyConName, negateName )
+import OccName ( isDataOcc, isTvOcc, occNameString )
+-- To avoid clashes with DsMeta.varName we must make a local alias for OccName.varName
+-- we do this by removing varName from the import of OccName above, making
+-- a qualified instance of OccName and using OccNameAlias.varName where varName
+-- ws previously used in this file.
+import qualified OccName
+
+import Module ( Module, mkModule, moduleString )
+import Id ( Id, mkLocalId )
+import OccName ( mkOccNameFS )
+import Name ( Name, mkExternalName, localiseName, nameOccName, nameModule,
+ isExternalName, getSrcLoc )
+import NameEnv
+import Type ( Type, mkTyConApp )
+import TcType ( tcTyConAppArgs )
+import TyCon ( tyConName )
+import TysWiredIn ( parrTyCon )
+import CoreSyn
+import CoreUtils ( exprType )
+import SrcLoc ( noSrcLoc, unLoc, Located(..), SrcSpan, srcLocSpan )
+import Maybe ( catMaybes )
+import Unique ( mkPreludeTyConUnique, mkPreludeMiscIdUnique, getKey, Uniquable(..) )
+import BasicTypes ( isBoxed )
+import Outputable
+import Bag ( bagToList, unionManyBags )
+import FastString ( unpackFS )
+import ForeignCall ( Safety(..), CCallConv(..), CCallTarget(..) )
+
+import Monad ( zipWithM )
+import List ( sortBy )
+
+-----------------------------------------------------------------------------
+dsBracket :: HsBracket Name -> [PendingSplice] -> DsM CoreExpr
+-- Returns a CoreExpr of type TH.ExpQ
+-- The quoted thing is parameterised over Name, even though it has
+-- been type checked. We don't want all those type decorations!
+
+dsBracket brack splices
+ = dsExtendMetaEnv new_bit (do_brack brack)
+ where
+ new_bit = mkNameEnv [(n, Splice (unLoc e)) | (n,e) <- splices]
+
+ do_brack (VarBr n) = do { MkC e1 <- lookupOcc n ; return e1 }
+ do_brack (ExpBr e) = do { MkC e1 <- repLE e ; return e1 }
+ do_brack (PatBr p) = do { MkC p1 <- repLP p ; return p1 }
+ do_brack (TypBr t) = do { MkC t1 <- repLTy t ; return t1 }
+ do_brack (DecBr ds) = do { MkC ds1 <- repTopDs ds ; return ds1 }
+
+{- -------------- Examples --------------------
+
+ [| \x -> x |]
+====>
+ gensym (unpackString "x"#) `bindQ` \ x1::String ->
+ lam (pvar x1) (var x1)
+
+
+ [| \x -> $(f [| x |]) |]
+====>
+ gensym (unpackString "x"#) `bindQ` \ x1::String ->
+ lam (pvar x1) (f (var x1))
+-}
+
+
+-------------------------------------------------------
+-- Declarations
+-------------------------------------------------------
+
+repTopDs :: HsGroup Name -> DsM (Core (TH.Q [TH.Dec]))
+repTopDs group
+ = do { let { bndrs = map unLoc (groupBinders group) } ;
+ ss <- mkGenSyms bndrs ;
+
+ -- Bind all the names mainly to avoid repeated use of explicit strings.
+ -- Thus we get
+ -- do { t :: String <- genSym "T" ;
+ -- return (Data t [] ...more t's... }
+ -- The other important reason is that the output must mention
+ -- only "T", not "Foo:T" where Foo is the current module
+
+
+ decls <- addBinds ss (do {
+ val_ds <- rep_val_binds (hs_valds group) ;
+ tycl_ds <- mapM repTyClD (hs_tyclds group) ;
+ inst_ds <- mapM repInstD' (hs_instds group) ;
+ for_ds <- mapM repForD (hs_fords group) ;
+ -- more needed
+ return (de_loc $ sort_by_loc $ val_ds ++ catMaybes tycl_ds ++ inst_ds ++ for_ds) }) ;
+
+ decl_ty <- lookupType decQTyConName ;
+ let { core_list = coreList' decl_ty decls } ;
+
+ dec_ty <- lookupType decTyConName ;
+ q_decs <- repSequenceQ dec_ty core_list ;
+
+ wrapNongenSyms ss q_decs
+ -- Do *not* gensym top-level binders
+ }
+
+groupBinders (HsGroup { hs_valds = val_decls, hs_tyclds = tycl_decls,
+ hs_fords = foreign_decls })
+-- Collect the binders of a Group
+ = collectHsValBinders val_decls ++
+ [n | d <- tycl_decls, n <- tyClDeclNames (unLoc d)] ++
+ [n | L _ (ForeignImport n _ _ _) <- foreign_decls]
+
+
+{- Note [Binders and occurrences]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When we desugar [d| data T = MkT |]
+we want to get
+ Data "T" [] [Con "MkT" []] []
+and *not*
+ Data "Foo:T" [] [Con "Foo:MkT" []] []
+That is, the new data decl should fit into whatever new module it is
+asked to fit in. We do *not* clone, though; no need for this:
+ Data "T79" ....
+
+But if we see this:
+ data T = MkT
+ foo = reifyDecl T
+
+then we must desugar to
+ foo = Data "Foo:T" [] [Con "Foo:MkT" []] []
+
+So in repTopDs we bring the binders into scope with mkGenSyms and addBinds.
+And we use lookupOcc, rather than lookupBinder
+in repTyClD and repC.
+
+-}
+
+repTyClD :: LTyClDecl Name -> DsM (Maybe (SrcSpan, Core TH.DecQ))
+
+repTyClD (L loc (TyData { tcdND = DataType, tcdCtxt = cxt,
+ tcdLName = tc, tcdTyVars = tvs,
+ tcdCons = cons, tcdDerivs = mb_derivs }))
+ = do { tc1 <- lookupLOcc tc ; -- See note [Binders and occurrences]
+ dec <- addTyVarBinds tvs $ \bndrs -> do {
+ cxt1 <- repLContext cxt ;
+ cons1 <- mapM repC cons ;
+ cons2 <- coreList conQTyConName cons1 ;
+ derivs1 <- repDerivs mb_derivs ;
+ bndrs1 <- coreList nameTyConName bndrs ;
+ repData cxt1 tc1 bndrs1 cons2 derivs1 } ;
+ return $ Just (loc, dec) }
+
+repTyClD (L loc (TyData { tcdND = NewType, tcdCtxt = cxt,
+ tcdLName = tc, tcdTyVars = tvs,
+ tcdCons = [con], tcdDerivs = mb_derivs }))
+ = do { tc1 <- lookupLOcc tc ; -- See note [Binders and occurrences]
+ dec <- addTyVarBinds tvs $ \bndrs -> do {
+ cxt1 <- repLContext cxt ;
+ con1 <- repC con ;
+ derivs1 <- repDerivs mb_derivs ;
+ bndrs1 <- coreList nameTyConName bndrs ;
+ repNewtype cxt1 tc1 bndrs1 con1 derivs1 } ;
+ return $ Just (loc, dec) }
+
+repTyClD (L loc (TySynonym { tcdLName = tc, tcdTyVars = tvs, tcdSynRhs = ty }))
+ = do { tc1 <- lookupLOcc tc ; -- See note [Binders and occurrences]
+ dec <- addTyVarBinds tvs $ \bndrs -> do {
+ ty1 <- repLTy ty ;
+ bndrs1 <- coreList nameTyConName bndrs ;
+ repTySyn tc1 bndrs1 ty1 } ;
+ return (Just (loc, dec)) }
+
+repTyClD (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls,
+ tcdTyVars = tvs,
+ tcdFDs = fds,
+ tcdSigs = sigs, tcdMeths = meth_binds }))
+ = do { cls1 <- lookupLOcc cls ; -- See note [Binders and occurrences]
+ dec <- addTyVarBinds tvs $ \bndrs -> do {
+ cxt1 <- repLContext cxt ;
+ sigs1 <- rep_sigs sigs ;
+ binds1 <- rep_binds meth_binds ;
+ fds1 <- repLFunDeps fds;
+ decls1 <- coreList decQTyConName (sigs1 ++ binds1) ;
+ bndrs1 <- coreList nameTyConName bndrs ;
+ repClass cxt1 cls1 bndrs1 fds1 decls1 } ;
+ return $ Just (loc, dec) }
+
+-- Un-handled cases
+repTyClD (L loc d) = putSrcSpanDs loc $
+ do { dsWarn (hang ds_msg 4 (ppr d))
+ ; return Nothing }
+
+-- represent fundeps
+--
+repLFunDeps :: [Located (FunDep Name)] -> DsM (Core [TH.FunDep])
+repLFunDeps fds = do fds' <- mapM repLFunDep fds
+ fdList <- coreList funDepTyConName fds'
+ return fdList
+
+repLFunDep :: Located (FunDep Name) -> DsM (Core TH.FunDep)
+repLFunDep (L _ (xs, ys)) = do xs' <- mapM lookupBinder xs
+ ys' <- mapM lookupBinder ys
+ xs_list <- coreList nameTyConName xs'
+ ys_list <- coreList nameTyConName ys'
+ repFunDep xs_list ys_list
+
+repInstD' (L loc (InstDecl ty binds _)) -- Ignore user pragmas for now
+ = do { i <- addTyVarBinds tvs $ \tv_bndrs ->
+ -- We must bring the type variables into scope, so their occurrences
+ -- don't fail, even though the binders don't appear in the resulting
+ -- data structure
+ do { cxt1 <- repContext cxt
+ ; inst_ty1 <- repPred (HsClassP cls tys)
+ ; ss <- mkGenSyms (collectHsBindBinders binds)
+ ; binds1 <- addBinds ss (rep_binds binds)
+ ; decls1 <- coreList decQTyConName binds1
+ ; decls2 <- wrapNongenSyms ss decls1
+ -- wrapNonGenSyms: do not clone the class op names!
+ -- They must be called 'op' etc, not 'op34'
+ ; repInst cxt1 inst_ty1 decls2 }
+
+ ; return (loc, i)}
+ where
+ (tvs, cxt, cls, tys) = splitHsInstDeclTy (unLoc ty)
+
+repForD :: Located (ForeignDecl Name) -> DsM (SrcSpan, Core TH.DecQ)
+repForD (L loc (ForeignImport name typ (CImport cc s ch cn cis) _))
+ = do MkC name' <- lookupLOcc name
+ MkC typ' <- repLTy typ
+ MkC cc' <- repCCallConv cc
+ MkC s' <- repSafety s
+ MkC str <- coreStringLit $ static
+ ++ unpackFS ch ++ " "
+ ++ unpackFS cn ++ " "
+ ++ conv_cimportspec cis
+ dec <- rep2 forImpDName [cc', s', str, name', typ']
+ return (loc, dec)
+ where
+ conv_cimportspec (CLabel cls) = panic "repForD': CLabel Not handled"
+ conv_cimportspec (CFunction DynamicTarget) = "dynamic"
+ conv_cimportspec (CFunction (StaticTarget fs)) = unpackFS fs
+ conv_cimportspec CWrapper = "wrapper"
+ static = case cis of
+ CFunction (StaticTarget _) -> "static "
+ _ -> ""
+
+repCCallConv :: CCallConv -> DsM (Core TH.Callconv)
+repCCallConv CCallConv = rep2 cCallName []
+repCCallConv StdCallConv = rep2 stdCallName []
+
+repSafety :: Safety -> DsM (Core TH.Safety)
+repSafety PlayRisky = rep2 unsafeName []
+repSafety (PlaySafe False) = rep2 safeName []
+repSafety (PlaySafe True) = rep2 threadsafeName []
+
+ds_msg = ptext SLIT("Cannot desugar this Template Haskell declaration:")
+
+-------------------------------------------------------
+-- Constructors
+-------------------------------------------------------
+
+repC :: LConDecl Name -> DsM (Core TH.ConQ)
+repC (L loc (ConDecl con expl [] (L _ []) details ResTyH98))
+ = do { con1 <- lookupLOcc con ; -- See note [Binders and occurrences]
+ repConstr con1 details }
+repC (L loc (ConDecl con expl tvs (L cloc ctxt) details ResTyH98))
+ = do { addTyVarBinds tvs $ \bndrs -> do {
+ c' <- repC (L loc (ConDecl con expl [] (L cloc []) details ResTyH98));
+ ctxt' <- repContext ctxt;
+ bndrs' <- coreList nameTyConName bndrs;
+ rep2 forallCName [unC bndrs', unC ctxt', unC c']
+ }
+ }
+repC (L loc con_decl) -- GADTs
+ = putSrcSpanDs loc $
+ do { dsWarn (hang ds_msg 4 (ppr con_decl))
+ ; return (panic "DsMeta:repC") }
+
+repBangTy :: LBangType Name -> DsM (Core (TH.StrictTypeQ))
+repBangTy ty= do
+ MkC s <- rep2 str []
+ MkC t <- repLTy ty'
+ rep2 strictTypeName [s, t]
+ where
+ (str, ty') = case ty of
+ L _ (HsBangTy _ ty) -> (isStrictName, ty)
+ other -> (notStrictName, ty)
+
+-------------------------------------------------------
+-- Deriving clause
+-------------------------------------------------------
+
+repDerivs :: Maybe [LHsType Name] -> DsM (Core [TH.Name])
+repDerivs Nothing = coreList nameTyConName []
+repDerivs (Just ctxt)
+ = do { strs <- mapM rep_deriv ctxt ;
+ coreList nameTyConName strs }
+ where
+ rep_deriv :: LHsType Name -> DsM (Core TH.Name)
+ -- Deriving clauses must have the simple H98 form
+ rep_deriv (L _ (HsPredTy (HsClassP cls []))) = lookupOcc cls
+ rep_deriv other = panic "rep_deriv"
+
+
+-------------------------------------------------------
+-- Signatures in a class decl, or a group of bindings
+-------------------------------------------------------
+
+rep_sigs :: [LSig Name] -> DsM [Core TH.DecQ]
+rep_sigs sigs = do locs_cores <- rep_sigs' sigs
+ return $ de_loc $ sort_by_loc locs_cores
+
+rep_sigs' :: [LSig Name] -> DsM [(SrcSpan, Core TH.DecQ)]
+ -- We silently ignore ones we don't recognise
+rep_sigs' sigs = do { sigs1 <- mapM rep_sig sigs ;
+ return (concat sigs1) }
+
+rep_sig :: LSig Name -> DsM [(SrcSpan, Core TH.DecQ)]
+ -- Singleton => Ok
+ -- Empty => Too hard, signature ignored
+rep_sig (L loc (TypeSig nm ty)) = rep_proto nm ty loc
+rep_sig other = return []
+
+rep_proto :: Located Name -> LHsType Name -> SrcSpan -> DsM [(SrcSpan, Core TH.DecQ)]
+rep_proto nm ty loc = do { nm1 <- lookupLOcc nm ;
+ ty1 <- repLTy ty ;
+ sig <- repProto nm1 ty1 ;
+ return [(loc, sig)] }
+
+
+-------------------------------------------------------
+-- Types
+-------------------------------------------------------
+
+-- gensym a list of type variables and enter them into the meta environment;
+-- the computations passed as the second argument is executed in that extended
+-- meta environment and gets the *new* names on Core-level as an argument
+--
+addTyVarBinds :: [LHsTyVarBndr Name] -- the binders to be added
+ -> ([Core TH.Name] -> DsM (Core (TH.Q a))) -- action in the ext env
+ -> DsM (Core (TH.Q a))
+addTyVarBinds tvs m =
+ do
+ let names = map (hsTyVarName.unLoc) tvs
+ freshNames <- mkGenSyms names
+ term <- addBinds freshNames $ do
+ bndrs <- mapM lookupBinder names
+ m bndrs
+ wrapGenSyns freshNames term
+
+-- represent a type context
+--
+repLContext :: LHsContext Name -> DsM (Core TH.CxtQ)
+repLContext (L _ ctxt) = repContext ctxt
+
+repContext :: HsContext Name -> DsM (Core TH.CxtQ)
+repContext ctxt = do
+ preds <- mapM repLPred ctxt
+ predList <- coreList typeQTyConName preds
+ repCtxt predList
+
+-- represent a type predicate
+--
+repLPred :: LHsPred Name -> DsM (Core TH.TypeQ)
+repLPred (L _ p) = repPred p
+
+repPred :: HsPred Name -> DsM (Core TH.TypeQ)
+repPred (HsClassP cls tys) = do
+ tcon <- repTy (HsTyVar cls)
+ tys1 <- repLTys tys
+ repTapps tcon tys1
+repPred (HsIParam _ _) =
+ panic "DsMeta.repTy: Can't represent predicates with implicit parameters"
+
+-- yield the representation of a list of types
+--
+repLTys :: [LHsType Name] -> DsM [Core TH.TypeQ]
+repLTys tys = mapM repLTy tys
+
+-- represent a type
+--
+repLTy :: LHsType Name -> DsM (Core TH.TypeQ)
+repLTy (L _ ty) = repTy ty
+
+repTy :: HsType Name -> DsM (Core TH.TypeQ)
+repTy (HsForAllTy _ tvs ctxt ty) =
+ addTyVarBinds tvs $ \bndrs -> do
+ ctxt1 <- repLContext ctxt
+ ty1 <- repLTy ty
+ bndrs1 <- coreList nameTyConName bndrs
+ repTForall bndrs1 ctxt1 ty1
+
+repTy (HsTyVar n)
+ | isTvOcc (nameOccName n) = do
+ tv1 <- lookupBinder n
+ repTvar tv1
+ | otherwise = do
+ tc1 <- lookupOcc n
+ repNamedTyCon tc1
+repTy (HsAppTy f a) = do
+ f1 <- repLTy f
+ a1 <- repLTy a
+ repTapp f1 a1
+repTy (HsFunTy f a) = do
+ f1 <- repLTy f
+ a1 <- repLTy a
+ tcon <- repArrowTyCon
+ repTapps tcon [f1, a1]
+repTy (HsListTy t) = do
+ t1 <- repLTy t
+ tcon <- repListTyCon
+ repTapp tcon t1
+repTy (HsPArrTy t) = do
+ t1 <- repLTy t
+ tcon <- repTy (HsTyVar (tyConName parrTyCon))
+ repTapp tcon t1
+repTy (HsTupleTy tc tys) = do
+ tys1 <- repLTys tys
+ tcon <- repTupleTyCon (length tys)
+ repTapps tcon tys1
+repTy (HsOpTy ty1 n ty2) = repLTy ((nlHsTyVar (unLoc n) `nlHsAppTy` ty1)
+ `nlHsAppTy` ty2)
+repTy (HsParTy t) = repLTy t
+repTy (HsNumTy i) =
+ panic "DsMeta.repTy: Can't represent number types (for generics)"
+repTy (HsPredTy pred) = repPred pred
+repTy (HsKindSig ty kind) =
+ panic "DsMeta.repTy: Can't represent explicit kind signatures yet"
+
+
+-----------------------------------------------------------------------------
+-- Expressions
+-----------------------------------------------------------------------------
+
+repLEs :: [LHsExpr Name] -> DsM (Core [TH.ExpQ])
+repLEs es = do { es' <- mapM repLE es ;
+ coreList expQTyConName es' }
+
+-- FIXME: some of these panics should be converted into proper error messages
+-- unless we can make sure that constructs, which are plainly not
+-- supported in TH already lead to error messages at an earlier stage
+repLE :: LHsExpr Name -> DsM (Core TH.ExpQ)
+repLE (L _ e) = repE e
+
+repE :: HsExpr Name -> DsM (Core TH.ExpQ)
+repE (HsVar x) =
+ do { mb_val <- dsLookupMetaEnv x
+ ; case mb_val of
+ Nothing -> do { str <- globalVar x
+ ; repVarOrCon x str }
+ Just (Bound y) -> repVarOrCon x (coreVar y)
+ Just (Splice e) -> do { e' <- dsExpr e
+ ; return (MkC e') } }
+repE (HsIPVar x) = panic "DsMeta.repE: Can't represent implicit parameters"
+
+ -- Remember, we're desugaring renamer output here, so
+ -- HsOverlit can definitely occur
+repE (HsOverLit l) = do { a <- repOverloadedLiteral l; repLit a }
+repE (HsLit l) = do { a <- repLiteral l; repLit a }
+repE (HsLam (MatchGroup [m] _)) = repLambda m
+repE (HsApp x y) = do {a <- repLE x; b <- repLE y; repApp a b}
+
+repE (OpApp e1 op fix e2) =
+ do { arg1 <- repLE e1;
+ arg2 <- repLE e2;
+ the_op <- repLE op ;
+ repInfixApp arg1 the_op arg2 }
+repE (NegApp x nm) = do
+ a <- repLE x
+ negateVar <- lookupOcc negateName >>= repVar
+ negateVar `repApp` a
+repE (HsPar x) = repLE x
+repE (SectionL x y) = do { a <- repLE x; b <- repLE y; repSectionL a b }
+repE (SectionR x y) = do { a <- repLE x; b <- repLE y; repSectionR a b }
+repE (HsCase e (MatchGroup ms _)) = do { arg <- repLE e
+ ; ms2 <- mapM repMatchTup ms
+ ; repCaseE arg (nonEmptyCoreList ms2) }
+repE (HsIf x y z) = do
+ a <- repLE x
+ b <- repLE y
+ c <- repLE z
+ repCond a b c
+repE (HsLet bs e) = do { (ss,ds) <- repBinds bs
+ ; e2 <- addBinds ss (repLE e)
+ ; z <- repLetE ds e2
+ ; wrapGenSyns ss z }
+-- FIXME: I haven't got the types here right yet
+repE (HsDo DoExpr sts body ty)
+ = do { (ss,zs) <- repLSts sts;
+ body' <- addBinds ss $ repLE body;
+ ret <- repNoBindSt body';
+ e <- repDoE (nonEmptyCoreList (zs ++ [ret]));
+ wrapGenSyns ss e }
+repE (HsDo ListComp sts body ty)
+ = do { (ss,zs) <- repLSts sts;
+ body' <- addBinds ss $ repLE body;
+ ret <- repNoBindSt body';
+ e <- repComp (nonEmptyCoreList (zs ++ [ret]));
+ wrapGenSyns ss e }
+repE (HsDo _ _ _ _) = panic "DsMeta.repE: Can't represent mdo and [: :] yet"
+repE (ExplicitList ty es) = do { xs <- repLEs es; repListExp xs }
+repE (ExplicitPArr ty es) =
+ panic "DsMeta.repE: No explicit parallel arrays yet"
+repE (ExplicitTuple es boxed)
+ | isBoxed boxed = do { xs <- repLEs es; repTup xs }
+ | otherwise = panic "DsMeta.repE: Can't represent unboxed tuples"
+repE (RecordCon c _ flds)
+ = do { x <- lookupLOcc c;
+ fs <- repFields flds;
+ repRecCon x fs }
+repE (RecordUpd e flds _ _)
+ = do { x <- repLE e;
+ fs <- repFields flds;
+ repRecUpd x fs }
+
+repE (ExprWithTySig e ty) = do { e1 <- repLE e; t1 <- repLTy ty; repSigExp e1 t1 }
+repE (ArithSeq _ aseq) =
+ case aseq of
+ From e -> do { ds1 <- repLE e; repFrom ds1 }
+ FromThen e1 e2 -> do
+ ds1 <- repLE e1
+ ds2 <- repLE e2
+ repFromThen ds1 ds2
+ FromTo e1 e2 -> do
+ ds1 <- repLE e1
+ ds2 <- repLE e2
+ repFromTo ds1 ds2
+ FromThenTo e1 e2 e3 -> do
+ ds1 <- repLE e1
+ ds2 <- repLE e2
+ ds3 <- repLE e3
+ repFromThenTo ds1 ds2 ds3
+repE (PArrSeq _ aseq) = panic "DsMeta.repE: parallel array seq.s missing"
+repE (HsCoreAnn _ _) = panic "DsMeta.repE: Can't represent CoreAnn" -- hdaume: core annotations
+repE (HsSCC _ _) = panic "DsMeta.repE: Can't represent SCC"
+repE (HsBracketOut _ _) = panic "DsMeta.repE: Can't represent Oxford brackets"
+repE (HsSpliceE (HsSplice n _))
+ = do { mb_val <- dsLookupMetaEnv n
+ ; case mb_val of
+ Just (Splice e) -> do { e' <- dsExpr e
+ ; return (MkC e') }
+ other -> pprPanic "HsSplice" (ppr n) }
+
+repE e = pprPanic "DsMeta.repE: Illegal expression form" (ppr e)
+
+-----------------------------------------------------------------------------
+-- Building representations of auxillary structures like Match, Clause, Stmt,
+
+repMatchTup :: LMatch Name -> DsM (Core TH.MatchQ)
+repMatchTup (L _ (Match [p] ty (GRHSs guards wheres))) =
+ do { ss1 <- mkGenSyms (collectPatBinders p)
+ ; addBinds ss1 $ do {
+ ; p1 <- repLP p
+ ; (ss2,ds) <- repBinds wheres
+ ; addBinds ss2 $ do {
+ ; gs <- repGuards guards
+ ; match <- repMatch p1 gs ds
+ ; wrapGenSyns (ss1++ss2) match }}}
+
+repClauseTup :: LMatch Name -> DsM (Core TH.ClauseQ)
+repClauseTup (L _ (Match ps ty (GRHSs guards wheres))) =
+ do { ss1 <- mkGenSyms (collectPatsBinders ps)
+ ; addBinds ss1 $ do {
+ ps1 <- repLPs ps
+ ; (ss2,ds) <- repBinds wheres
+ ; addBinds ss2 $ do {
+ gs <- repGuards guards
+ ; clause <- repClause ps1 gs ds
+ ; wrapGenSyns (ss1++ss2) clause }}}
+
+repGuards :: [LGRHS Name] -> DsM (Core TH.BodyQ)
+repGuards [L _ (GRHS [] e)]
+ = do {a <- repLE e; repNormal a }
+repGuards other
+ = do { zs <- mapM process other;
+ let {(xs, ys) = unzip zs};
+ gd <- repGuarded (nonEmptyCoreList ys);
+ wrapGenSyns (concat xs) gd }
+ where
+ process :: LGRHS Name -> DsM ([GenSymBind], (Core (TH.Q (TH.Guard, TH.Exp))))
+ process (L _ (GRHS [L _ (ExprStmt e1 _ _)] e2))
+ = do { x <- repLNormalGE e1 e2;
+ return ([], x) }
+ process (L _ (GRHS ss rhs))
+ = do (gs, ss') <- repLSts ss
+ rhs' <- addBinds gs $ repLE rhs
+ g <- repPatGE (nonEmptyCoreList ss') rhs'
+ return (gs, g)
+
+repFields :: [(Located Name, LHsExpr Name)] -> DsM (Core [TH.Q TH.FieldExp])
+repFields flds = do
+ fnames <- mapM lookupLOcc (map fst flds)
+ es <- mapM repLE (map snd flds)
+ fs <- zipWithM repFieldExp fnames es
+ coreList fieldExpQTyConName fs
+
+
+-----------------------------------------------------------------------------
+-- Representing Stmt's is tricky, especially if bound variables
+-- shadow each other. Consider: [| do { x <- f 1; x <- f x; g x } |]
+-- First gensym new names for every variable in any of the patterns.
+-- both static (x'1 and x'2), and dynamic ((gensym "x") and (gensym "y"))
+-- if variables didn't shaddow, the static gensym wouldn't be necessary
+-- and we could reuse the original names (x and x).
+--
+-- do { x'1 <- gensym "x"
+-- ; x'2 <- gensym "x"
+-- ; doE [ BindSt (pvar x'1) [| f 1 |]
+-- , BindSt (pvar x'2) [| f x |]
+-- , NoBindSt [| g x |]
+-- ]
+-- }
+
+-- The strategy is to translate a whole list of do-bindings by building a
+-- bigger environment, and a bigger set of meta bindings
+-- (like: x'1 <- gensym "x" ) and then combining these with the translations
+-- of the expressions within the Do
+
+-----------------------------------------------------------------------------
+-- The helper function repSts computes the translation of each sub expression
+-- and a bunch of prefix bindings denoting the dynamic renaming.
+
+repLSts :: [LStmt Name] -> DsM ([GenSymBind], [Core TH.StmtQ])
+repLSts stmts = repSts (map unLoc stmts)
+
+repSts :: [Stmt Name] -> DsM ([GenSymBind], [Core TH.StmtQ])
+repSts (BindStmt p e _ _ : ss) =
+ do { e2 <- repLE e
+ ; ss1 <- mkGenSyms (collectPatBinders p)
+ ; addBinds ss1 $ do {
+ ; p1 <- repLP p;
+ ; (ss2,zs) <- repSts ss
+ ; z <- repBindSt p1 e2
+ ; return (ss1++ss2, z : zs) }}
+repSts (LetStmt bs : ss) =
+ do { (ss1,ds) <- repBinds bs
+ ; z <- repLetSt ds
+ ; (ss2,zs) <- addBinds ss1 (repSts ss)
+ ; return (ss1++ss2, z : zs) }
+repSts (ExprStmt e _ _ : ss) =
+ do { e2 <- repLE e
+ ; z <- repNoBindSt e2
+ ; (ss2,zs) <- repSts ss
+ ; return (ss2, z : zs) }
+repSts [] = return ([],[])
+repSts other = panic "Exotic Stmt in meta brackets"
+
+
+-----------------------------------------------------------
+-- Bindings
+-----------------------------------------------------------
+
+repBinds :: HsLocalBinds Name -> DsM ([GenSymBind], Core [TH.DecQ])
+repBinds EmptyLocalBinds
+ = do { core_list <- coreList decQTyConName []
+ ; return ([], core_list) }
+
+repBinds (HsIPBinds _)
+ = panic "DsMeta:repBinds: can't do implicit parameters"
+
+repBinds (HsValBinds decs)
+ = do { let { bndrs = map unLoc (collectHsValBinders decs) }
+ -- No need to worrry about detailed scopes within
+ -- the binding group, because we are talking Names
+ -- here, so we can safely treat it as a mutually
+ -- recursive group
+ ; ss <- mkGenSyms bndrs
+ ; prs <- addBinds ss (rep_val_binds decs)
+ ; core_list <- coreList decQTyConName
+ (de_loc (sort_by_loc prs))
+ ; return (ss, core_list) }
+
+rep_val_binds :: HsValBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]
+-- Assumes: all the binders of the binding are alrady in the meta-env
+rep_val_binds (ValBindsOut binds sigs)
+ = do { core1 <- rep_binds' (unionManyBags (map snd binds))
+ ; core2 <- rep_sigs' sigs
+ ; return (core1 ++ core2) }
+
+rep_binds :: LHsBinds Name -> DsM [Core TH.DecQ]
+rep_binds binds = do { binds_w_locs <- rep_binds' binds
+ ; return (de_loc (sort_by_loc binds_w_locs)) }
+
+rep_binds' :: LHsBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]
+rep_binds' binds = mapM rep_bind (bagToList binds)
+
+rep_bind :: LHsBind Name -> DsM (SrcSpan, Core TH.DecQ)
+-- Assumes: all the binders of the binding are alrady in the meta-env
+
+-- Note GHC treats declarations of a variable (not a pattern)
+-- e.g. x = g 5 as a Fun MonoBinds. This is indicated by a single match
+-- with an empty list of patterns
+rep_bind (L loc (FunBind { fun_id = fn,
+ fun_matches = MatchGroup [L _ (Match [] ty (GRHSs guards wheres))] _ }))
+ = do { (ss,wherecore) <- repBinds wheres
+ ; guardcore <- addBinds ss (repGuards guards)
+ ; fn' <- lookupLBinder fn
+ ; p <- repPvar fn'
+ ; ans <- repVal p guardcore wherecore
+ ; ans' <- wrapGenSyns ss ans
+ ; return (loc, ans') }
+
+rep_bind (L loc (FunBind { fun_id = fn, fun_matches = MatchGroup ms _ }))
+ = do { ms1 <- mapM repClauseTup ms
+ ; fn' <- lookupLBinder fn
+ ; ans <- repFun fn' (nonEmptyCoreList ms1)
+ ; return (loc, ans) }
+
+rep_bind (L loc (PatBind { pat_lhs = pat, pat_rhs = GRHSs guards wheres }))
+ = do { patcore <- repLP pat
+ ; (ss,wherecore) <- repBinds wheres
+ ; guardcore <- addBinds ss (repGuards guards)
+ ; ans <- repVal patcore guardcore wherecore
+ ; ans' <- wrapGenSyns ss ans
+ ; return (loc, ans') }
+
+rep_bind (L loc (VarBind { var_id = v, var_rhs = e}))
+ = do { v' <- lookupBinder v
+ ; e2 <- repLE e
+ ; x <- repNormal e2
+ ; patcore <- repPvar v'
+ ; empty_decls <- coreList decQTyConName []
+ ; ans <- repVal patcore x empty_decls
+ ; return (srcLocSpan (getSrcLoc v), ans) }
+
+-----------------------------------------------------------------------------
+-- Since everything in a Bind is mutually recursive we need rename all
+-- all the variables simultaneously. For example:
+-- [| AndMonoBinds (f x = x + g 2) (g x = f 1 + 2) |] would translate to
+-- do { f'1 <- gensym "f"
+-- ; g'2 <- gensym "g"
+-- ; [ do { x'3 <- gensym "x"; fun f'1 [pvar x'3] [| x + g2 |]},
+-- do { x'4 <- gensym "x"; fun g'2 [pvar x'4] [| f 1 + 2 |]}
+-- ]}
+-- This requires collecting the bindings (f'1 <- gensym "f"), and the
+-- environment ( f |-> f'1 ) from each binding, and then unioning them
+-- together. As we do this we collect GenSymBinds's which represent the renamed
+-- variables bound by the Bindings. In order not to lose track of these
+-- representations we build a shadow datatype MB with the same structure as
+-- MonoBinds, but which has slots for the representations
+
+
+-----------------------------------------------------------------------------
+-- GHC allows a more general form of lambda abstraction than specified
+-- by Haskell 98. In particular it allows guarded lambda's like :
+-- (\ x | even x -> 0 | odd x -> 1) at the moment we can't represent this in
+-- Haskell Template's Meta.Exp type so we punt if it isn't a simple thing like
+-- (\ p1 .. pn -> exp) by causing an error.
+
+repLambda :: LMatch Name -> DsM (Core TH.ExpQ)
+repLambda (L _ (Match ps _ (GRHSs [L _ (GRHS [] e)] EmptyLocalBinds)))
+ = do { let bndrs = collectPatsBinders ps ;
+ ; ss <- mkGenSyms bndrs
+ ; lam <- addBinds ss (
+ do { xs <- repLPs ps; body <- repLE e; repLam xs body })
+ ; wrapGenSyns ss lam }
+
+repLambda z = panic "Can't represent a guarded lambda in Template Haskell"
+
+
+-----------------------------------------------------------------------------
+-- Patterns
+-- repP deals with patterns. It assumes that we have already
+-- walked over the pattern(s) once to collect the binders, and
+-- have extended the environment. So every pattern-bound
+-- variable should already appear in the environment.
+
+-- Process a list of patterns
+repLPs :: [LPat Name] -> DsM (Core [TH.PatQ])
+repLPs ps = do { ps' <- mapM repLP ps ;
+ coreList patQTyConName ps' }
+
+repLP :: LPat Name -> DsM (Core TH.PatQ)
+repLP (L _ p) = repP p
+
+repP :: Pat Name -> DsM (Core TH.PatQ)
+repP (WildPat _) = repPwild
+repP (LitPat l) = do { l2 <- repLiteral l; repPlit l2 }
+repP (VarPat x) = do { x' <- lookupBinder x; repPvar x' }
+repP (LazyPat p) = do { p1 <- repLP p; repPtilde p1 }
+repP (AsPat x p) = do { x' <- lookupLBinder x; p1 <- repLP p; repPaspat x' p1 }
+repP (ParPat p) = repLP p
+repP (ListPat ps _) = do { qs <- repLPs ps; repPlist qs }
+repP (TuplePat ps _ _) = do { qs <- repLPs ps; repPtup qs }
+repP (ConPatIn dc details)
+ = do { con_str <- lookupLOcc dc
+ ; case details of
+ PrefixCon ps -> do { qs <- repLPs ps; repPcon con_str qs }
+ RecCon pairs -> do { vs <- sequence $ map lookupLOcc (map fst pairs)
+ ; ps <- sequence $ map repLP (map snd pairs)
+ ; fps <- zipWithM (\x y -> rep2 fieldPatName [unC x,unC y]) vs ps
+ ; fps' <- coreList fieldPatQTyConName fps
+ ; repPrec con_str fps' }
+ InfixCon p1 p2 -> do { p1' <- repLP p1;
+ p2' <- repLP p2;
+ repPinfix p1' con_str p2' }
+ }
+repP (NPat l (Just _) _ _) = panic "Can't cope with negative overloaded patterns yet (repP (NPat _ (Just _)))"
+repP (NPat l Nothing _ _) = do { a <- repOverloadedLiteral l; repPlit a }
+repP (SigPatIn p t) = do { p' <- repLP p; t' <- repLTy t; repPsig p' t' }
+repP other = panic "Exotic pattern inside meta brackets"
+
+----------------------------------------------------------
+-- Declaration ordering helpers
+
+sort_by_loc :: [(SrcSpan, a)] -> [(SrcSpan, a)]
+sort_by_loc xs = sortBy comp xs
+ where comp x y = compare (fst x) (fst y)
+
+de_loc :: [(a, b)] -> [b]
+de_loc = map snd
+
+----------------------------------------------------------
+-- The meta-environment
+
+-- A name/identifier association for fresh names of locally bound entities
+type GenSymBind = (Name, Id) -- Gensym the string and bind it to the Id
+ -- I.e. (x, x_id) means
+ -- let x_id = gensym "x" in ...
+
+-- Generate a fresh name for a locally bound entity
+
+mkGenSyms :: [Name] -> DsM [GenSymBind]
+-- We can use the existing name. For example:
+-- [| \x_77 -> x_77 + x_77 |]
+-- desugars to
+-- do { x_77 <- genSym "x"; .... }
+-- We use the same x_77 in the desugared program, but with the type Bndr
+-- instead of Int
+--
+-- We do make it an Internal name, though (hence localiseName)
+--
+-- Nevertheless, it's monadic because we have to generate nameTy
+mkGenSyms ns = do { var_ty <- lookupType nameTyConName
+ ; return [(nm, mkLocalId (localiseName nm) var_ty) | nm <- ns] }
+
+
+addBinds :: [GenSymBind] -> DsM a -> DsM a
+-- Add a list of fresh names for locally bound entities to the
+-- meta environment (which is part of the state carried around
+-- by the desugarer monad)
+addBinds bs m = dsExtendMetaEnv (mkNameEnv [(n,Bound id) | (n,id) <- bs]) m
+
+-- Look up a locally bound name
+--
+lookupLBinder :: Located Name -> DsM (Core TH.Name)
+lookupLBinder (L _ n) = lookupBinder n
+
+lookupBinder :: Name -> DsM (Core TH.Name)
+lookupBinder n
+ = do { mb_val <- dsLookupMetaEnv n;
+ case mb_val of
+ Just (Bound x) -> return (coreVar x)
+ other -> pprPanic "DsMeta: failed binder lookup when desugaring a TH bracket:" (ppr n) }
+
+-- Look up a name that is either locally bound or a global name
+--
+-- * If it is a global name, generate the "original name" representation (ie,
+-- the <module>:<name> form) for the associated entity
+--
+lookupLOcc :: Located Name -> DsM (Core TH.Name)
+-- Lookup an occurrence; it can't be a splice.
+-- Use the in-scope bindings if they exist
+lookupLOcc (L _ n) = lookupOcc n
+
+lookupOcc :: Name -> DsM (Core TH.Name)
+lookupOcc n
+ = do { mb_val <- dsLookupMetaEnv n ;
+ case mb_val of
+ Nothing -> globalVar n
+ Just (Bound x) -> return (coreVar x)
+ Just (Splice _) -> pprPanic "repE:lookupOcc" (ppr n)
+ }
+
+globalVar :: Name -> DsM (Core TH.Name)
+-- Not bound by the meta-env
+-- Could be top-level; or could be local
+-- f x = $(g [| x |])
+-- Here the x will be local
+globalVar name
+ | isExternalName name
+ = do { MkC mod <- coreStringLit name_mod
+ ; MkC occ <- occNameLit name
+ ; rep2 mk_varg [mod,occ] }
+ | otherwise
+ = do { MkC occ <- occNameLit name
+ ; MkC uni <- coreIntLit (getKey (getUnique name))
+ ; rep2 mkNameLName [occ,uni] }
+ where
+ name_mod = moduleString (nameModule name)
+ name_occ = nameOccName name
+ mk_varg | OccName.isDataOcc name_occ = mkNameG_dName
+ | OccName.isVarOcc name_occ = mkNameG_vName
+ | OccName.isTcOcc name_occ = mkNameG_tcName
+ | otherwise = pprPanic "DsMeta.globalVar" (ppr name)
+
+lookupType :: Name -- Name of type constructor (e.g. TH.ExpQ)
+ -> DsM Type -- The type
+lookupType tc_name = do { tc <- dsLookupTyCon tc_name ;
+ return (mkTyConApp tc []) }
+
+wrapGenSyns :: [GenSymBind]
+ -> Core (TH.Q a) -> DsM (Core (TH.Q a))
+-- wrapGenSyns [(nm1,id1), (nm2,id2)] y
+-- --> bindQ (gensym nm1) (\ id1 ->
+-- bindQ (gensym nm2 (\ id2 ->
+-- y))
+
+wrapGenSyns binds body@(MkC b)
+ = do { var_ty <- lookupType nameTyConName
+ ; go var_ty binds }
+ where
+ [elt_ty] = tcTyConAppArgs (exprType b)
+ -- b :: Q a, so we can get the type 'a' by looking at the
+ -- argument type. NB: this relies on Q being a data/newtype,
+ -- not a type synonym
+
+ go var_ty [] = return body
+ go var_ty ((name,id) : binds)
+ = do { MkC body' <- go var_ty binds
+ ; lit_str <- occNameLit name
+ ; gensym_app <- repGensym lit_str
+ ; repBindQ var_ty elt_ty
+ gensym_app (MkC (Lam id body')) }
+
+-- Just like wrapGenSym, but don't actually do the gensym
+-- Instead use the existing name:
+-- let x = "x" in ...
+-- Only used for [Decl], and for the class ops in class
+-- and instance decls
+wrapNongenSyms :: [GenSymBind] -> Core a -> DsM (Core a)
+wrapNongenSyms binds (MkC body)
+ = do { binds' <- mapM do_one binds ;
+ return (MkC (mkLets binds' body)) }
+ where
+ do_one (name,id)
+ = do { MkC lit_str <- occNameLit name
+ ; MkC var <- rep2 mkNameName [lit_str]
+ ; return (NonRec id var) }
+
+occNameLit :: Name -> DsM (Core String)
+occNameLit n = coreStringLit (occNameString (nameOccName n))
+
+
+-- %*********************************************************************
+-- %* *
+-- Constructing code
+-- %* *
+-- %*********************************************************************
+
+-----------------------------------------------------------------------------
+-- PHANTOM TYPES for consistency. In order to make sure we do this correct
+-- we invent a new datatype which uses phantom types.
+
+newtype Core a = MkC CoreExpr
+unC (MkC x) = x
+
+rep2 :: Name -> [ CoreExpr ] -> DsM (Core a)
+rep2 n xs = do { id <- dsLookupGlobalId n
+ ; return (MkC (foldl App (Var id) xs)) }
+
+-- Then we make "repConstructors" which use the phantom types for each of the
+-- smart constructors of the Meta.Meta datatypes.
+
+
+-- %*********************************************************************
+-- %* *
+-- The 'smart constructors'
+-- %* *
+-- %*********************************************************************
+
+--------------- Patterns -----------------
+repPlit :: Core TH.Lit -> DsM (Core TH.PatQ)
+repPlit (MkC l) = rep2 litPName [l]
+
+repPvar :: Core TH.Name -> DsM (Core TH.PatQ)
+repPvar (MkC s) = rep2 varPName [s]
+
+repPtup :: Core [TH.PatQ] -> DsM (Core TH.PatQ)
+repPtup (MkC ps) = rep2 tupPName [ps]
+
+repPcon :: Core TH.Name -> Core [TH.PatQ] -> DsM (Core TH.PatQ)
+repPcon (MkC s) (MkC ps) = rep2 conPName [s, ps]
+
+repPrec :: Core TH.Name -> Core [(TH.Name,TH.PatQ)] -> DsM (Core TH.PatQ)
+repPrec (MkC c) (MkC rps) = rep2 recPName [c,rps]
+
+repPinfix :: Core TH.PatQ -> Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)
+repPinfix (MkC p1) (MkC n) (MkC p2) = rep2 infixPName [p1, n, p2]
+
+repPtilde :: Core TH.PatQ -> DsM (Core TH.PatQ)
+repPtilde (MkC p) = rep2 tildePName [p]
+
+repPaspat :: Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)
+repPaspat (MkC s) (MkC p) = rep2 asPName [s, p]
+
+repPwild :: DsM (Core TH.PatQ)
+repPwild = rep2 wildPName []
+
+repPlist :: Core [TH.PatQ] -> DsM (Core TH.PatQ)
+repPlist (MkC ps) = rep2 listPName [ps]
+
+repPsig :: Core TH.PatQ -> Core TH.TypeQ -> DsM (Core TH.PatQ)
+repPsig (MkC p) (MkC t) = rep2 sigPName [p, t]
+
+--------------- Expressions -----------------
+repVarOrCon :: Name -> Core TH.Name -> DsM (Core TH.ExpQ)
+repVarOrCon vc str | isDataOcc (nameOccName vc) = repCon str
+ | otherwise = repVar str
+
+repVar :: Core TH.Name -> DsM (Core TH.ExpQ)
+repVar (MkC s) = rep2 varEName [s]
+
+repCon :: Core TH.Name -> DsM (Core TH.ExpQ)
+repCon (MkC s) = rep2 conEName [s]
+
+repLit :: Core TH.Lit -> DsM (Core TH.ExpQ)
+repLit (MkC c) = rep2 litEName [c]
+
+repApp :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repApp (MkC x) (MkC y) = rep2 appEName [x,y]
+
+repLam :: Core [TH.PatQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repLam (MkC ps) (MkC e) = rep2 lamEName [ps, e]
+
+repTup :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)
+repTup (MkC es) = rep2 tupEName [es]
+
+repCond :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repCond (MkC x) (MkC y) (MkC z) = rep2 condEName [x,y,z]
+
+repLetE :: Core [TH.DecQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repLetE (MkC ds) (MkC e) = rep2 letEName [ds, e]
+
+repCaseE :: Core TH.ExpQ -> Core [TH.MatchQ] -> DsM( Core TH.ExpQ)
+repCaseE (MkC e) (MkC ms) = rep2 caseEName [e, ms]
+
+repDoE :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)
+repDoE (MkC ss) = rep2 doEName [ss]
+
+repComp :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)
+repComp (MkC ss) = rep2 compEName [ss]
+
+repListExp :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)
+repListExp (MkC es) = rep2 listEName [es]
+
+repSigExp :: Core TH.ExpQ -> Core TH.TypeQ -> DsM (Core TH.ExpQ)
+repSigExp (MkC e) (MkC t) = rep2 sigEName [e,t]
+
+repRecCon :: Core TH.Name -> Core [TH.Q TH.FieldExp]-> DsM (Core TH.ExpQ)
+repRecCon (MkC c) (MkC fs) = rep2 recConEName [c,fs]
+
+repRecUpd :: Core TH.ExpQ -> Core [TH.Q TH.FieldExp] -> DsM (Core TH.ExpQ)
+repRecUpd (MkC e) (MkC fs) = rep2 recUpdEName [e,fs]
+
+repFieldExp :: Core TH.Name -> Core TH.ExpQ -> DsM (Core (TH.Q TH.FieldExp))
+repFieldExp (MkC n) (MkC x) = rep2 fieldExpName [n,x]
+
+repInfixApp :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repInfixApp (MkC x) (MkC y) (MkC z) = rep2 infixAppName [x,y,z]
+
+repSectionL :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repSectionL (MkC x) (MkC y) = rep2 sectionLName [x,y]
+
+repSectionR :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repSectionR (MkC x) (MkC y) = rep2 sectionRName [x,y]
+
+------------ Right hand sides (guarded expressions) ----
+repGuarded :: Core [TH.Q (TH.Guard, TH.Exp)] -> DsM (Core TH.BodyQ)
+repGuarded (MkC pairs) = rep2 guardedBName [pairs]
+
+repNormal :: Core TH.ExpQ -> DsM (Core TH.BodyQ)
+repNormal (MkC e) = rep2 normalBName [e]
+
+------------ Guards ----
+repLNormalGE :: LHsExpr Name -> LHsExpr Name -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))
+repLNormalGE g e = do g' <- repLE g
+ e' <- repLE e
+ repNormalGE g' e'
+
+repNormalGE :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))
+repNormalGE (MkC g) (MkC e) = rep2 normalGEName [g, e]
+
+repPatGE :: Core [TH.StmtQ] -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))
+repPatGE (MkC ss) (MkC e) = rep2 patGEName [ss, e]
+
+------------- Stmts -------------------
+repBindSt :: Core TH.PatQ -> Core TH.ExpQ -> DsM (Core TH.StmtQ)
+repBindSt (MkC p) (MkC e) = rep2 bindSName [p,e]
+
+repLetSt :: Core [TH.DecQ] -> DsM (Core TH.StmtQ)
+repLetSt (MkC ds) = rep2 letSName [ds]
+
+repNoBindSt :: Core TH.ExpQ -> DsM (Core TH.StmtQ)
+repNoBindSt (MkC e) = rep2 noBindSName [e]
+
+-------------- Range (Arithmetic sequences) -----------
+repFrom :: Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repFrom (MkC x) = rep2 fromEName [x]
+
+repFromThen :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repFromThen (MkC x) (MkC y) = rep2 fromThenEName [x,y]
+
+repFromTo :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repFromTo (MkC x) (MkC y) = rep2 fromToEName [x,y]
+
+repFromThenTo :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)
+repFromThenTo (MkC x) (MkC y) (MkC z) = rep2 fromThenToEName [x,y,z]
+
+------------ Match and Clause Tuples -----------
+repMatch :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.MatchQ)
+repMatch (MkC p) (MkC bod) (MkC ds) = rep2 matchName [p, bod, ds]
+
+repClause :: Core [TH.PatQ] -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.ClauseQ)
+repClause (MkC ps) (MkC bod) (MkC ds) = rep2 clauseName [ps, bod, ds]
+
+-------------- Dec -----------------------------
+repVal :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)
+repVal (MkC p) (MkC b) (MkC ds) = rep2 valDName [p, b, ds]
+
+repFun :: Core TH.Name -> Core [TH.ClauseQ] -> DsM (Core TH.DecQ)
+repFun (MkC nm) (MkC b) = rep2 funDName [nm, b]
+
+repData :: Core TH.CxtQ -> Core TH.Name -> Core [TH.Name] -> Core [TH.ConQ] -> Core [TH.Name] -> DsM (Core TH.DecQ)
+repData (MkC cxt) (MkC nm) (MkC tvs) (MkC cons) (MkC derivs)
+ = rep2 dataDName [cxt, nm, tvs, cons, derivs]
+
+repNewtype :: Core TH.CxtQ -> Core TH.Name -> Core [TH.Name] -> Core TH.ConQ -> Core [TH.Name] -> DsM (Core TH.DecQ)
+repNewtype (MkC cxt) (MkC nm) (MkC tvs) (MkC con) (MkC derivs)
+ = rep2 newtypeDName [cxt, nm, tvs, con, derivs]
+
+repTySyn :: Core TH.Name -> Core [TH.Name] -> Core TH.TypeQ -> DsM (Core TH.DecQ)
+repTySyn (MkC nm) (MkC tvs) (MkC rhs) = rep2 tySynDName [nm, tvs, rhs]
+
+repInst :: Core TH.CxtQ -> Core TH.TypeQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)
+repInst (MkC cxt) (MkC ty) (MkC ds) = rep2 instanceDName [cxt, ty, ds]
+
+repClass :: Core TH.CxtQ -> Core TH.Name -> Core [TH.Name] -> Core [TH.FunDep] -> Core [TH.DecQ] -> DsM (Core TH.DecQ)
+repClass (MkC cxt) (MkC cls) (MkC tvs) (MkC fds) (MkC ds) = rep2 classDName [cxt, cls, tvs, fds, ds]
+
+repFunDep :: Core [TH.Name] -> Core [TH.Name] -> DsM (Core TH.FunDep)
+repFunDep (MkC xs) (MkC ys) = rep2 funDepName [xs, ys]
+
+repProto :: Core TH.Name -> Core TH.TypeQ -> DsM (Core TH.DecQ)
+repProto (MkC s) (MkC ty) = rep2 sigDName [s, ty]
+
+repCtxt :: Core [TH.TypeQ] -> DsM (Core TH.CxtQ)
+repCtxt (MkC tys) = rep2 cxtName [tys]
+
+repConstr :: Core TH.Name -> HsConDetails Name (LBangType Name)
+ -> DsM (Core TH.ConQ)
+repConstr con (PrefixCon ps)
+ = do arg_tys <- mapM repBangTy ps
+ arg_tys1 <- coreList strictTypeQTyConName arg_tys
+ rep2 normalCName [unC con, unC arg_tys1]
+repConstr con (RecCon ips)
+ = do arg_vs <- mapM lookupLOcc (map fst ips)
+ arg_tys <- mapM repBangTy (map snd ips)
+ arg_vtys <- zipWithM (\x y -> rep2 varStrictTypeName [unC x, unC y])
+ arg_vs arg_tys
+ arg_vtys' <- coreList varStrictTypeQTyConName arg_vtys
+ rep2 recCName [unC con, unC arg_vtys']
+repConstr con (InfixCon st1 st2)
+ = do arg1 <- repBangTy st1
+ arg2 <- repBangTy st2
+ rep2 infixCName [unC arg1, unC con, unC arg2]
+
+------------ Types -------------------
+
+repTForall :: Core [TH.Name] -> Core TH.CxtQ -> Core TH.TypeQ -> DsM (Core TH.TypeQ)
+repTForall (MkC tvars) (MkC ctxt) (MkC ty)
+ = rep2 forallTName [tvars, ctxt, ty]
+
+repTvar :: Core TH.Name -> DsM (Core TH.TypeQ)
+repTvar (MkC s) = rep2 varTName [s]
+
+repTapp :: Core TH.TypeQ -> Core TH.TypeQ -> DsM (Core TH.TypeQ)
+repTapp (MkC t1) (MkC t2) = rep2 appTName [t1,t2]
+
+repTapps :: Core TH.TypeQ -> [Core TH.TypeQ] -> DsM (Core TH.TypeQ)
+repTapps f [] = return f
+repTapps f (t:ts) = do { f1 <- repTapp f t; repTapps f1 ts }
+
+--------- Type constructors --------------
+
+repNamedTyCon :: Core TH.Name -> DsM (Core TH.TypeQ)
+repNamedTyCon (MkC s) = rep2 conTName [s]
+
+repTupleTyCon :: Int -> DsM (Core TH.TypeQ)
+-- Note: not Core Int; it's easier to be direct here
+repTupleTyCon i = rep2 tupleTName [mkIntExpr (fromIntegral i)]
+
+repArrowTyCon :: DsM (Core TH.TypeQ)
+repArrowTyCon = rep2 arrowTName []
+
+repListTyCon :: DsM (Core TH.TypeQ)
+repListTyCon = rep2 listTName []
+
+
+----------------------------------------------------------
+-- Literals
+
+repLiteral :: HsLit -> DsM (Core TH.Lit)
+repLiteral lit
+ = do lit' <- case lit of
+ HsIntPrim i -> mk_integer i
+ HsInt i -> mk_integer i
+ HsFloatPrim r -> mk_rational r
+ HsDoublePrim r -> mk_rational r
+ _ -> return lit
+ lit_expr <- dsLit lit'
+ rep2 lit_name [lit_expr]
+ where
+ lit_name = case lit of
+ HsInteger _ _ -> integerLName
+ HsInt _ -> integerLName
+ HsIntPrim _ -> intPrimLName
+ HsFloatPrim _ -> floatPrimLName
+ HsDoublePrim _ -> doublePrimLName
+ HsChar _ -> charLName
+ HsString _ -> stringLName
+ HsRat _ _ -> rationalLName
+ other -> uh_oh
+ uh_oh = pprPanic "DsMeta.repLiteral: trying to represent exotic literal"
+ (ppr lit)
+
+mk_integer i = do integer_ty <- lookupType integerTyConName
+ return $ HsInteger i integer_ty
+mk_rational r = do rat_ty <- lookupType rationalTyConName
+ return $ HsRat r rat_ty
+
+repOverloadedLiteral :: HsOverLit Name -> DsM (Core TH.Lit)
+repOverloadedLiteral (HsIntegral i _) = do { lit <- mk_integer i; repLiteral lit }
+repOverloadedLiteral (HsFractional f _) = do { lit <- mk_rational f; repLiteral lit }
+ -- The type Rational will be in the environment, becuase
+ -- the smart constructor 'TH.Syntax.rationalL' uses it in its type,
+ -- and rationalL is sucked in when any TH stuff is used
+
+--------------- Miscellaneous -------------------
+
+repGensym :: Core String -> DsM (Core (TH.Q TH.Name))
+repGensym (MkC lit_str) = rep2 newNameName [lit_str]
+
+repBindQ :: Type -> Type -- a and b
+ -> Core (TH.Q a) -> Core (a -> TH.Q b) -> DsM (Core (TH.Q b))
+repBindQ ty_a ty_b (MkC x) (MkC y)
+ = rep2 bindQName [Type ty_a, Type ty_b, x, y]
+
+repSequenceQ :: Type -> Core [TH.Q a] -> DsM (Core (TH.Q [a]))
+repSequenceQ ty_a (MkC list)
+ = rep2 sequenceQName [Type ty_a, list]
+
+------------ Lists and Tuples -------------------
+-- turn a list of patterns into a single pattern matching a list
+
+coreList :: Name -- Of the TyCon of the element type
+ -> [Core a] -> DsM (Core [a])
+coreList tc_name es
+ = do { elt_ty <- lookupType tc_name; return (coreList' elt_ty es) }
+
+coreList' :: Type -- The element type
+ -> [Core a] -> Core [a]
+coreList' elt_ty es = MkC (mkListExpr elt_ty (map unC es ))
+
+nonEmptyCoreList :: [Core a] -> Core [a]
+ -- The list must be non-empty so we can get the element type
+ -- Otherwise use coreList
+nonEmptyCoreList [] = panic "coreList: empty argument"
+nonEmptyCoreList xs@(MkC x:_) = MkC (mkListExpr (exprType x) (map unC xs))
+
+corePair :: (Core a, Core b) -> Core (a,b)
+corePair (MkC x, MkC y) = MkC (mkCoreTup [x,y])
+
+coreStringLit :: String -> DsM (Core String)
+coreStringLit s = do { z <- mkStringExpr s; return(MkC z) }
+
+coreIntLit :: Int -> DsM (Core Int)
+coreIntLit i = return (MkC (mkIntExpr (fromIntegral i)))
+
+coreVar :: Id -> Core TH.Name -- The Id has type Name
+coreVar id = MkC (Var id)
+
+
+
+-- %************************************************************************
+-- %* *
+-- The known-key names for Template Haskell
+-- %* *
+-- %************************************************************************
+
+-- To add a name, do three things
+--
+-- 1) Allocate a key
+-- 2) Make a "Name"
+-- 3) Add the name to knownKeyNames
+
+templateHaskellNames :: [Name]
+-- The names that are implicitly mentioned by ``bracket''
+-- Should stay in sync with the import list of DsMeta
+
+templateHaskellNames = [
+ returnQName, bindQName, sequenceQName, newNameName, liftName,
+ mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameLName,
+
+ -- Lit
+ charLName, stringLName, integerLName, intPrimLName,
+ floatPrimLName, doublePrimLName, rationalLName,
+ -- Pat
+ litPName, varPName, tupPName, conPName, tildePName, infixPName,
+ asPName, wildPName, recPName, listPName, sigPName,
+ -- FieldPat
+ fieldPatName,
+ -- Match
+ matchName,
+ -- Clause
+ clauseName,
+ -- Exp
+ varEName, conEName, litEName, appEName, infixEName,
+ infixAppName, sectionLName, sectionRName, lamEName, tupEName,
+ condEName, letEName, caseEName, doEName, compEName,
+ fromEName, fromThenEName, fromToEName, fromThenToEName,
+ listEName, sigEName, recConEName, recUpdEName,
+ -- FieldExp
+ fieldExpName,
+ -- Body
+ guardedBName, normalBName,
+ -- Guard
+ normalGEName, patGEName,
+ -- Stmt
+ bindSName, letSName, noBindSName, parSName,
+ -- Dec
+ funDName, valDName, dataDName, newtypeDName, tySynDName,
+ classDName, instanceDName, sigDName, forImpDName,
+ -- Cxt
+ cxtName,
+ -- Strict
+ isStrictName, notStrictName,
+ -- Con
+ normalCName, recCName, infixCName, forallCName,
+ -- StrictType
+ strictTypeName,
+ -- VarStrictType
+ varStrictTypeName,
+ -- Type
+ forallTName, varTName, conTName, appTName,
+ tupleTName, arrowTName, listTName,
+ -- Callconv
+ cCallName, stdCallName,
+ -- Safety
+ unsafeName,
+ safeName,
+ threadsafeName,
+ -- FunDep
+ funDepName,
+
+ -- And the tycons
+ qTyConName, nameTyConName, patTyConName, fieldPatTyConName, matchQTyConName,
+ clauseQTyConName, expQTyConName, fieldExpTyConName, stmtQTyConName,
+ decQTyConName, conQTyConName, strictTypeQTyConName,
+ varStrictTypeQTyConName, typeQTyConName, expTyConName, decTyConName,
+ typeTyConName, matchTyConName, clauseTyConName, patQTyConName,
+ fieldPatQTyConName, fieldExpQTyConName, funDepTyConName]
+
+thSyn :: Module
+thSyn = mkModule "Language.Haskell.TH.Syntax"
+thLib = mkModule "Language.Haskell.TH.Lib"
+
+mk_known_key_name mod space str uniq
+ = mkExternalName uniq mod (mkOccNameFS space str)
+ Nothing noSrcLoc
+
+libFun = mk_known_key_name thLib OccName.varName
+libTc = mk_known_key_name thLib OccName.tcName
+thFun = mk_known_key_name thSyn OccName.varName
+thTc = mk_known_key_name thSyn OccName.tcName
+
+-------------------- TH.Syntax -----------------------
+qTyConName = thTc FSLIT("Q") qTyConKey
+nameTyConName = thTc FSLIT("Name") nameTyConKey
+fieldExpTyConName = thTc FSLIT("FieldExp") fieldExpTyConKey
+patTyConName = thTc FSLIT("Pat") patTyConKey
+fieldPatTyConName = thTc FSLIT("FieldPat") fieldPatTyConKey
+expTyConName = thTc FSLIT("Exp") expTyConKey
+decTyConName = thTc FSLIT("Dec") decTyConKey
+typeTyConName = thTc FSLIT("Type") typeTyConKey
+matchTyConName = thTc FSLIT("Match") matchTyConKey
+clauseTyConName = thTc FSLIT("Clause") clauseTyConKey
+funDepTyConName = thTc FSLIT("FunDep") funDepTyConKey
+
+returnQName = thFun FSLIT("returnQ") returnQIdKey
+bindQName = thFun FSLIT("bindQ") bindQIdKey
+sequenceQName = thFun FSLIT("sequenceQ") sequenceQIdKey
+newNameName = thFun FSLIT("newName") newNameIdKey
+liftName = thFun FSLIT("lift") liftIdKey
+mkNameName = thFun FSLIT("mkName") mkNameIdKey
+mkNameG_vName = thFun FSLIT("mkNameG_v") mkNameG_vIdKey
+mkNameG_dName = thFun FSLIT("mkNameG_d") mkNameG_dIdKey
+mkNameG_tcName = thFun FSLIT("mkNameG_tc") mkNameG_tcIdKey
+mkNameLName = thFun FSLIT("mkNameL") mkNameLIdKey
+
+
+-------------------- TH.Lib -----------------------
+-- data Lit = ...
+charLName = libFun FSLIT("charL") charLIdKey
+stringLName = libFun FSLIT("stringL") stringLIdKey
+integerLName = libFun FSLIT("integerL") integerLIdKey
+intPrimLName = libFun FSLIT("intPrimL") intPrimLIdKey
+floatPrimLName = libFun FSLIT("floatPrimL") floatPrimLIdKey
+doublePrimLName = libFun FSLIT("doublePrimL") doublePrimLIdKey
+rationalLName = libFun FSLIT("rationalL") rationalLIdKey
+
+-- data Pat = ...
+litPName = libFun FSLIT("litP") litPIdKey
+varPName = libFun FSLIT("varP") varPIdKey
+tupPName = libFun FSLIT("tupP") tupPIdKey
+conPName = libFun FSLIT("conP") conPIdKey
+infixPName = libFun FSLIT("infixP") infixPIdKey
+tildePName = libFun FSLIT("tildeP") tildePIdKey
+asPName = libFun FSLIT("asP") asPIdKey
+wildPName = libFun FSLIT("wildP") wildPIdKey
+recPName = libFun FSLIT("recP") recPIdKey
+listPName = libFun FSLIT("listP") listPIdKey
+sigPName = libFun FSLIT("sigP") sigPIdKey
+
+-- type FieldPat = ...
+fieldPatName = libFun FSLIT("fieldPat") fieldPatIdKey
+
+-- data Match = ...
+matchName = libFun FSLIT("match") matchIdKey
+
+-- data Clause = ...
+clauseName = libFun FSLIT("clause") clauseIdKey
+
+-- data Exp = ...
+varEName = libFun FSLIT("varE") varEIdKey
+conEName = libFun FSLIT("conE") conEIdKey
+litEName = libFun FSLIT("litE") litEIdKey
+appEName = libFun FSLIT("appE") appEIdKey
+infixEName = libFun FSLIT("infixE") infixEIdKey
+infixAppName = libFun FSLIT("infixApp") infixAppIdKey
+sectionLName = libFun FSLIT("sectionL") sectionLIdKey
+sectionRName = libFun FSLIT("sectionR") sectionRIdKey
+lamEName = libFun FSLIT("lamE") lamEIdKey
+tupEName = libFun FSLIT("tupE") tupEIdKey
+condEName = libFun FSLIT("condE") condEIdKey
+letEName = libFun FSLIT("letE") letEIdKey
+caseEName = libFun FSLIT("caseE") caseEIdKey
+doEName = libFun FSLIT("doE") doEIdKey
+compEName = libFun FSLIT("compE") compEIdKey
+-- ArithSeq skips a level
+fromEName = libFun FSLIT("fromE") fromEIdKey
+fromThenEName = libFun FSLIT("fromThenE") fromThenEIdKey
+fromToEName = libFun FSLIT("fromToE") fromToEIdKey
+fromThenToEName = libFun FSLIT("fromThenToE") fromThenToEIdKey
+-- end ArithSeq
+listEName = libFun FSLIT("listE") listEIdKey
+sigEName = libFun FSLIT("sigE") sigEIdKey
+recConEName = libFun FSLIT("recConE") recConEIdKey
+recUpdEName = libFun FSLIT("recUpdE") recUpdEIdKey
+
+-- type FieldExp = ...
+fieldExpName = libFun FSLIT("fieldExp") fieldExpIdKey
+
+-- data Body = ...
+guardedBName = libFun FSLIT("guardedB") guardedBIdKey
+normalBName = libFun FSLIT("normalB") normalBIdKey
+
+-- data Guard = ...
+normalGEName = libFun FSLIT("normalGE") normalGEIdKey
+patGEName = libFun FSLIT("patGE") patGEIdKey
+
+-- data Stmt = ...
+bindSName = libFun FSLIT("bindS") bindSIdKey
+letSName = libFun FSLIT("letS") letSIdKey
+noBindSName = libFun FSLIT("noBindS") noBindSIdKey
+parSName = libFun FSLIT("parS") parSIdKey
+
+-- data Dec = ...
+funDName = libFun FSLIT("funD") funDIdKey
+valDName = libFun FSLIT("valD") valDIdKey
+dataDName = libFun FSLIT("dataD") dataDIdKey
+newtypeDName = libFun FSLIT("newtypeD") newtypeDIdKey
+tySynDName = libFun FSLIT("tySynD") tySynDIdKey
+classDName = libFun FSLIT("classD") classDIdKey
+instanceDName = libFun FSLIT("instanceD") instanceDIdKey
+sigDName = libFun FSLIT("sigD") sigDIdKey
+forImpDName = libFun FSLIT("forImpD") forImpDIdKey
+
+-- type Ctxt = ...
+cxtName = libFun FSLIT("cxt") cxtIdKey
+
+-- data Strict = ...
+isStrictName = libFun FSLIT("isStrict") isStrictKey
+notStrictName = libFun FSLIT("notStrict") notStrictKey
+
+-- data Con = ...
+normalCName = libFun FSLIT("normalC") normalCIdKey
+recCName = libFun FSLIT("recC") recCIdKey
+infixCName = libFun FSLIT("infixC") infixCIdKey
+forallCName = libFun FSLIT("forallC") forallCIdKey
+
+-- type StrictType = ...
+strictTypeName = libFun FSLIT("strictType") strictTKey
+
+-- type VarStrictType = ...
+varStrictTypeName = libFun FSLIT("varStrictType") varStrictTKey
+
+-- data Type = ...
+forallTName = libFun FSLIT("forallT") forallTIdKey
+varTName = libFun FSLIT("varT") varTIdKey
+conTName = libFun FSLIT("conT") conTIdKey
+tupleTName = libFun FSLIT("tupleT") tupleTIdKey
+arrowTName = libFun FSLIT("arrowT") arrowTIdKey
+listTName = libFun FSLIT("listT") listTIdKey
+appTName = libFun FSLIT("appT") appTIdKey
+
+-- data Callconv = ...
+cCallName = libFun FSLIT("cCall") cCallIdKey
+stdCallName = libFun FSLIT("stdCall") stdCallIdKey
+
+-- data Safety = ...
+unsafeName = libFun FSLIT("unsafe") unsafeIdKey
+safeName = libFun FSLIT("safe") safeIdKey
+threadsafeName = libFun FSLIT("threadsafe") threadsafeIdKey
+
+-- data FunDep = ...
+funDepName = libFun FSLIT("funDep") funDepIdKey
+
+matchQTyConName = libTc FSLIT("MatchQ") matchQTyConKey
+clauseQTyConName = libTc FSLIT("ClauseQ") clauseQTyConKey
+expQTyConName = libTc FSLIT("ExpQ") expQTyConKey
+stmtQTyConName = libTc FSLIT("StmtQ") stmtQTyConKey
+decQTyConName = libTc FSLIT("DecQ") decQTyConKey
+conQTyConName = libTc FSLIT("ConQ") conQTyConKey
+strictTypeQTyConName = libTc FSLIT("StrictTypeQ") strictTypeQTyConKey
+varStrictTypeQTyConName = libTc FSLIT("VarStrictTypeQ") varStrictTypeQTyConKey
+typeQTyConName = libTc FSLIT("TypeQ") typeQTyConKey
+fieldExpQTyConName = libTc FSLIT("FieldExpQ") fieldExpQTyConKey
+patQTyConName = libTc FSLIT("PatQ") patQTyConKey
+fieldPatQTyConName = libTc FSLIT("FieldPatQ") fieldPatQTyConKey
+
+-- TyConUniques available: 100-129
+-- Check in PrelNames if you want to change this
+
+expTyConKey = mkPreludeTyConUnique 100
+matchTyConKey = mkPreludeTyConUnique 101
+clauseTyConKey = mkPreludeTyConUnique 102
+qTyConKey = mkPreludeTyConUnique 103
+expQTyConKey = mkPreludeTyConUnique 104
+decQTyConKey = mkPreludeTyConUnique 105
+patTyConKey = mkPreludeTyConUnique 106
+matchQTyConKey = mkPreludeTyConUnique 107
+clauseQTyConKey = mkPreludeTyConUnique 108
+stmtQTyConKey = mkPreludeTyConUnique 109
+conQTyConKey = mkPreludeTyConUnique 110
+typeQTyConKey = mkPreludeTyConUnique 111
+typeTyConKey = mkPreludeTyConUnique 112
+decTyConKey = mkPreludeTyConUnique 113
+varStrictTypeQTyConKey = mkPreludeTyConUnique 114
+strictTypeQTyConKey = mkPreludeTyConUnique 115
+fieldExpTyConKey = mkPreludeTyConUnique 116
+fieldPatTyConKey = mkPreludeTyConUnique 117
+nameTyConKey = mkPreludeTyConUnique 118
+patQTyConKey = mkPreludeTyConUnique 119
+fieldPatQTyConKey = mkPreludeTyConUnique 120
+fieldExpQTyConKey = mkPreludeTyConUnique 121
+funDepTyConKey = mkPreludeTyConUnique 122
+
+-- IdUniques available: 200-399
+-- If you want to change this, make sure you check in PrelNames
+
+returnQIdKey = mkPreludeMiscIdUnique 200
+bindQIdKey = mkPreludeMiscIdUnique 201
+sequenceQIdKey = mkPreludeMiscIdUnique 202
+liftIdKey = mkPreludeMiscIdUnique 203
+newNameIdKey = mkPreludeMiscIdUnique 204
+mkNameIdKey = mkPreludeMiscIdUnique 205
+mkNameG_vIdKey = mkPreludeMiscIdUnique 206
+mkNameG_dIdKey = mkPreludeMiscIdUnique 207
+mkNameG_tcIdKey = mkPreludeMiscIdUnique 208
+mkNameLIdKey = mkPreludeMiscIdUnique 209
+
+
+-- data Lit = ...
+charLIdKey = mkPreludeMiscIdUnique 210
+stringLIdKey = mkPreludeMiscIdUnique 211
+integerLIdKey = mkPreludeMiscIdUnique 212
+intPrimLIdKey = mkPreludeMiscIdUnique 213
+floatPrimLIdKey = mkPreludeMiscIdUnique 214
+doublePrimLIdKey = mkPreludeMiscIdUnique 215
+rationalLIdKey = mkPreludeMiscIdUnique 216
+
+-- data Pat = ...
+litPIdKey = mkPreludeMiscIdUnique 220
+varPIdKey = mkPreludeMiscIdUnique 221
+tupPIdKey = mkPreludeMiscIdUnique 222
+conPIdKey = mkPreludeMiscIdUnique 223
+infixPIdKey = mkPreludeMiscIdUnique 312
+tildePIdKey = mkPreludeMiscIdUnique 224
+asPIdKey = mkPreludeMiscIdUnique 225
+wildPIdKey = mkPreludeMiscIdUnique 226
+recPIdKey = mkPreludeMiscIdUnique 227
+listPIdKey = mkPreludeMiscIdUnique 228
+sigPIdKey = mkPreludeMiscIdUnique 229
+
+-- type FieldPat = ...
+fieldPatIdKey = mkPreludeMiscIdUnique 230
+
+-- data Match = ...
+matchIdKey = mkPreludeMiscIdUnique 231
+
+-- data Clause = ...
+clauseIdKey = mkPreludeMiscIdUnique 232
+
+-- data Exp = ...
+varEIdKey = mkPreludeMiscIdUnique 240
+conEIdKey = mkPreludeMiscIdUnique 241
+litEIdKey = mkPreludeMiscIdUnique 242
+appEIdKey = mkPreludeMiscIdUnique 243
+infixEIdKey = mkPreludeMiscIdUnique 244
+infixAppIdKey = mkPreludeMiscIdUnique 245
+sectionLIdKey = mkPreludeMiscIdUnique 246
+sectionRIdKey = mkPreludeMiscIdUnique 247
+lamEIdKey = mkPreludeMiscIdUnique 248
+tupEIdKey = mkPreludeMiscIdUnique 249
+condEIdKey = mkPreludeMiscIdUnique 250
+letEIdKey = mkPreludeMiscIdUnique 251
+caseEIdKey = mkPreludeMiscIdUnique 252
+doEIdKey = mkPreludeMiscIdUnique 253
+compEIdKey = mkPreludeMiscIdUnique 254
+fromEIdKey = mkPreludeMiscIdUnique 255
+fromThenEIdKey = mkPreludeMiscIdUnique 256
+fromToEIdKey = mkPreludeMiscIdUnique 257
+fromThenToEIdKey = mkPreludeMiscIdUnique 258
+listEIdKey = mkPreludeMiscIdUnique 259
+sigEIdKey = mkPreludeMiscIdUnique 260
+recConEIdKey = mkPreludeMiscIdUnique 261
+recUpdEIdKey = mkPreludeMiscIdUnique 262
+
+-- type FieldExp = ...
+fieldExpIdKey = mkPreludeMiscIdUnique 265
+
+-- data Body = ...
+guardedBIdKey = mkPreludeMiscIdUnique 266
+normalBIdKey = mkPreludeMiscIdUnique 267
+
+-- data Guard = ...
+normalGEIdKey = mkPreludeMiscIdUnique 310
+patGEIdKey = mkPreludeMiscIdUnique 311
+
+-- data Stmt = ...
+bindSIdKey = mkPreludeMiscIdUnique 268
+letSIdKey = mkPreludeMiscIdUnique 269
+noBindSIdKey = mkPreludeMiscIdUnique 270
+parSIdKey = mkPreludeMiscIdUnique 271
+
+-- data Dec = ...
+funDIdKey = mkPreludeMiscIdUnique 272
+valDIdKey = mkPreludeMiscIdUnique 273
+dataDIdKey = mkPreludeMiscIdUnique 274
+newtypeDIdKey = mkPreludeMiscIdUnique 275
+tySynDIdKey = mkPreludeMiscIdUnique 276
+classDIdKey = mkPreludeMiscIdUnique 277
+instanceDIdKey = mkPreludeMiscIdUnique 278
+sigDIdKey = mkPreludeMiscIdUnique 279
+forImpDIdKey = mkPreludeMiscIdUnique 297
+
+-- type Cxt = ...
+cxtIdKey = mkPreludeMiscIdUnique 280
+
+-- data Strict = ...
+isStrictKey = mkPreludeMiscIdUnique 281
+notStrictKey = mkPreludeMiscIdUnique 282
+
+-- data Con = ...
+normalCIdKey = mkPreludeMiscIdUnique 283
+recCIdKey = mkPreludeMiscIdUnique 284
+infixCIdKey = mkPreludeMiscIdUnique 285
+forallCIdKey = mkPreludeMiscIdUnique 288
+
+-- type StrictType = ...
+strictTKey = mkPreludeMiscIdUnique 286
+
+-- type VarStrictType = ...
+varStrictTKey = mkPreludeMiscIdUnique 287
+
+-- data Type = ...
+forallTIdKey = mkPreludeMiscIdUnique 290
+varTIdKey = mkPreludeMiscIdUnique 291
+conTIdKey = mkPreludeMiscIdUnique 292
+tupleTIdKey = mkPreludeMiscIdUnique 294
+arrowTIdKey = mkPreludeMiscIdUnique 295
+listTIdKey = mkPreludeMiscIdUnique 296
+appTIdKey = mkPreludeMiscIdUnique 293
+
+-- data Callconv = ...
+cCallIdKey = mkPreludeMiscIdUnique 300
+stdCallIdKey = mkPreludeMiscIdUnique 301
+
+-- data Safety = ...
+unsafeIdKey = mkPreludeMiscIdUnique 305
+safeIdKey = mkPreludeMiscIdUnique 306
+threadsafeIdKey = mkPreludeMiscIdUnique 307
+
+-- data FunDep = ...
+funDepIdKey = mkPreludeMiscIdUnique 320
+
diff --git a/compiler/deSugar/DsMonad.lhs b/compiler/deSugar/DsMonad.lhs
new file mode 100644
index 0000000000..f24dee4905
--- /dev/null
+++ b/compiler/deSugar/DsMonad.lhs
@@ -0,0 +1,285 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsMonad]{@DsMonad@: monadery used in desugaring}
+
+\begin{code}
+module DsMonad (
+ DsM, mappM, mapAndUnzipM,
+ initDs, returnDs, thenDs, listDs, fixDs, mapAndUnzipDs,
+ foldlDs, foldrDs,
+
+ newTyVarsDs, newLocalName,
+ duplicateLocalDs, newSysLocalDs, newSysLocalsDs, newUniqueId,
+ newFailLocalDs,
+ getSrcSpanDs, putSrcSpanDs,
+ getModuleDs,
+ newUnique,
+ UniqSupply, newUniqueSupply,
+ getDOptsDs,
+ dsLookupGlobal, dsLookupGlobalId, dsLookupTyCon, dsLookupDataCon,
+
+ DsMetaEnv, DsMetaVal(..), dsLookupMetaEnv, dsExtendMetaEnv,
+
+ -- Warnings
+ DsWarning, dsWarn,
+
+ -- Data types
+ DsMatchContext(..),
+ EquationInfo(..), MatchResult(..), DsWrapper, idWrapper,
+ CanItFail(..), orFail
+ ) where
+
+#include "HsVersions.h"
+
+import TcRnMonad
+import CoreSyn ( CoreExpr )
+import HsSyn ( HsExpr, HsMatchContext, Pat )
+import TcIface ( tcIfaceGlobal )
+import RdrName ( GlobalRdrEnv )
+import HscTypes ( TyThing(..), TypeEnv, HscEnv,
+ tyThingId, tyThingTyCon, tyThingDataCon, unQualInScope )
+import Bag ( emptyBag, snocBag, Bag )
+import DataCon ( DataCon )
+import TyCon ( TyCon )
+import Id ( mkSysLocal, setIdUnique, Id )
+import Module ( Module )
+import Var ( TyVar, setTyVarUnique )
+import Outputable
+import SrcLoc ( noSrcSpan, SrcSpan )
+import Type ( Type )
+import UniqSupply ( UniqSupply, uniqsFromSupply )
+import Name ( Name, nameOccName )
+import NameEnv
+import OccName ( occNameFS )
+import DynFlags ( DynFlags )
+import ErrUtils ( WarnMsg, mkWarnMsg )
+import Bag ( mapBag )
+
+import DATA_IOREF ( newIORef, readIORef )
+
+infixr 9 `thenDs`
+\end{code}
+
+%************************************************************************
+%* *
+ Data types for the desugarer
+%* *
+%************************************************************************
+
+\begin{code}
+data DsMatchContext
+ = DsMatchContext (HsMatchContext Name) SrcSpan
+ | NoMatchContext
+ deriving ()
+
+data EquationInfo
+ = EqnInfo { eqn_wrap :: DsWrapper, -- Bindings
+ eqn_pats :: [Pat Id], -- The patterns for an eqn
+ eqn_rhs :: MatchResult } -- What to do after match
+
+type DsWrapper = CoreExpr -> CoreExpr
+idWrapper e = e
+
+-- The semantics of (match vs (EqnInfo wrap pats rhs)) is the MatchResult
+-- \fail. wrap (case vs of { pats -> rhs fail })
+-- where vs are not bound by wrap
+
+
+-- A MatchResult is an expression with a hole in it
+data MatchResult
+ = MatchResult
+ CanItFail -- Tells whether the failure expression is used
+ (CoreExpr -> DsM CoreExpr)
+ -- Takes a expression to plug in at the
+ -- failure point(s). The expression should
+ -- be duplicatable!
+
+data CanItFail = CanFail | CantFail
+
+orFail CantFail CantFail = CantFail
+orFail _ _ = CanFail
+\end{code}
+
+
+%************************************************************************
+%* *
+ Monad stuff
+%* *
+%************************************************************************
+
+Now the mondo monad magic (yes, @DsM@ is a silly name)---carry around
+a @UniqueSupply@ and some annotations, which
+presumably include source-file location information:
+\begin{code}
+type DsM result = TcRnIf DsGblEnv DsLclEnv result
+
+-- Compatibility functions
+fixDs = fixM
+thenDs = thenM
+returnDs = returnM
+listDs = sequenceM
+foldlDs = foldlM
+foldrDs = foldrM
+mapAndUnzipDs = mapAndUnzipM
+
+
+type DsWarning = (SrcSpan, SDoc)
+ -- Not quite the same as a WarnMsg, we have an SDoc here
+ -- and we'll do the print_unqual stuff later on to turn it
+ -- into a Doc.
+
+data DsGblEnv = DsGblEnv {
+ ds_mod :: Module, -- For SCC profiling
+ ds_warns :: IORef (Bag DsWarning), -- Warning messages
+ ds_if_env :: (IfGblEnv, IfLclEnv) -- Used for looking up global,
+ -- possibly-imported things
+ }
+
+data DsLclEnv = DsLclEnv {
+ ds_meta :: DsMetaEnv, -- Template Haskell bindings
+ ds_loc :: SrcSpan -- to put in pattern-matching error msgs
+ }
+
+-- Inside [| |] brackets, the desugarer looks
+-- up variables in the DsMetaEnv
+type DsMetaEnv = NameEnv DsMetaVal
+
+data DsMetaVal
+ = Bound Id -- Bound by a pattern inside the [| |].
+ -- Will be dynamically alpha renamed.
+ -- The Id has type THSyntax.Var
+
+ | Splice (HsExpr Id) -- These bindings are introduced by
+ -- the PendingSplices on a HsBracketOut
+
+-- initDs returns the UniqSupply out the end (not just the result)
+
+initDs :: HscEnv
+ -> Module -> GlobalRdrEnv -> TypeEnv
+ -> DsM a
+ -> IO (a, Bag WarnMsg)
+
+initDs hsc_env mod rdr_env type_env thing_inside
+ = do { warn_var <- newIORef emptyBag
+ ; let { if_genv = IfGblEnv { if_rec_types = Just (mod, return type_env) }
+ ; if_lenv = mkIfLclEnv mod (ptext SLIT("GHC error in desugarer lookup in") <+> ppr mod)
+ ; gbl_env = DsGblEnv { ds_mod = mod,
+ ds_if_env = (if_genv, if_lenv),
+ ds_warns = warn_var }
+ ; lcl_env = DsLclEnv { ds_meta = emptyNameEnv,
+ ds_loc = noSrcSpan } }
+
+ ; res <- initTcRnIf 'd' hsc_env gbl_env lcl_env thing_inside
+
+ ; warns <- readIORef warn_var
+ ; return (res, mapBag mk_warn warns)
+ }
+ where
+ print_unqual = unQualInScope rdr_env
+
+ mk_warn :: (SrcSpan,SDoc) -> WarnMsg
+ mk_warn (loc,sdoc) = mkWarnMsg loc print_unqual sdoc
+\end{code}
+
+%************************************************************************
+%* *
+ Operations in the monad
+%* *
+%************************************************************************
+
+And all this mysterious stuff is so we can occasionally reach out and
+grab one or more names. @newLocalDs@ isn't exported---exported
+functions are defined with it. The difference in name-strings makes
+it easier to read debugging output.
+
+\begin{code}
+-- Make a new Id with the same print name, but different type, and new unique
+newUniqueId :: Name -> Type -> DsM Id
+newUniqueId id ty
+ = newUnique `thenDs` \ uniq ->
+ returnDs (mkSysLocal (occNameFS (nameOccName id)) uniq ty)
+
+duplicateLocalDs :: Id -> DsM Id
+duplicateLocalDs old_local
+ = newUnique `thenDs` \ uniq ->
+ returnDs (setIdUnique old_local uniq)
+
+newSysLocalDs, newFailLocalDs :: Type -> DsM Id
+newSysLocalDs ty
+ = newUnique `thenDs` \ uniq ->
+ returnDs (mkSysLocal FSLIT("ds") uniq ty)
+
+newSysLocalsDs tys = mappM newSysLocalDs tys
+
+newFailLocalDs ty
+ = newUnique `thenDs` \ uniq ->
+ returnDs (mkSysLocal FSLIT("fail") uniq ty)
+ -- The UserLocal bit just helps make the code a little clearer
+\end{code}
+
+\begin{code}
+newTyVarsDs :: [TyVar] -> DsM [TyVar]
+newTyVarsDs tyvar_tmpls
+ = newUniqueSupply `thenDs` \ uniqs ->
+ returnDs (zipWith setTyVarUnique tyvar_tmpls (uniqsFromSupply uniqs))
+\end{code}
+
+We can also reach out and either set/grab location information from
+the @SrcSpan@ being carried around.
+
+\begin{code}
+getDOptsDs :: DsM DynFlags
+getDOptsDs = getDOpts
+
+getModuleDs :: DsM Module
+getModuleDs = do { env <- getGblEnv; return (ds_mod env) }
+
+getSrcSpanDs :: DsM SrcSpan
+getSrcSpanDs = do { env <- getLclEnv; return (ds_loc env) }
+
+putSrcSpanDs :: SrcSpan -> DsM a -> DsM a
+putSrcSpanDs new_loc thing_inside = updLclEnv (\ env -> env {ds_loc = new_loc}) thing_inside
+
+dsWarn :: SDoc -> DsM ()
+dsWarn warn = do { env <- getGblEnv
+ ; loc <- getSrcSpanDs
+ ; updMutVar (ds_warns env) (`snocBag` (loc,msg)) }
+ where
+ msg = ptext SLIT("Warning:") <+> warn
+\end{code}
+
+\begin{code}
+dsLookupGlobal :: Name -> DsM TyThing
+-- Very like TcEnv.tcLookupGlobal
+dsLookupGlobal name
+ = do { env <- getGblEnv
+ ; setEnvs (ds_if_env env)
+ (tcIfaceGlobal name) }
+
+dsLookupGlobalId :: Name -> DsM Id
+dsLookupGlobalId name
+ = dsLookupGlobal name `thenDs` \ thing ->
+ returnDs (tyThingId thing)
+
+dsLookupTyCon :: Name -> DsM TyCon
+dsLookupTyCon name
+ = dsLookupGlobal name `thenDs` \ thing ->
+ returnDs (tyThingTyCon thing)
+
+dsLookupDataCon :: Name -> DsM DataCon
+dsLookupDataCon name
+ = dsLookupGlobal name `thenDs` \ thing ->
+ returnDs (tyThingDataCon thing)
+\end{code}
+
+\begin{code}
+dsLookupMetaEnv :: Name -> DsM (Maybe DsMetaVal)
+dsLookupMetaEnv name = do { env <- getLclEnv; return (lookupNameEnv (ds_meta env) name) }
+
+dsExtendMetaEnv :: DsMetaEnv -> DsM a -> DsM a
+dsExtendMetaEnv menv thing_inside
+ = updLclEnv (\env -> env { ds_meta = ds_meta env `plusNameEnv` menv }) thing_inside
+\end{code}
+
+
diff --git a/compiler/deSugar/DsUtils.lhs b/compiler/deSugar/DsUtils.lhs
new file mode 100644
index 0000000000..29e7773bb8
--- /dev/null
+++ b/compiler/deSugar/DsUtils.lhs
@@ -0,0 +1,884 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[DsUtils]{Utilities for desugaring}
+
+This module exports some utility functions of no great interest.
+
+\begin{code}
+module DsUtils (
+ EquationInfo(..),
+ firstPat, shiftEqns,
+
+ mkDsLet, mkDsLets,
+
+ MatchResult(..), CanItFail(..),
+ cantFailMatchResult, alwaysFailMatchResult,
+ extractMatchResult, combineMatchResults,
+ adjustMatchResult, adjustMatchResultDs,
+ mkCoLetMatchResult, mkGuardedMatchResult,
+ matchCanFail,
+ mkCoPrimCaseMatchResult, mkCoAlgCaseMatchResult,
+ wrapBind, wrapBinds,
+
+ mkErrorAppDs, mkNilExpr, mkConsExpr, mkListExpr,
+ mkIntExpr, mkCharExpr,
+ mkStringExpr, mkStringExprFS, mkIntegerExpr,
+
+ mkSelectorBinds, mkTupleExpr, mkTupleSelector,
+ mkTupleType, mkTupleCase, mkBigCoreTup,
+ mkCoreTup, mkCoreTupTy, seqVar,
+
+ dsSyntaxTable, lookupEvidence,
+
+ selectSimpleMatchVarL, selectMatchVars, selectMatchVar
+ ) where
+
+#include "HsVersions.h"
+
+import {-# SOURCE #-} Match ( matchSimply )
+import {-# SOURCE #-} DsExpr( dsExpr )
+
+import HsSyn
+import TcHsSyn ( hsPatType )
+import CoreSyn
+import Constants ( mAX_TUPLE_SIZE )
+import DsMonad
+
+import CoreUtils ( exprType, mkIfThenElse, mkCoerce, bindNonRec )
+import MkId ( iRREFUT_PAT_ERROR_ID, mkReboxingAlt, mkNewTypeBody )
+import Id ( idType, Id, mkWildId, mkTemplateLocals, mkSysLocal )
+import Var ( Var )
+import Name ( Name )
+import Literal ( Literal(..), mkStringLit, inIntRange, tARGET_MAX_INT )
+import TyCon ( isNewTyCon, tyConDataCons )
+import DataCon ( DataCon, dataConSourceArity, dataConTyCon, dataConTag )
+import Type ( mkFunTy, isUnLiftedType, Type, splitTyConApp, mkTyVarTy )
+import TcType ( tcEqType )
+import TysPrim ( intPrimTy )
+import TysWiredIn ( nilDataCon, consDataCon,
+ tupleCon, mkTupleTy,
+ unitDataConId, unitTy,
+ charTy, charDataCon,
+ intTy, intDataCon,
+ isPArrFakeCon )
+import BasicTypes ( Boxity(..) )
+import UniqSet ( mkUniqSet, minusUniqSet, isEmptyUniqSet )
+import UniqSupply ( splitUniqSupply, uniqFromSupply, uniqsFromSupply )
+import PrelNames ( unpackCStringName, unpackCStringUtf8Name,
+ plusIntegerName, timesIntegerName, smallIntegerDataConName,
+ lengthPName, indexPName )
+import Outputable
+import SrcLoc ( Located(..), unLoc )
+import Util ( isSingleton, zipEqual, sortWith )
+import ListSetOps ( assocDefault )
+import FastString
+import Data.Char ( ord )
+
+#ifdef DEBUG
+import Util ( notNull ) -- Used in an assertion
+#endif
+\end{code}
+
+
+
+%************************************************************************
+%* *
+ Rebindable syntax
+%* *
+%************************************************************************
+
+\begin{code}
+dsSyntaxTable :: SyntaxTable Id
+ -> DsM ([CoreBind], -- Auxiliary bindings
+ [(Name,Id)]) -- Maps the standard name to its value
+
+dsSyntaxTable rebound_ids
+ = mapAndUnzipDs mk_bind rebound_ids `thenDs` \ (binds_s, prs) ->
+ return (concat binds_s, prs)
+ where
+ -- The cheapo special case can happen when we
+ -- make an intermediate HsDo when desugaring a RecStmt
+ mk_bind (std_name, HsVar id) = return ([], (std_name, id))
+ mk_bind (std_name, expr)
+ = dsExpr expr `thenDs` \ rhs ->
+ newSysLocalDs (exprType rhs) `thenDs` \ id ->
+ return ([NonRec id rhs], (std_name, id))
+
+lookupEvidence :: [(Name, Id)] -> Name -> Id
+lookupEvidence prs std_name
+ = assocDefault (mk_panic std_name) prs std_name
+ where
+ mk_panic std_name = pprPanic "dsSyntaxTable" (ptext SLIT("Not found:") <+> ppr std_name)
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Building lets}
+%* *
+%************************************************************************
+
+Use case, not let for unlifted types. The simplifier will turn some
+back again.
+
+\begin{code}
+mkDsLet :: CoreBind -> CoreExpr -> CoreExpr
+mkDsLet (NonRec bndr rhs) body
+ | isUnLiftedType (idType bndr)
+ = Case rhs bndr (exprType body) [(DEFAULT,[],body)]
+mkDsLet bind body
+ = Let bind body
+
+mkDsLets :: [CoreBind] -> CoreExpr -> CoreExpr
+mkDsLets binds body = foldr mkDsLet body binds
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{ Selecting match variables}
+%* *
+%************************************************************************
+
+We're about to match against some patterns. We want to make some
+@Ids@ to use as match variables. If a pattern has an @Id@ readily at
+hand, which should indeed be bound to the pattern as a whole, then use it;
+otherwise, make one up.
+
+\begin{code}
+selectSimpleMatchVarL :: LPat Id -> DsM Id
+selectSimpleMatchVarL pat = selectMatchVar (unLoc pat) (hsPatType pat)
+
+-- (selectMatchVars ps tys) chooses variables of type tys
+-- to use for matching ps against. If the pattern is a variable,
+-- we try to use that, to save inventing lots of fresh variables.
+-- But even if it is a variable, its type might not match. Consider
+-- data T a where
+-- T1 :: Int -> T Int
+-- T2 :: a -> T a
+--
+-- f :: T a -> a -> Int
+-- f (T1 i) (x::Int) = x
+-- f (T2 i) (y::a) = 0
+-- Then we must not choose (x::Int) as the matching variable!
+
+selectMatchVars :: [Pat Id] -> [Type] -> DsM [Id]
+selectMatchVars [] [] = return []
+selectMatchVars (p:ps) (ty:tys) = do { v <- selectMatchVar p ty
+ ; vs <- selectMatchVars ps tys
+ ; return (v:vs) }
+
+selectMatchVar (BangPat pat) pat_ty = selectMatchVar (unLoc pat) pat_ty
+selectMatchVar (LazyPat pat) pat_ty = selectMatchVar (unLoc pat) pat_ty
+selectMatchVar (VarPat var) pat_ty = try_for var pat_ty
+selectMatchVar (AsPat var pat) pat_ty = try_for (unLoc var) pat_ty
+selectMatchVar other_pat pat_ty = newSysLocalDs pat_ty -- OK, better make up one...
+
+try_for var pat_ty
+ | idType var `tcEqType` pat_ty = returnDs var
+ | otherwise = newSysLocalDs pat_ty
+\end{code}
+
+
+%************************************************************************
+%* *
+%* type synonym EquationInfo and access functions for its pieces *
+%* *
+%************************************************************************
+\subsection[EquationInfo-synonym]{@EquationInfo@: a useful synonym}
+
+The ``equation info'' used by @match@ is relatively complicated and
+worthy of a type synonym and a few handy functions.
+
+\begin{code}
+firstPat :: EquationInfo -> Pat Id
+firstPat eqn = head (eqn_pats eqn)
+
+shiftEqns :: [EquationInfo] -> [EquationInfo]
+-- Drop the first pattern in each equation
+shiftEqns eqns = [ eqn { eqn_pats = tail (eqn_pats eqn) } | eqn <- eqns ]
+\end{code}
+
+Functions on MatchResults
+
+\begin{code}
+matchCanFail :: MatchResult -> Bool
+matchCanFail (MatchResult CanFail _) = True
+matchCanFail (MatchResult CantFail _) = False
+
+alwaysFailMatchResult :: MatchResult
+alwaysFailMatchResult = MatchResult CanFail (\fail -> returnDs fail)
+
+cantFailMatchResult :: CoreExpr -> MatchResult
+cantFailMatchResult expr = MatchResult CantFail (\ ignore -> returnDs expr)
+
+extractMatchResult :: MatchResult -> CoreExpr -> DsM CoreExpr
+extractMatchResult (MatchResult CantFail match_fn) fail_expr
+ = match_fn (error "It can't fail!")
+
+extractMatchResult (MatchResult CanFail match_fn) fail_expr
+ = mkFailurePair fail_expr `thenDs` \ (fail_bind, if_it_fails) ->
+ match_fn if_it_fails `thenDs` \ body ->
+ returnDs (mkDsLet fail_bind body)
+
+
+combineMatchResults :: MatchResult -> MatchResult -> MatchResult
+combineMatchResults (MatchResult CanFail body_fn1)
+ (MatchResult can_it_fail2 body_fn2)
+ = MatchResult can_it_fail2 body_fn
+ where
+ body_fn fail = body_fn2 fail `thenDs` \ body2 ->
+ mkFailurePair body2 `thenDs` \ (fail_bind, duplicatable_expr) ->
+ body_fn1 duplicatable_expr `thenDs` \ body1 ->
+ returnDs (Let fail_bind body1)
+
+combineMatchResults match_result1@(MatchResult CantFail body_fn1) match_result2
+ = match_result1
+
+adjustMatchResult :: (CoreExpr -> CoreExpr) -> MatchResult -> MatchResult
+adjustMatchResult encl_fn (MatchResult can_it_fail body_fn)
+ = MatchResult can_it_fail (\fail -> body_fn fail `thenDs` \ body ->
+ returnDs (encl_fn body))
+
+adjustMatchResultDs :: (CoreExpr -> DsM CoreExpr) -> MatchResult -> MatchResult
+adjustMatchResultDs encl_fn (MatchResult can_it_fail body_fn)
+ = MatchResult can_it_fail (\fail -> body_fn fail `thenDs` \ body ->
+ encl_fn body)
+
+wrapBinds :: [(Var,Var)] -> CoreExpr -> CoreExpr
+wrapBinds [] e = e
+wrapBinds ((new,old):prs) e = wrapBind new old (wrapBinds prs e)
+
+wrapBind :: Var -> Var -> CoreExpr -> CoreExpr
+wrapBind new old body
+ | new==old = body
+ | isTyVar new = App (Lam new body) (Type (mkTyVarTy old))
+ | otherwise = Let (NonRec new (Var old)) body
+
+seqVar :: Var -> CoreExpr -> CoreExpr
+seqVar var body = Case (Var var) var (exprType body)
+ [(DEFAULT, [], body)]
+
+mkCoLetMatchResult :: CoreBind -> MatchResult -> MatchResult
+mkCoLetMatchResult bind match_result
+ = adjustMatchResult (mkDsLet bind) match_result
+
+mkGuardedMatchResult :: CoreExpr -> MatchResult -> MatchResult
+mkGuardedMatchResult pred_expr (MatchResult can_it_fail body_fn)
+ = MatchResult CanFail (\fail -> body_fn fail `thenDs` \ body ->
+ returnDs (mkIfThenElse pred_expr body fail))
+
+mkCoPrimCaseMatchResult :: Id -- Scrutinee
+ -> Type -- Type of the case
+ -> [(Literal, MatchResult)] -- Alternatives
+ -> MatchResult
+mkCoPrimCaseMatchResult var ty match_alts
+ = MatchResult CanFail mk_case
+ where
+ mk_case fail
+ = mappM (mk_alt fail) sorted_alts `thenDs` \ alts ->
+ returnDs (Case (Var var) var ty ((DEFAULT, [], fail) : alts))
+
+ sorted_alts = sortWith fst match_alts -- Right order for a Case
+ mk_alt fail (lit, MatchResult _ body_fn) = body_fn fail `thenDs` \ body ->
+ returnDs (LitAlt lit, [], body)
+
+
+mkCoAlgCaseMatchResult :: Id -- Scrutinee
+ -> Type -- Type of exp
+ -> [(DataCon, [CoreBndr], MatchResult)] -- Alternatives
+ -> MatchResult
+mkCoAlgCaseMatchResult var ty match_alts
+ | isNewTyCon tycon -- Newtype case; use a let
+ = ASSERT( null (tail match_alts) && null (tail arg_ids1) )
+ mkCoLetMatchResult (NonRec arg_id1 newtype_rhs) match_result1
+
+ | isPArrFakeAlts match_alts -- Sugared parallel array; use a literal case
+ = MatchResult CanFail mk_parrCase
+
+ | otherwise -- Datatype case; use a case
+ = MatchResult fail_flag mk_case
+ where
+ tycon = dataConTyCon con1
+ -- [Interesting: becuase of GADTs, we can't rely on the type of
+ -- the scrutinised Id to be sufficiently refined to have a TyCon in it]
+
+ -- Stuff for newtype
+ (con1, arg_ids1, match_result1) = head match_alts
+ arg_id1 = head arg_ids1
+ newtype_rhs = mkNewTypeBody tycon (idType arg_id1) (Var var)
+
+ -- Stuff for data types
+ data_cons = tyConDataCons tycon
+ match_results = [match_result | (_,_,match_result) <- match_alts]
+
+ fail_flag | exhaustive_case
+ = foldr1 orFail [can_it_fail | MatchResult can_it_fail _ <- match_results]
+ | otherwise
+ = CanFail
+
+ wild_var = mkWildId (idType var)
+ sorted_alts = sortWith get_tag match_alts
+ get_tag (con, _, _) = dataConTag con
+ mk_case fail = mappM (mk_alt fail) sorted_alts `thenDs` \ alts ->
+ returnDs (Case (Var var) wild_var ty (mk_default fail ++ alts))
+
+ mk_alt fail (con, args, MatchResult _ body_fn)
+ = body_fn fail `thenDs` \ body ->
+ newUniqueSupply `thenDs` \ us ->
+ returnDs (mkReboxingAlt (uniqsFromSupply us) con args body)
+
+ mk_default fail | exhaustive_case = []
+ | otherwise = [(DEFAULT, [], fail)]
+
+ un_mentioned_constructors
+ = mkUniqSet data_cons `minusUniqSet` mkUniqSet [ con | (con, _, _) <- match_alts]
+ exhaustive_case = isEmptyUniqSet un_mentioned_constructors
+
+ -- Stuff for parallel arrays
+ --
+ -- * the following is to desugar cases over fake constructors for
+ -- parallel arrays, which are introduced by `tidy1' in the `PArrPat'
+ -- case
+ --
+ -- Concerning `isPArrFakeAlts':
+ --
+ -- * it is *not* sufficient to just check the type of the type
+ -- constructor, as we have to be careful not to confuse the real
+ -- representation of parallel arrays with the fake constructors;
+ -- moreover, a list of alternatives must not mix fake and real
+ -- constructors (this is checked earlier on)
+ --
+ -- FIXME: We actually go through the whole list and make sure that
+ -- either all or none of the constructors are fake parallel
+ -- array constructors. This is to spot equations that mix fake
+ -- constructors with the real representation defined in
+ -- `PrelPArr'. It would be nicer to spot this situation
+ -- earlier and raise a proper error message, but it can really
+ -- only happen in `PrelPArr' anyway.
+ --
+ isPArrFakeAlts [(dcon, _, _)] = isPArrFakeCon dcon
+ isPArrFakeAlts ((dcon, _, _):alts) =
+ case (isPArrFakeCon dcon, isPArrFakeAlts alts) of
+ (True , True ) -> True
+ (False, False) -> False
+ _ ->
+ panic "DsUtils: You may not mix `[:...:]' with `PArr' patterns"
+ --
+ mk_parrCase fail =
+ dsLookupGlobalId lengthPName `thenDs` \lengthP ->
+ unboxAlt `thenDs` \alt ->
+ returnDs (Case (len lengthP) (mkWildId intTy) ty [alt])
+ where
+ elemTy = case splitTyConApp (idType var) of
+ (_, [elemTy]) -> elemTy
+ _ -> panic panicMsg
+ panicMsg = "DsUtils.mkCoAlgCaseMatchResult: not a parallel array?"
+ len lengthP = mkApps (Var lengthP) [Type elemTy, Var var]
+ --
+ unboxAlt =
+ newSysLocalDs intPrimTy `thenDs` \l ->
+ dsLookupGlobalId indexPName `thenDs` \indexP ->
+ mappM (mkAlt indexP) sorted_alts `thenDs` \alts ->
+ returnDs (DataAlt intDataCon, [l], (Case (Var l) wild ty (dft : alts)))
+ where
+ wild = mkWildId intPrimTy
+ dft = (DEFAULT, [], fail)
+ --
+ -- each alternative matches one array length (corresponding to one
+ -- fake array constructor), so the match is on a literal; each
+ -- alternative's body is extended by a local binding for each
+ -- constructor argument, which are bound to array elements starting
+ -- with the first
+ --
+ mkAlt indexP (con, args, MatchResult _ bodyFun) =
+ bodyFun fail `thenDs` \body ->
+ returnDs (LitAlt lit, [], mkDsLets binds body)
+ where
+ lit = MachInt $ toInteger (dataConSourceArity con)
+ binds = [NonRec arg (indexExpr i) | (i, arg) <- zip [1..] args]
+ --
+ indexExpr i = mkApps (Var indexP) [Type elemTy, Var var, mkIntExpr i]
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Desugarer's versions of some Core functions}
+%* *
+%************************************************************************
+
+\begin{code}
+mkErrorAppDs :: Id -- The error function
+ -> Type -- Type to which it should be applied
+ -> String -- The error message string to pass
+ -> DsM CoreExpr
+
+mkErrorAppDs err_id ty msg
+ = getSrcSpanDs `thenDs` \ src_loc ->
+ let
+ full_msg = showSDoc (hcat [ppr src_loc, text "|", text msg])
+ core_msg = Lit (mkStringLit full_msg)
+ -- mkStringLit returns a result of type String#
+ in
+ returnDs (mkApps (Var err_id) [Type ty, core_msg])
+\end{code}
+
+
+*************************************************************
+%* *
+\subsection{Making literals}
+%* *
+%************************************************************************
+
+\begin{code}
+mkCharExpr :: Char -> CoreExpr -- Returns C# c :: Int
+mkIntExpr :: Integer -> CoreExpr -- Returns I# i :: Int
+mkIntegerExpr :: Integer -> DsM CoreExpr -- Result :: Integer
+mkStringExpr :: String -> DsM CoreExpr -- Result :: String
+mkStringExprFS :: FastString -> DsM CoreExpr -- Result :: String
+
+mkIntExpr i = mkConApp intDataCon [mkIntLit i]
+mkCharExpr c = mkConApp charDataCon [mkLit (MachChar c)]
+
+mkIntegerExpr i
+ | inIntRange i -- Small enough, so start from an Int
+ = dsLookupDataCon smallIntegerDataConName `thenDs` \ integer_dc ->
+ returnDs (mkSmallIntegerLit integer_dc i)
+
+-- Special case for integral literals with a large magnitude:
+-- They are transformed into an expression involving only smaller
+-- integral literals. This improves constant folding.
+
+ | otherwise -- Big, so start from a string
+ = dsLookupGlobalId plusIntegerName `thenDs` \ plus_id ->
+ dsLookupGlobalId timesIntegerName `thenDs` \ times_id ->
+ dsLookupDataCon smallIntegerDataConName `thenDs` \ integer_dc ->
+ let
+ lit i = mkSmallIntegerLit integer_dc i
+ plus a b = Var plus_id `App` a `App` b
+ times a b = Var times_id `App` a `App` b
+
+ -- Transform i into (x1 + (x2 + (x3 + (...) * b) * b) * b) with abs xi <= b
+ horner :: Integer -> Integer -> CoreExpr
+ horner b i | abs q <= 1 = if r == 0 || r == i
+ then lit i
+ else lit r `plus` lit (i-r)
+ | r == 0 = horner b q `times` lit b
+ | otherwise = lit r `plus` (horner b q `times` lit b)
+ where
+ (q,r) = i `quotRem` b
+
+ in
+ returnDs (horner tARGET_MAX_INT i)
+
+mkSmallIntegerLit small_integer_data_con i = mkConApp small_integer_data_con [mkIntLit i]
+
+mkStringExpr str = mkStringExprFS (mkFastString str)
+
+mkStringExprFS str
+ | nullFS str
+ = returnDs (mkNilExpr charTy)
+
+ | lengthFS str == 1
+ = let
+ the_char = mkCharExpr (headFS str)
+ in
+ returnDs (mkConsExpr charTy the_char (mkNilExpr charTy))
+
+ | all safeChar chars
+ = dsLookupGlobalId unpackCStringName `thenDs` \ unpack_id ->
+ returnDs (App (Var unpack_id) (Lit (MachStr str)))
+
+ | otherwise
+ = dsLookupGlobalId unpackCStringUtf8Name `thenDs` \ unpack_id ->
+ returnDs (App (Var unpack_id) (Lit (MachStr str)))
+
+ where
+ chars = unpackFS str
+ safeChar c = ord c >= 1 && ord c <= 0x7F
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[mkSelectorBind]{Make a selector bind}
+%* *
+%************************************************************************
+
+This is used in various places to do with lazy patterns.
+For each binder $b$ in the pattern, we create a binding:
+\begin{verbatim}
+ b = case v of pat' -> b'
+\end{verbatim}
+where @pat'@ is @pat@ with each binder @b@ cloned into @b'@.
+
+ToDo: making these bindings should really depend on whether there's
+much work to be done per binding. If the pattern is complex, it
+should be de-mangled once, into a tuple (and then selected from).
+Otherwise the demangling can be in-line in the bindings (as here).
+
+Boring! Boring! One error message per binder. The above ToDo is
+even more helpful. Something very similar happens for pattern-bound
+expressions.
+
+\begin{code}
+mkSelectorBinds :: LPat Id -- The pattern
+ -> CoreExpr -- Expression to which the pattern is bound
+ -> DsM [(Id,CoreExpr)]
+
+mkSelectorBinds (L _ (VarPat v)) val_expr
+ = returnDs [(v, val_expr)]
+
+mkSelectorBinds pat val_expr
+ | isSingleton binders || is_simple_lpat pat
+ = -- Given p = e, where p binds x,y
+ -- we are going to make
+ -- v = p (where v is fresh)
+ -- x = case v of p -> x
+ -- y = case v of p -> x
+
+ -- Make up 'v'
+ -- NB: give it the type of *pattern* p, not the type of the *rhs* e.
+ -- This does not matter after desugaring, but there's a subtle
+ -- issue with implicit parameters. Consider
+ -- (x,y) = ?i
+ -- Then, ?i is given type {?i :: Int}, a PredType, which is opaque
+ -- to the desugarer. (Why opaque? Because newtypes have to be. Why
+ -- does it get that type? So that when we abstract over it we get the
+ -- right top-level type (?i::Int) => ...)
+ --
+ -- So to get the type of 'v', use the pattern not the rhs. Often more
+ -- efficient too.
+ newSysLocalDs (hsPatType pat) `thenDs` \ val_var ->
+
+ -- For the error message we make one error-app, to avoid duplication.
+ -- But we need it at different types... so we use coerce for that
+ mkErrorAppDs iRREFUT_PAT_ERROR_ID
+ unitTy (showSDoc (ppr pat)) `thenDs` \ err_expr ->
+ newSysLocalDs unitTy `thenDs` \ err_var ->
+ mappM (mk_bind val_var err_var) binders `thenDs` \ binds ->
+ returnDs ( (val_var, val_expr) :
+ (err_var, err_expr) :
+ binds )
+
+
+ | otherwise
+ = mkErrorAppDs iRREFUT_PAT_ERROR_ID
+ tuple_ty (showSDoc (ppr pat)) `thenDs` \ error_expr ->
+ matchSimply val_expr PatBindRhs pat local_tuple error_expr `thenDs` \ tuple_expr ->
+ newSysLocalDs tuple_ty `thenDs` \ tuple_var ->
+ let
+ mk_tup_bind binder
+ = (binder, mkTupleSelector binders binder tuple_var (Var tuple_var))
+ in
+ returnDs ( (tuple_var, tuple_expr) : map mk_tup_bind binders )
+ where
+ binders = collectPatBinders pat
+ local_tuple = mkTupleExpr binders
+ tuple_ty = exprType local_tuple
+
+ mk_bind scrut_var err_var bndr_var
+ -- (mk_bind sv err_var) generates
+ -- bv = case sv of { pat -> bv; other -> coerce (type-of-bv) err_var }
+ -- Remember, pat binds bv
+ = matchSimply (Var scrut_var) PatBindRhs pat
+ (Var bndr_var) error_expr `thenDs` \ rhs_expr ->
+ returnDs (bndr_var, rhs_expr)
+ where
+ error_expr = mkCoerce (idType bndr_var) (Var err_var)
+
+ is_simple_lpat p = is_simple_pat (unLoc p)
+
+ is_simple_pat (TuplePat ps Boxed _) = all is_triv_lpat ps
+ is_simple_pat (ConPatOut _ _ _ _ ps _) = all is_triv_lpat (hsConArgs ps)
+ is_simple_pat (VarPat _) = True
+ is_simple_pat (ParPat p) = is_simple_lpat p
+ is_simple_pat other = False
+
+ is_triv_lpat p = is_triv_pat (unLoc p)
+
+ is_triv_pat (VarPat v) = True
+ is_triv_pat (WildPat _) = True
+ is_triv_pat (ParPat p) = is_triv_lpat p
+ is_triv_pat other = False
+\end{code}
+
+
+%************************************************************************
+%* *
+ Tuples
+%* *
+%************************************************************************
+
+@mkTupleExpr@ builds a tuple; the inverse to @mkTupleSelector@.
+
+* If it has only one element, it is the identity function.
+
+* If there are more elements than a big tuple can have, it nests
+ the tuples.
+
+Nesting policy. Better a 2-tuple of 10-tuples (3 objects) than
+a 10-tuple of 2-tuples (11 objects). So we want the leaves to be big.
+
+\begin{code}
+mkTupleExpr :: [Id] -> CoreExpr
+mkTupleExpr ids = mkBigCoreTup (map Var ids)
+
+-- corresponding type
+mkTupleType :: [Id] -> Type
+mkTupleType ids = mkBigTuple mkCoreTupTy (map idType ids)
+
+mkBigCoreTup :: [CoreExpr] -> CoreExpr
+mkBigCoreTup = mkBigTuple mkCoreTup
+
+mkBigTuple :: ([a] -> a) -> [a] -> a
+mkBigTuple small_tuple as = mk_big_tuple (chunkify as)
+ where
+ -- Each sub-list is short enough to fit in a tuple
+ mk_big_tuple [as] = small_tuple as
+ mk_big_tuple as_s = mk_big_tuple (chunkify (map small_tuple as_s))
+
+chunkify :: [a] -> [[a]]
+-- The sub-lists of the result all have length <= mAX_TUPLE_SIZE
+-- But there may be more than mAX_TUPLE_SIZE sub-lists
+chunkify xs
+ | n_xs <= mAX_TUPLE_SIZE = {- pprTrace "Small" (ppr n_xs) -} [xs]
+ | otherwise = {- pprTrace "Big" (ppr n_xs) -} (split xs)
+ where
+ n_xs = length xs
+ split [] = []
+ split xs = take mAX_TUPLE_SIZE xs : split (drop mAX_TUPLE_SIZE xs)
+\end{code}
+
+
+@mkTupleSelector@ builds a selector which scrutises the given
+expression and extracts the one name from the list given.
+If you want the no-shadowing rule to apply, the caller
+is responsible for making sure that none of these names
+are in scope.
+
+If there is just one id in the ``tuple'', then the selector is
+just the identity.
+
+If it's big, it does nesting
+ mkTupleSelector [a,b,c,d] b v e
+ = case e of v {
+ (p,q) -> case p of p {
+ (a,b) -> b }}
+We use 'tpl' vars for the p,q, since shadowing does not matter.
+
+In fact, it's more convenient to generate it innermost first, getting
+
+ case (case e of v
+ (p,q) -> p) of p
+ (a,b) -> b
+
+\begin{code}
+mkTupleSelector :: [Id] -- The tuple args
+ -> Id -- The selected one
+ -> Id -- A variable of the same type as the scrutinee
+ -> CoreExpr -- Scrutinee
+ -> CoreExpr
+
+mkTupleSelector vars the_var scrut_var scrut
+ = mk_tup_sel (chunkify vars) the_var
+ where
+ mk_tup_sel [vars] the_var = mkCoreSel vars the_var scrut_var scrut
+ mk_tup_sel vars_s the_var = mkCoreSel group the_var tpl_v $
+ mk_tup_sel (chunkify tpl_vs) tpl_v
+ where
+ tpl_tys = [mkCoreTupTy (map idType gp) | gp <- vars_s]
+ tpl_vs = mkTemplateLocals tpl_tys
+ [(tpl_v, group)] = [(tpl,gp) | (tpl,gp) <- zipEqual "mkTupleSelector" tpl_vs vars_s,
+ the_var `elem` gp ]
+\end{code}
+
+A generalization of @mkTupleSelector@, allowing the body
+of the case to be an arbitrary expression.
+
+If the tuple is big, it is nested:
+
+ mkTupleCase uniqs [a,b,c,d] body v e
+ = case e of v { (p,q) ->
+ case p of p { (a,b) ->
+ case q of q { (c,d) ->
+ body }}}
+
+To avoid shadowing, we use uniqs to invent new variables p,q.
+
+ToDo: eliminate cases where none of the variables are needed.
+
+\begin{code}
+mkTupleCase
+ :: UniqSupply -- for inventing names of intermediate variables
+ -> [Id] -- the tuple args
+ -> CoreExpr -- body of the case
+ -> Id -- a variable of the same type as the scrutinee
+ -> CoreExpr -- scrutinee
+ -> CoreExpr
+
+mkTupleCase uniqs vars body scrut_var scrut
+ = mk_tuple_case uniqs (chunkify vars) body
+ where
+ mk_tuple_case us [vars] body
+ = mkSmallTupleCase vars body scrut_var scrut
+ mk_tuple_case us vars_s body
+ = let
+ (us', vars', body') = foldr one_tuple_case (us, [], body) vars_s
+ in
+ mk_tuple_case us' (chunkify vars') body'
+ one_tuple_case chunk_vars (us, vs, body)
+ = let
+ (us1, us2) = splitUniqSupply us
+ scrut_var = mkSysLocal FSLIT("ds") (uniqFromSupply us1)
+ (mkCoreTupTy (map idType chunk_vars))
+ body' = mkSmallTupleCase chunk_vars body scrut_var (Var scrut_var)
+ in (us2, scrut_var:vs, body')
+\end{code}
+
+The same, but with a tuple small enough not to need nesting.
+
+\begin{code}
+mkSmallTupleCase
+ :: [Id] -- the tuple args
+ -> CoreExpr -- body of the case
+ -> Id -- a variable of the same type as the scrutinee
+ -> CoreExpr -- scrutinee
+ -> CoreExpr
+
+mkSmallTupleCase [var] body _scrut_var scrut
+ = bindNonRec var scrut body
+mkSmallTupleCase vars body scrut_var scrut
+-- One branch no refinement?
+ = Case scrut scrut_var (exprType body) [(DataAlt (tupleCon Boxed (length vars)), vars, body)]
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[mkFailurePair]{Code for pattern-matching and other failures}
+%* *
+%************************************************************************
+
+Call the constructor Ids when building explicit lists, so that they
+interact well with rules.
+
+\begin{code}
+mkNilExpr :: Type -> CoreExpr
+mkNilExpr ty = mkConApp nilDataCon [Type ty]
+
+mkConsExpr :: Type -> CoreExpr -> CoreExpr -> CoreExpr
+mkConsExpr ty hd tl = mkConApp consDataCon [Type ty, hd, tl]
+
+mkListExpr :: Type -> [CoreExpr] -> CoreExpr
+mkListExpr ty xs = foldr (mkConsExpr ty) (mkNilExpr ty) xs
+
+
+-- The next three functions make tuple types, constructors and selectors,
+-- with the rule that a 1-tuple is represented by the thing itselg
+mkCoreTupTy :: [Type] -> Type
+mkCoreTupTy [ty] = ty
+mkCoreTupTy tys = mkTupleTy Boxed (length tys) tys
+
+mkCoreTup :: [CoreExpr] -> CoreExpr
+-- Builds exactly the specified tuple.
+-- No fancy business for big tuples
+mkCoreTup [] = Var unitDataConId
+mkCoreTup [c] = c
+mkCoreTup cs = mkConApp (tupleCon Boxed (length cs))
+ (map (Type . exprType) cs ++ cs)
+
+mkCoreSel :: [Id] -- The tuple args
+ -> Id -- The selected one
+ -> Id -- A variable of the same type as the scrutinee
+ -> CoreExpr -- Scrutinee
+ -> CoreExpr
+-- mkCoreSel [x,y,z] x v e
+-- ===> case e of v { (x,y,z) -> x
+mkCoreSel [var] should_be_the_same_var scrut_var scrut
+ = ASSERT(var == should_be_the_same_var)
+ scrut
+
+mkCoreSel vars the_var scrut_var scrut
+ = ASSERT( notNull vars )
+ Case scrut scrut_var (idType the_var)
+ [(DataAlt (tupleCon Boxed (length vars)), vars, Var the_var)]
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[mkFailurePair]{Code for pattern-matching and other failures}
+%* *
+%************************************************************************
+
+Generally, we handle pattern matching failure like this: let-bind a
+fail-variable, and use that variable if the thing fails:
+\begin{verbatim}
+ let fail.33 = error "Help"
+ in
+ case x of
+ p1 -> ...
+ p2 -> fail.33
+ p3 -> fail.33
+ p4 -> ...
+\end{verbatim}
+Then
+\begin{itemize}
+\item
+If the case can't fail, then there'll be no mention of @fail.33@, and the
+simplifier will later discard it.
+
+\item
+If it can fail in only one way, then the simplifier will inline it.
+
+\item
+Only if it is used more than once will the let-binding remain.
+\end{itemize}
+
+There's a problem when the result of the case expression is of
+unboxed type. Then the type of @fail.33@ is unboxed too, and
+there is every chance that someone will change the let into a case:
+\begin{verbatim}
+ case error "Help" of
+ fail.33 -> case ....
+\end{verbatim}
+
+which is of course utterly wrong. Rather than drop the condition that
+only boxed types can be let-bound, we just turn the fail into a function
+for the primitive case:
+\begin{verbatim}
+ let fail.33 :: Void -> Int#
+ fail.33 = \_ -> error "Help"
+ in
+ case x of
+ p1 -> ...
+ p2 -> fail.33 void
+ p3 -> fail.33 void
+ p4 -> ...
+\end{verbatim}
+
+Now @fail.33@ is a function, so it can be let-bound.
+
+\begin{code}
+mkFailurePair :: CoreExpr -- Result type of the whole case expression
+ -> DsM (CoreBind, -- Binds the newly-created fail variable
+ -- to either the expression or \ _ -> expression
+ CoreExpr) -- Either the fail variable, or fail variable
+ -- applied to unit tuple
+mkFailurePair expr
+ | isUnLiftedType ty
+ = newFailLocalDs (unitTy `mkFunTy` ty) `thenDs` \ fail_fun_var ->
+ newSysLocalDs unitTy `thenDs` \ fail_fun_arg ->
+ returnDs (NonRec fail_fun_var (Lam fail_fun_arg expr),
+ App (Var fail_fun_var) (Var unitDataConId))
+
+ | otherwise
+ = newFailLocalDs ty `thenDs` \ fail_var ->
+ returnDs (NonRec fail_var expr, Var fail_var)
+ where
+ ty = exprType expr
+\end{code}
+
+
diff --git a/compiler/deSugar/Match.hi-boot-5 b/compiler/deSugar/Match.hi-boot-5
new file mode 100644
index 0000000000..42c200fbff
--- /dev/null
+++ b/compiler/deSugar/Match.hi-boot-5
@@ -0,0 +1,6 @@
+__interface Match 1 0 where
+__export Match match matchExport matchSimply matchSinglePat;
+1 match :: [Var.Id] -> [DsUtils.EquationInfo] -> DsMonad.DsM DsUtils.MatchResult ;
+1 matchExport :: [Var.Id] -> [DsUtils.EquationInfo] -> DsMonad.DsM DsUtils.MatchResult ;
+1 matchSimply :: CoreSyn.CoreExpr -> HsExpr.HsMatchContext Name.Name -> HsPat.LPat Var.Id -> CoreSyn.CoreExpr -> CoreSyn.CoreExpr -> DsMonad.DsM CoreSyn.CoreExpr ;
+1 matchSinglePat :: CoreSyn.CoreExpr -> DsMonad.DsMatchContext -> HsPat.LPat Var.Id -> DsUtils.MatchResult -> DsMonad.DsM DsUtils.MatchResult ;
diff --git a/compiler/deSugar/Match.hi-boot-6 b/compiler/deSugar/Match.hi-boot-6
new file mode 100644
index 0000000000..df806ec644
--- /dev/null
+++ b/compiler/deSugar/Match.hi-boot-6
@@ -0,0 +1,27 @@
+module Match where
+
+match :: [Var.Id]
+ -> TcType.TcType
+ -> [DsMonad.EquationInfo]
+ -> DsMonad.DsM DsMonad.MatchResult
+
+matchWrapper
+ :: HsExpr.HsMatchContext Name.Name
+ -> HsExpr.MatchGroup Var.Id
+ -> DsMonad.DsM ([Var.Id], CoreSyn.CoreExpr)
+
+matchSimply
+ :: CoreSyn.CoreExpr
+ -> HsExpr.HsMatchContext Name.Name
+ -> HsPat.LPat Var.Id
+ -> CoreSyn.CoreExpr
+ -> CoreSyn.CoreExpr
+ -> DsMonad.DsM CoreSyn.CoreExpr
+
+matchSinglePat
+ :: CoreSyn.CoreExpr
+ -> HsExpr.HsMatchContext Name.Name
+ -> HsPat.LPat Var.Id
+ -> TcType.TcType
+ -> DsMonad.MatchResult
+ -> DsMonad.DsM DsMonad.MatchResult
diff --git a/compiler/deSugar/Match.lhs b/compiler/deSugar/Match.lhs
new file mode 100644
index 0000000000..d72d6adf17
--- /dev/null
+++ b/compiler/deSugar/Match.lhs
@@ -0,0 +1,740 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[Main_match]{The @match@ function}
+
+\begin{code}
+module Match ( match, matchEquations, matchWrapper, matchSimply, matchSinglePat ) where
+
+#include "HsVersions.h"
+
+import DynFlags ( DynFlag(..), dopt )
+import HsSyn
+import TcHsSyn ( mkVanillaTuplePat )
+import Check ( check, ExhaustivePat )
+import CoreSyn
+import CoreUtils ( bindNonRec, exprType )
+import DsMonad
+import DsBinds ( dsLHsBinds )
+import DsGRHSs ( dsGRHSs )
+import DsUtils
+import Id ( idName, idType, Id )
+import DataCon ( dataConFieldLabels, dataConInstOrigArgTys, isVanillaDataCon )
+import MatchCon ( matchConFamily )
+import MatchLit ( matchLiterals, matchNPlusKPats, matchNPats, tidyLitPat, tidyNPat )
+import PrelInfo ( pAT_ERROR_ID )
+import TcType ( Type, tcTyConAppArgs )
+import Type ( splitFunTysN, mkTyVarTys )
+import TysWiredIn ( consDataCon, mkListTy, unitTy,
+ tupleCon, parrFakeCon, mkPArrTy )
+import BasicTypes ( Boxity(..) )
+import ListSetOps ( runs )
+import SrcLoc ( noLoc, unLoc, Located(..) )
+import Util ( lengthExceeds, notNull )
+import Name ( Name )
+import Outputable
+\end{code}
+
+This function is a wrapper of @match@, it must be called from all the parts where
+it was called match, but only substitutes the firs call, ....
+if the associated flags are declared, warnings will be issued.
+It can not be called matchWrapper because this name already exists :-(
+
+JJCQ 30-Nov-1997
+
+\begin{code}
+matchCheck :: DsMatchContext
+ -> [Id] -- Vars rep'ing the exprs we're matching with
+ -> Type -- Type of the case expression
+ -> [EquationInfo] -- Info about patterns, etc. (type synonym below)
+ -> DsM MatchResult -- Desugared result!
+
+matchCheck ctx vars ty qs
+ = getDOptsDs `thenDs` \ dflags ->
+ matchCheck_really dflags ctx vars ty qs
+
+matchCheck_really dflags ctx vars ty qs
+ | incomplete && shadow =
+ dsShadowWarn ctx eqns_shadow `thenDs` \ () ->
+ dsIncompleteWarn ctx pats `thenDs` \ () ->
+ match vars ty qs
+ | incomplete =
+ dsIncompleteWarn ctx pats `thenDs` \ () ->
+ match vars ty qs
+ | shadow =
+ dsShadowWarn ctx eqns_shadow `thenDs` \ () ->
+ match vars ty qs
+ | otherwise =
+ match vars ty qs
+ where (pats, eqns_shadow) = check qs
+ incomplete = want_incomplete && (notNull pats)
+ want_incomplete = case ctx of
+ DsMatchContext RecUpd _ ->
+ dopt Opt_WarnIncompletePatternsRecUpd dflags
+ _ ->
+ dopt Opt_WarnIncompletePatterns dflags
+ shadow = dopt Opt_WarnOverlappingPatterns dflags
+ && not (null eqns_shadow)
+\end{code}
+
+This variable shows the maximum number of lines of output generated for warnings.
+It will limit the number of patterns/equations displayed to@ maximum_output@.
+
+(ToDo: add command-line option?)
+
+\begin{code}
+maximum_output = 4
+\end{code}
+
+The next two functions create the warning message.
+
+\begin{code}
+dsShadowWarn :: DsMatchContext -> [EquationInfo] -> DsM ()
+dsShadowWarn ctx@(DsMatchContext kind loc) qs
+ = putSrcSpanDs loc (dsWarn warn)
+ where
+ warn | qs `lengthExceeds` maximum_output
+ = pp_context ctx (ptext SLIT("are overlapped"))
+ (\ f -> vcat (map (ppr_eqn f kind) (take maximum_output qs)) $$
+ ptext SLIT("..."))
+ | otherwise
+ = pp_context ctx (ptext SLIT("are overlapped"))
+ (\ f -> vcat $ map (ppr_eqn f kind) qs)
+
+
+dsIncompleteWarn :: DsMatchContext -> [ExhaustivePat] -> DsM ()
+dsIncompleteWarn ctx@(DsMatchContext kind loc) pats
+ = putSrcSpanDs loc (dsWarn warn)
+ where
+ warn = pp_context ctx (ptext SLIT("are non-exhaustive"))
+ (\f -> hang (ptext SLIT("Patterns not matched:"))
+ 4 ((vcat $ map (ppr_incomplete_pats kind)
+ (take maximum_output pats))
+ $$ dots))
+
+ dots | pats `lengthExceeds` maximum_output = ptext SLIT("...")
+ | otherwise = empty
+
+pp_context (DsMatchContext kind _loc) msg rest_of_msg_fun
+ = vcat [ptext SLIT("Pattern match(es)") <+> msg,
+ sep [ptext SLIT("In") <+> ppr_match <> char ':', nest 4 (rest_of_msg_fun pref)]]
+ where
+ (ppr_match, pref)
+ = case kind of
+ FunRhs fun -> (pprMatchContext kind, \ pp -> ppr fun <+> pp)
+ other -> (pprMatchContext kind, \ pp -> pp)
+
+ppr_pats pats = sep (map ppr pats)
+
+ppr_shadow_pats kind pats
+ = sep [ppr_pats pats, matchSeparator kind, ptext SLIT("...")]
+
+ppr_incomplete_pats kind (pats,[]) = ppr_pats pats
+ppr_incomplete_pats kind (pats,constraints) =
+ sep [ppr_pats pats, ptext SLIT("with"),
+ sep (map ppr_constraint constraints)]
+
+
+ppr_constraint (var,pats) = sep [ppr var, ptext SLIT("`notElem`"), ppr pats]
+
+ppr_eqn prefixF kind eqn = prefixF (ppr_shadow_pats kind (eqn_pats eqn))
+\end{code}
+
+
+The function @match@ is basically the same as in the Wadler chapter,
+except it is monadised, to carry around the name supply, info about
+annotations, etc.
+
+Notes on @match@'s arguments, assuming $m$ equations and $n$ patterns:
+\begin{enumerate}
+\item
+A list of $n$ variable names, those variables presumably bound to the
+$n$ expressions being matched against the $n$ patterns. Using the
+list of $n$ expressions as the first argument showed no benefit and
+some inelegance.
+
+\item
+The second argument, a list giving the ``equation info'' for each of
+the $m$ equations:
+\begin{itemize}
+\item
+the $n$ patterns for that equation, and
+\item
+a list of Core bindings [@(Id, CoreExpr)@ pairs] to be ``stuck on
+the front'' of the matching code, as in:
+\begin{verbatim}
+let <binds>
+in <matching-code>
+\end{verbatim}
+\item
+and finally: (ToDo: fill in)
+
+The right way to think about the ``after-match function'' is that it
+is an embryonic @CoreExpr@ with a ``hole'' at the end for the
+final ``else expression''.
+\end{itemize}
+
+There is a type synonym, @EquationInfo@, defined in module @DsUtils@.
+
+An experiment with re-ordering this information about equations (in
+particular, having the patterns available in column-major order)
+showed no benefit.
+
+\item
+A default expression---what to evaluate if the overall pattern-match
+fails. This expression will (almost?) always be
+a measly expression @Var@, unless we know it will only be used once
+(as we do in @glue_success_exprs@).
+
+Leaving out this third argument to @match@ (and slamming in lots of
+@Var "fail"@s) is a positively {\em bad} idea, because it makes it
+impossible to share the default expressions. (Also, it stands no
+chance of working in our post-upheaval world of @Locals@.)
+\end{enumerate}
+So, the full type signature:
+\begin{code}
+match :: [Id] -- Variables rep'ing the exprs we're matching with
+ -> Type -- Type of the case expression
+ -> [EquationInfo] -- Info about patterns, etc. (type synonym below)
+ -> DsM MatchResult -- Desugared result!
+\end{code}
+
+Note: @match@ is often called via @matchWrapper@ (end of this module),
+a function that does much of the house-keeping that goes with a call
+to @match@.
+
+It is also worth mentioning the {\em typical} way a block of equations
+is desugared with @match@. At each stage, it is the first column of
+patterns that is examined. The steps carried out are roughly:
+\begin{enumerate}
+\item
+Tidy the patterns in column~1 with @tidyEqnInfo@ (this may add
+bindings to the second component of the equation-info):
+\begin{itemize}
+\item
+Remove the `as' patterns from column~1.
+\item
+Make all constructor patterns in column~1 into @ConPats@, notably
+@ListPats@ and @TuplePats@.
+\item
+Handle any irrefutable (or ``twiddle'') @LazyPats@.
+\end{itemize}
+\item
+Now {\em unmix} the equations into {\em blocks} [w/ local function
+@unmix_eqns@], in which the equations in a block all have variable
+patterns in column~1, or they all have constructor patterns in ...
+(see ``the mixture rule'' in SLPJ).
+\item
+Call @matchEqnBlock@ on each block of equations; it will do the
+appropriate thing for each kind of column-1 pattern, usually ending up
+in a recursive call to @match@.
+\end{enumerate}
+
+%************************************************************************
+%* *
+%* match: empty rule *
+%* *
+%************************************************************************
+\subsection[Match-empty-rule]{The ``empty rule''}
+
+We are a little more paranoid about the ``empty rule'' (SLPJ, p.~87)
+than the Wadler-chapter code for @match@ (p.~93, first @match@ clause).
+And gluing the ``success expressions'' together isn't quite so pretty.
+
+\begin{code}
+match [] ty eqns_info
+ = ASSERT( not (null eqns_info) )
+ returnDs (foldr1 combineMatchResults match_results)
+ where
+ match_results = [ ASSERT( null (eqn_pats eqn) )
+ adjustMatchResult (eqn_wrap eqn) (eqn_rhs eqn)
+ | eqn <- eqns_info ]
+\end{code}
+
+
+%************************************************************************
+%* *
+%* match: non-empty rule *
+%* *
+%************************************************************************
+\subsection[Match-nonempty]{@match@ when non-empty: unmixing}
+
+This (more interesting) clause of @match@ uses @tidy_and_unmix_eqns@
+(a)~to get `as'- and `twiddle'-patterns out of the way (tidying), and
+(b)~to do ``the mixture rule'' (SLPJ, p.~88) [which really {\em
+un}mixes the equations], producing a list of equation-info
+blocks, each block having as its first column of patterns either all
+constructors, or all variables (or similar beasts), etc.
+
+@match_unmixed_eqn_blks@ simply takes the place of the @foldr@ in the
+Wadler-chapter @match@ (p.~93, last clause), and @match_unmixed_blk@
+corresponds roughly to @matchVarCon@.
+
+\begin{code}
+match vars@(v:_) ty eqns_info
+ = do { tidy_eqns <- mappM (tidyEqnInfo v) eqns_info
+ ; let eqns_blks = runs same_family tidy_eqns
+ ; match_results <- mappM match_block eqns_blks
+ ; ASSERT( not (null match_results) )
+ return (foldr1 combineMatchResults match_results) }
+ where
+ same_family eqn1 eqn2
+ = samePatFamily (firstPat eqn1) (firstPat eqn2)
+
+ match_block eqns
+ = case firstPat (head eqns) of
+ WildPat {} -> matchVariables vars ty eqns
+ ConPatOut {} -> matchConFamily vars ty eqns
+ NPlusKPat {} -> matchNPlusKPats vars ty eqns
+ NPat {} -> matchNPats vars ty eqns
+ LitPat {} -> matchLiterals vars ty eqns
+
+-- After tidying, there are only five kinds of patterns
+samePatFamily (WildPat {}) (WildPat {}) = True
+samePatFamily (ConPatOut {}) (ConPatOut {}) = True
+samePatFamily (NPlusKPat {}) (NPlusKPat {}) = True
+samePatFamily (NPat {}) (NPat {}) = True
+samePatFamily (LitPat {}) (LitPat {}) = True
+samePatFamily _ _ = False
+
+matchVariables :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult
+-- Real true variables, just like in matchVar, SLPJ p 94
+-- No binding to do: they'll all be wildcards by now (done in tidy)
+matchVariables (var:vars) ty eqns = match vars ty (shiftEqns eqns)
+\end{code}
+
+
+\end{code}
+
+Tidy up the leftmost pattern in an @EquationInfo@, given the variable @v@
+which will be scrutinised. This means:
+\begin{itemize}
+\item
+Replace variable patterns @x@ (@x /= v@) with the pattern @_@,
+together with the binding @x = v@.
+\item
+Replace the `as' pattern @x@@p@ with the pattern p and a binding @x = v@.
+\item
+Removing lazy (irrefutable) patterns (you don't want to know...).
+\item
+Converting explicit tuple-, list-, and parallel-array-pats into ordinary
+@ConPats@.
+\item
+Convert the literal pat "" to [].
+\end{itemize}
+
+The result of this tidying is that the column of patterns will include
+{\em only}:
+\begin{description}
+\item[@WildPats@:]
+The @VarPat@ information isn't needed any more after this.
+
+\item[@ConPats@:]
+@ListPats@, @TuplePats@, etc., are all converted into @ConPats@.
+
+\item[@LitPats@ and @NPats@:]
+@LitPats@/@NPats@ of ``known friendly types'' (Int, Char,
+Float, Double, at least) are converted to unboxed form; e.g.,
+\tr{(NPat (HsInt i) _ _)} is converted to:
+\begin{verbatim}
+(ConPat I# _ _ [LitPat (HsIntPrim i)])
+\end{verbatim}
+\end{description}
+
+\begin{code}
+tidyEqnInfo :: Id -> EquationInfo -> DsM EquationInfo
+ -- DsM'd because of internal call to dsLHsBinds
+ -- and mkSelectorBinds.
+ -- "tidy1" does the interesting stuff, looking at
+ -- one pattern and fiddling the list of bindings.
+ --
+ -- POST CONDITION: head pattern in the EqnInfo is
+ -- WildPat
+ -- ConPat
+ -- NPat
+ -- LitPat
+ -- NPlusKPat
+ -- but no other
+
+tidyEqnInfo v eqn@(EqnInfo { eqn_wrap = wrap, eqn_pats = pat : pats })
+ = tidy1 v wrap pat `thenDs` \ (wrap', pat') ->
+ returnDs (eqn { eqn_wrap = wrap', eqn_pats = pat' : pats })
+
+tidy1 :: Id -- The Id being scrutinised
+ -> DsWrapper -- Previous wrapping bindings
+ -> Pat Id -- The pattern against which it is to be matched
+ -> DsM (DsWrapper, -- Extra bindings around what to do afterwards
+ Pat Id) -- Equivalent pattern
+
+-- The extra bindings etc are all wrapped around the RHS of the match
+-- so they are only available when matching is complete. But that's ok
+-- becuase, for example, in the pattern x@(...), the x can only be
+-- used in the RHS, not in the nested pattern, nor subsquent patterns
+--
+-- However this does have an awkward consequence. The bindings in
+-- a VarPatOut get wrapped around the result in right to left order,
+-- rather than left to right. This only matters if one set of
+-- bindings can mention things used in another, and that can happen
+-- if we allow equality dictionary bindings of form d1=d2.
+-- bindIInstsOfLocalFuns is now careful not to do this, but it's a wart.
+-- (Without this care in bindInstsOfLocalFuns, compiling
+-- Data.Generics.Schemes.hs fails in function everywhereBut.)
+
+-------------------------------------------------------
+-- (pat', mr') = tidy1 v pat mr
+-- tidies the *outer level only* of pat, giving pat'
+-- It eliminates many pattern forms (as-patterns, variable patterns,
+-- list patterns, etc) yielding one of:
+-- WildPat
+-- ConPatOut
+-- LitPat
+-- NPat
+-- NPlusKPat
+
+tidy1 v wrap (ParPat pat) = tidy1 v wrap (unLoc pat)
+tidy1 v wrap (SigPatOut pat _) = tidy1 v wrap (unLoc pat)
+tidy1 v wrap (WildPat ty) = returnDs (wrap, WildPat ty)
+
+ -- case v of { x -> mr[] }
+ -- = case v of { _ -> let x=v in mr[] }
+tidy1 v wrap (VarPat var)
+ = returnDs (wrap . wrapBind var v, WildPat (idType var))
+
+tidy1 v wrap (VarPatOut var binds)
+ = do { prs <- dsLHsBinds binds
+ ; return (wrap . wrapBind var v . mkDsLet (Rec prs),
+ WildPat (idType var)) }
+
+ -- case v of { x@p -> mr[] }
+ -- = case v of { p -> let x=v in mr[] }
+tidy1 v wrap (AsPat (L _ var) pat)
+ = tidy1 v (wrap . wrapBind var v) (unLoc pat)
+
+tidy1 v wrap (BangPat pat)
+ = tidy1 v (wrap . seqVar v) (unLoc pat)
+
+{- now, here we handle lazy patterns:
+ tidy1 v ~p bs = (v, v1 = case v of p -> v1 :
+ v2 = case v of p -> v2 : ... : bs )
+
+ where the v_i's are the binders in the pattern.
+
+ ToDo: in "v_i = ... -> v_i", are the v_i's really the same thing?
+
+ The case expr for v_i is just: match [v] [(p, [], \ x -> Var v_i)] any_expr
+-}
+
+tidy1 v wrap (LazyPat pat)
+ = do { v' <- newSysLocalDs (idType v)
+ ; sel_prs <- mkSelectorBinds pat (Var v)
+ ; let sel_binds = [NonRec b rhs | (b,rhs) <- sel_prs]
+ ; returnDs (wrap . wrapBind v' v . mkDsLets sel_binds,
+ WildPat (idType v)) }
+
+-- re-express <con-something> as (ConPat ...) [directly]
+
+tidy1 v wrap (ConPatOut (L loc con) ex_tvs dicts binds ps pat_ty)
+ = returnDs (wrap, ConPatOut (L loc con) ex_tvs dicts binds tidy_ps pat_ty)
+ where
+ tidy_ps = PrefixCon (tidy_con con ex_tvs pat_ty ps)
+
+tidy1 v wrap (ListPat pats ty)
+ = returnDs (wrap, unLoc list_ConPat)
+ where
+ list_ty = mkListTy ty
+ list_ConPat = foldr (\ x y -> mkPrefixConPat consDataCon [x, y] list_ty)
+ (mkNilPat list_ty)
+ pats
+
+-- Introduce fake parallel array constructors to be able to handle parallel
+-- arrays with the existing machinery for constructor pattern
+tidy1 v wrap (PArrPat pats ty)
+ = returnDs (wrap, unLoc parrConPat)
+ where
+ arity = length pats
+ parrConPat = mkPrefixConPat (parrFakeCon arity) pats (mkPArrTy ty)
+
+tidy1 v wrap (TuplePat pats boxity ty)
+ = returnDs (wrap, unLoc tuple_ConPat)
+ where
+ arity = length pats
+ tuple_ConPat = mkPrefixConPat (tupleCon boxity arity) pats ty
+
+tidy1 v wrap (DictPat dicts methods)
+ = case num_of_d_and_ms of
+ 0 -> tidy1 v wrap (TuplePat [] Boxed unitTy)
+ 1 -> tidy1 v wrap (unLoc (head dict_and_method_pats))
+ _ -> tidy1 v wrap (mkVanillaTuplePat dict_and_method_pats Boxed)
+ where
+ num_of_d_and_ms = length dicts + length methods
+ dict_and_method_pats = map nlVarPat (dicts ++ methods)
+
+-- LitPats: we *might* be able to replace these w/ a simpler form
+tidy1 v wrap pat@(LitPat lit)
+ = returnDs (wrap, unLoc (tidyLitPat lit (noLoc pat)))
+
+-- NPats: we *might* be able to replace these w/ a simpler form
+tidy1 v wrap pat@(NPat lit mb_neg _ lit_ty)
+ = returnDs (wrap, unLoc (tidyNPat lit mb_neg lit_ty (noLoc pat)))
+
+-- and everything else goes through unchanged...
+
+tidy1 v wrap non_interesting_pat
+ = returnDs (wrap, non_interesting_pat)
+
+
+tidy_con data_con ex_tvs pat_ty (PrefixCon ps) = ps
+tidy_con data_con ex_tvs pat_ty (InfixCon p1 p2) = [p1,p2]
+tidy_con data_con ex_tvs pat_ty (RecCon rpats)
+ | null rpats
+ = -- Special case for C {}, which can be used for
+ -- a constructor that isn't declared to have
+ -- fields at all
+ map (noLoc . WildPat) con_arg_tys'
+
+ | otherwise
+ = map mk_pat tagged_arg_tys
+ where
+ -- Boring stuff to find the arg-tys of the constructor
+
+ inst_tys | isVanillaDataCon data_con = tcTyConAppArgs pat_ty -- Newtypes must be opaque
+ | otherwise = mkTyVarTys ex_tvs
+
+ con_arg_tys' = dataConInstOrigArgTys data_con inst_tys
+ tagged_arg_tys = con_arg_tys' `zip` dataConFieldLabels data_con
+
+ -- mk_pat picks a WildPat of the appropriate type for absent fields,
+ -- and the specified pattern for present fields
+ mk_pat (arg_ty, lbl) =
+ case [ pat | (sel_id,pat) <- rpats, idName (unLoc sel_id) == lbl] of
+ (pat:pats) -> ASSERT( null pats ) pat
+ [] -> noLoc (WildPat arg_ty)
+\end{code}
+
+\noindent
+{\bf Previous @matchTwiddled@ stuff:}
+
+Now we get to the only interesting part; note: there are choices for
+translation [from Simon's notes]; translation~1:
+\begin{verbatim}
+deTwiddle [s,t] e
+\end{verbatim}
+returns
+\begin{verbatim}
+[ w = e,
+ s = case w of [s,t] -> s
+ t = case w of [s,t] -> t
+]
+\end{verbatim}
+
+Here \tr{w} is a fresh variable, and the \tr{w}-binding prevents multiple
+evaluation of \tr{e}. An alternative translation (No.~2):
+\begin{verbatim}
+[ w = case e of [s,t] -> (s,t)
+ s = case w of (s,t) -> s
+ t = case w of (s,t) -> t
+]
+\end{verbatim}
+
+%************************************************************************
+%* *
+\subsubsection[improved-unmixing]{UNIMPLEMENTED idea for improved unmixing}
+%* *
+%************************************************************************
+
+We might be able to optimise unmixing when confronted by
+only-one-constructor-possible, of which tuples are the most notable
+examples. Consider:
+\begin{verbatim}
+f (a,b,c) ... = ...
+f d ... (e:f) = ...
+f (g,h,i) ... = ...
+f j ... = ...
+\end{verbatim}
+This definition would normally be unmixed into four equation blocks,
+one per equation. But it could be unmixed into just one equation
+block, because if the one equation matches (on the first column),
+the others certainly will.
+
+You have to be careful, though; the example
+\begin{verbatim}
+f j ... = ...
+-------------------
+f (a,b,c) ... = ...
+f d ... (e:f) = ...
+f (g,h,i) ... = ...
+\end{verbatim}
+{\em must} be broken into two blocks at the line shown; otherwise, you
+are forcing unnecessary evaluation. In any case, the top-left pattern
+always gives the cue. You could then unmix blocks into groups of...
+\begin{description}
+\item[all variables:]
+As it is now.
+\item[constructors or variables (mixed):]
+Need to make sure the right names get bound for the variable patterns.
+\item[literals or variables (mixed):]
+Presumably just a variant on the constructor case (as it is now).
+\end{description}
+
+%************************************************************************
+%* *
+%* matchWrapper: a convenient way to call @match@ *
+%* *
+%************************************************************************
+\subsection[matchWrapper]{@matchWrapper@: a convenient interface to @match@}
+
+Calls to @match@ often involve similar (non-trivial) work; that work
+is collected here, in @matchWrapper@. This function takes as
+arguments:
+\begin{itemize}
+\item
+Typchecked @Matches@ (of a function definition, or a case or lambda
+expression)---the main input;
+\item
+An error message to be inserted into any (runtime) pattern-matching
+failure messages.
+\end{itemize}
+
+As results, @matchWrapper@ produces:
+\begin{itemize}
+\item
+A list of variables (@Locals@) that the caller must ``promise'' to
+bind to appropriate values; and
+\item
+a @CoreExpr@, the desugared output (main result).
+\end{itemize}
+
+The main actions of @matchWrapper@ include:
+\begin{enumerate}
+\item
+Flatten the @[TypecheckedMatch]@ into a suitable list of
+@EquationInfo@s.
+\item
+Create as many new variables as there are patterns in a pattern-list
+(in any one of the @EquationInfo@s).
+\item
+Create a suitable ``if it fails'' expression---a call to @error@ using
+the error-string input; the {\em type} of this fail value can be found
+by examining one of the RHS expressions in one of the @EquationInfo@s.
+\item
+Call @match@ with all of this information!
+\end{enumerate}
+
+\begin{code}
+matchWrapper :: HsMatchContext Name -- For shadowing warning messages
+ -> MatchGroup Id -- Matches being desugared
+ -> DsM ([Id], CoreExpr) -- Results
+\end{code}
+
+ There is one small problem with the Lambda Patterns, when somebody
+ writes something similar to:
+\begin{verbatim}
+ (\ (x:xs) -> ...)
+\end{verbatim}
+ he/she don't want a warning about incomplete patterns, that is done with
+ the flag @opt_WarnSimplePatterns@.
+ This problem also appears in the:
+\begin{itemize}
+\item @do@ patterns, but if the @do@ can fail
+ it creates another equation if the match can fail
+ (see @DsExpr.doDo@ function)
+\item @let@ patterns, are treated by @matchSimply@
+ List Comprension Patterns, are treated by @matchSimply@ also
+\end{itemize}
+
+We can't call @matchSimply@ with Lambda patterns,
+due to the fact that lambda patterns can have more than
+one pattern, and match simply only accepts one pattern.
+
+JJQC 30-Nov-1997
+
+\begin{code}
+matchWrapper ctxt (MatchGroup matches match_ty)
+ = do { eqns_info <- mapM mk_eqn_info matches
+ ; new_vars <- selectMatchVars arg_pats pat_tys
+ ; result_expr <- matchEquations ctxt new_vars eqns_info rhs_ty
+ ; return (new_vars, result_expr) }
+ where
+ arg_pats = map unLoc (hsLMatchPats (head matches))
+ n_pats = length arg_pats
+ (pat_tys, rhs_ty) = splitFunTysN n_pats match_ty
+
+ mk_eqn_info (L _ (Match pats _ grhss))
+ = do { let upats = map unLoc pats
+ ; match_result <- dsGRHSs ctxt upats grhss rhs_ty
+ ; return (EqnInfo { eqn_wrap = idWrapper,
+ eqn_pats = upats,
+ eqn_rhs = match_result}) }
+
+
+matchEquations :: HsMatchContext Name
+ -> [Id] -> [EquationInfo] -> Type
+ -> DsM CoreExpr
+matchEquations ctxt vars eqns_info rhs_ty
+ = do { dflags <- getDOptsDs
+ ; locn <- getSrcSpanDs
+ ; let ds_ctxt = DsMatchContext ctxt locn
+ error_string = matchContextErrString ctxt
+
+ ; match_result <- match_fun dflags ds_ctxt vars rhs_ty eqns_info
+
+ ; fail_expr <- mkErrorAppDs pAT_ERROR_ID rhs_ty error_string
+ ; extractMatchResult match_result fail_expr }
+ where
+ match_fun dflags ds_ctxt
+ = case ctxt of
+ LambdaExpr | dopt Opt_WarnSimplePatterns dflags -> matchCheck ds_ctxt
+ | otherwise -> match
+ _ -> matchCheck ds_ctxt
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[matchSimply]{@matchSimply@: match a single expression against a single pattern}
+%* *
+%************************************************************************
+
+@mkSimpleMatch@ is a wrapper for @match@ which deals with the
+situation where we want to match a single expression against a single
+pattern. It returns an expression.
+
+\begin{code}
+matchSimply :: CoreExpr -- Scrutinee
+ -> HsMatchContext Name -- Match kind
+ -> LPat Id -- Pattern it should match
+ -> CoreExpr -- Return this if it matches
+ -> CoreExpr -- Return this if it doesn't
+ -> DsM CoreExpr
+
+matchSimply scrut hs_ctx pat result_expr fail_expr
+ = let
+ match_result = cantFailMatchResult result_expr
+ rhs_ty = exprType fail_expr
+ -- Use exprType of fail_expr, because won't refine in the case of failure!
+ in
+ matchSinglePat scrut hs_ctx pat rhs_ty match_result `thenDs` \ match_result' ->
+ extractMatchResult match_result' fail_expr
+
+
+matchSinglePat :: CoreExpr -> HsMatchContext Name -> LPat Id
+ -> Type -> MatchResult -> DsM MatchResult
+matchSinglePat (Var var) hs_ctx (L _ pat) ty match_result
+ = getDOptsDs `thenDs` \ dflags ->
+ getSrcSpanDs `thenDs` \ locn ->
+ let
+ match_fn dflags
+ | dopt Opt_WarnSimplePatterns dflags = matchCheck ds_ctx
+ | otherwise = match
+ where
+ ds_ctx = DsMatchContext hs_ctx locn
+ in
+ match_fn dflags [var] ty [EqnInfo { eqn_wrap = idWrapper,
+ eqn_pats = [pat],
+ eqn_rhs = match_result }]
+
+matchSinglePat scrut hs_ctx pat ty match_result
+ = selectSimpleMatchVarL pat `thenDs` \ var ->
+ matchSinglePat (Var var) hs_ctx pat ty match_result `thenDs` \ match_result' ->
+ returnDs (adjustMatchResult (bindNonRec var scrut) match_result')
+\end{code}
+
diff --git a/compiler/deSugar/Match.lhs-boot b/compiler/deSugar/Match.lhs-boot
new file mode 100644
index 0000000000..5f99f5cc1a
--- /dev/null
+++ b/compiler/deSugar/Match.lhs-boot
@@ -0,0 +1,35 @@
+\begin{code}
+module Match where
+import Var ( Id )
+import TcType ( TcType )
+import DsMonad ( DsM, EquationInfo, MatchResult )
+import CoreSyn ( CoreExpr )
+import HsSyn ( LPat, HsMatchContext, MatchGroup )
+import Name ( Name )
+
+match :: [Id]
+ -> TcType
+ -> [EquationInfo]
+ -> DsM MatchResult
+
+matchWrapper
+ :: HsMatchContext Name
+ -> MatchGroup Id
+ -> DsM ([Id], CoreExpr)
+
+matchSimply
+ :: CoreExpr
+ -> HsMatchContext Name
+ -> LPat Id
+ -> CoreExpr
+ -> CoreExpr
+ -> DsM CoreExpr
+
+matchSinglePat
+ :: CoreExpr
+ -> HsMatchContext Name
+ -> LPat Id
+ -> TcType
+ -> MatchResult
+ -> DsM MatchResult
+\end{code}
diff --git a/compiler/deSugar/MatchCon.lhs b/compiler/deSugar/MatchCon.lhs
new file mode 100644
index 0000000000..6ff502a8ae
--- /dev/null
+++ b/compiler/deSugar/MatchCon.lhs
@@ -0,0 +1,174 @@
+
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[MatchCon]{Pattern-matching constructors}
+
+\begin{code}
+module MatchCon ( matchConFamily ) where
+
+#include "HsVersions.h"
+
+import Id( idType )
+
+import {-# SOURCE #-} Match ( match )
+
+import HsSyn ( Pat(..), HsConDetails(..) )
+import DsBinds ( dsLHsBinds )
+import DataCon ( isVanillaDataCon, dataConInstOrigArgTys )
+import TcType ( tcTyConAppArgs )
+import Type ( mkTyVarTys )
+import CoreSyn
+import DsMonad
+import DsUtils
+
+import Id ( Id )
+import Type ( Type )
+import ListSetOps ( equivClassesByUniq )
+import SrcLoc ( unLoc, Located(..) )
+import Unique ( Uniquable(..) )
+import Outputable
+\end{code}
+
+We are confronted with the first column of patterns in a set of
+equations, all beginning with constructors from one ``family'' (e.g.,
+@[]@ and @:@ make up the @List@ ``family''). We want to generate the
+alternatives for a @Case@ expression. There are several choices:
+\begin{enumerate}
+\item
+Generate an alternative for every constructor in the family, whether
+they are used in this set of equations or not; this is what the Wadler
+chapter does.
+\begin{description}
+\item[Advantages:]
+(a)~Simple. (b)~It may also be that large sparsely-used constructor
+families are mainly handled by the code for literals.
+\item[Disadvantages:]
+(a)~Not practical for large sparsely-used constructor families, e.g.,
+the ASCII character set. (b)~Have to look up a list of what
+constructors make up the whole family.
+\end{description}
+
+\item
+Generate an alternative for each constructor used, then add a default
+alternative in case some constructors in the family weren't used.
+\begin{description}
+\item[Advantages:]
+(a)~Alternatives aren't generated for unused constructors. (b)~The
+STG is quite happy with defaults. (c)~No lookup in an environment needed.
+\item[Disadvantages:]
+(a)~A spurious default alternative may be generated.
+\end{description}
+
+\item
+``Do it right:'' generate an alternative for each constructor used,
+and add a default alternative if all constructors in the family
+weren't used.
+\begin{description}
+\item[Advantages:]
+(a)~You will get cases with only one alternative (and no default),
+which should be amenable to optimisation. Tuples are a common example.
+\item[Disadvantages:]
+(b)~Have to look up constructor families in TDE (as above).
+\end{description}
+\end{enumerate}
+
+We are implementing the ``do-it-right'' option for now. The arguments
+to @matchConFamily@ are the same as to @match@; the extra @Int@
+returned is the number of constructors in the family.
+
+The function @matchConFamily@ is concerned with this
+have-we-used-all-the-constructors? question; the local function
+@match_cons_used@ does all the real work.
+\begin{code}
+matchConFamily :: [Id]
+ -> Type
+ -> [EquationInfo]
+ -> DsM MatchResult
+matchConFamily (var:vars) ty eqns_info
+ = let
+ -- Sort into equivalence classes by the unique on the constructor
+ -- All the EqnInfos should start with a ConPat
+ groups = equivClassesByUniq get_uniq eqns_info
+ get_uniq (EqnInfo { eqn_pats = ConPatOut (L _ data_con) _ _ _ _ _ : _}) = getUnique data_con
+
+ -- Get the wrapper from the head of each group. We're going to
+ -- use it as the pattern in this case expression, so we need to
+ -- ensure that any type variables it mentions in the pattern are
+ -- in scope. So we put its wrappers outside the case, and
+ -- zap the wrapper for it.
+ wraps :: [CoreExpr -> CoreExpr]
+ wraps = map (eqn_wrap . head) groups
+
+ groups' = [ eqn { eqn_wrap = idWrapper } : eqns | eqn:eqns <- groups ]
+ in
+ -- Now make a case alternative out of each group
+ mappM (match_con vars ty) groups' `thenDs` \ alts ->
+ returnDs (adjustMatchResult (foldr (.) idWrapper wraps) $
+ mkCoAlgCaseMatchResult var ty alts)
+\end{code}
+
+And here is the local function that does all the work. It is
+more-or-less the @matchCon@/@matchClause@ functions on page~94 in
+Wadler's chapter in SLPJ. The function @shift_con_pats@ does what the
+list comprehension in @matchClause@ (SLPJ, p.~94) does, except things
+are trickier in real life. Works for @ConPats@, and we want it to
+fail catastrophically for anything else (which a list comprehension
+wouldn't). Cf.~@shift_lit_pats@ in @MatchLits@.
+
+\begin{code}
+match_con vars ty eqns
+ = do { -- Make new vars for the con arguments; avoid new locals where possible
+ arg_vars <- selectMatchVars (map unLoc arg_pats1) arg_tys
+ ; eqns' <- mapM shift eqns
+ ; match_result <- match (arg_vars ++ vars) ty eqns'
+ ; return (con, tvs1 ++ dicts1 ++ arg_vars, match_result) }
+ where
+ ConPatOut (L _ con) tvs1 dicts1 _ (PrefixCon arg_pats1) pat_ty = firstPat (head eqns)
+
+ shift eqn@(EqnInfo { eqn_wrap = wrap,
+ eqn_pats = ConPatOut _ tvs ds bind (PrefixCon arg_pats) _ : pats })
+ = do { prs <- dsLHsBinds bind
+ ; return (eqn { eqn_wrap = wrap . wrapBinds (tvs `zip` tvs1)
+ . wrapBinds (ds `zip` dicts1)
+ . mkDsLet (Rec prs),
+ eqn_pats = map unLoc arg_pats ++ pats }) }
+
+ -- Get the arg types, which we use to type the new vars
+ -- to match on, from the "outside"; the types of pats1 may
+ -- be more refined, and hence won't do
+ arg_tys = dataConInstOrigArgTys con inst_tys
+ inst_tys | isVanillaDataCon con = tcTyConAppArgs pat_ty -- Newtypes opaque!
+ | otherwise = mkTyVarTys tvs1
+\end{code}
+
+Note [Existentials in shift_con_pat]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ data T = forall a. Ord a => T a (a->Int)
+
+ f (T x f) True = ...expr1...
+ f (T y g) False = ...expr2..
+
+When we put in the tyvars etc we get
+
+ f (T a (d::Ord a) (x::a) (f::a->Int)) True = ...expr1...
+ f (T b (e::Ord b) (y::a) (g::a->Int)) True = ...expr2...
+
+After desugaring etc we'll get a single case:
+
+ f = \t::T b::Bool ->
+ case t of
+ T a (d::Ord a) (x::a) (f::a->Int)) ->
+ case b of
+ True -> ...expr1...
+ False -> ...expr2...
+
+*** We have to substitute [a/b, d/e] in expr2! **
+Hence
+ False -> ....((/\b\(e:Ord b).expr2) a d)....
+
+Originally I tried to use
+ (\b -> let e = d in expr2) a
+to do this substitution. While this is "correct" in a way, it fails
+Lint, because e::Ord b but d::Ord a.
+
diff --git a/compiler/deSugar/MatchLit.lhs b/compiler/deSugar/MatchLit.lhs
new file mode 100644
index 0000000000..0b7907b22e
--- /dev/null
+++ b/compiler/deSugar/MatchLit.lhs
@@ -0,0 +1,329 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+%
+\section[MatchLit]{Pattern-matching literal patterns}
+
+\begin{code}
+module MatchLit ( dsLit, dsOverLit,
+ tidyLitPat, tidyNPat,
+ matchLiterals, matchNPlusKPats, matchNPats ) where
+
+#include "HsVersions.h"
+
+import {-# SOURCE #-} Match ( match )
+import {-# SOURCE #-} DsExpr ( dsExpr )
+
+import DsMonad
+import DsUtils
+
+import HsSyn
+import Id ( Id, idType )
+import CoreSyn
+import TyCon ( tyConDataCons )
+import TcType ( tcSplitTyConApp, isIntegerTy, isIntTy,
+ isFloatTy, isDoubleTy, isStringTy )
+import Type ( Type )
+import PrelNames ( ratioTyConKey )
+import TysWiredIn ( stringTy, consDataCon, intDataCon, floatDataCon, doubleDataCon )
+import PrelNames ( eqStringName )
+import Unique ( hasKey )
+import Literal ( mkMachInt, Literal(..) )
+import SrcLoc ( noLoc )
+import ListSetOps ( equivClasses, runs )
+import Ratio ( numerator, denominator )
+import SrcLoc ( Located(..) )
+import Outputable
+import FastString ( lengthFS, unpackFS )
+\end{code}
+
+%************************************************************************
+%* *
+ Desugaring literals
+ [used to be in DsExpr, but DsMeta needs it,
+ and it's nice to avoid a loop]
+%* *
+%************************************************************************
+
+We give int/float literals type @Integer@ and @Rational@, respectively.
+The typechecker will (presumably) have put \tr{from{Integer,Rational}s}
+around them.
+
+ToDo: put in range checks for when converting ``@i@''
+(or should that be in the typechecker?)
+
+For numeric literals, we try to detect there use at a standard type
+(@Int@, @Float@, etc.) are directly put in the right constructor.
+[NB: down with the @App@ conversion.]
+
+See also below where we look for @DictApps@ for \tr{plusInt}, etc.
+
+\begin{code}
+dsLit :: HsLit -> DsM CoreExpr
+dsLit (HsChar c) = returnDs (mkCharExpr c)
+dsLit (HsCharPrim c) = returnDs (mkLit (MachChar c))
+dsLit (HsString str) = mkStringExprFS str
+dsLit (HsStringPrim s) = returnDs (mkLit (MachStr s))
+dsLit (HsInteger i _) = mkIntegerExpr i
+dsLit (HsInt i) = returnDs (mkIntExpr i)
+dsLit (HsIntPrim i) = returnDs (mkIntLit i)
+dsLit (HsFloatPrim f) = returnDs (mkLit (MachFloat f))
+dsLit (HsDoublePrim d) = returnDs (mkLit (MachDouble d))
+
+dsLit (HsRat r ty)
+ = mkIntegerExpr (numerator r) `thenDs` \ num ->
+ mkIntegerExpr (denominator r) `thenDs` \ denom ->
+ returnDs (mkConApp ratio_data_con [Type integer_ty, num, denom])
+ where
+ (ratio_data_con, integer_ty)
+ = case tcSplitTyConApp ty of
+ (tycon, [i_ty]) -> ASSERT(isIntegerTy i_ty && tycon `hasKey` ratioTyConKey)
+ (head (tyConDataCons tycon), i_ty)
+
+dsOverLit :: HsOverLit Id -> DsM CoreExpr
+-- Post-typechecker, the SyntaxExpr field of an OverLit contains
+-- (an expression for) the literal value itself
+dsOverLit (HsIntegral _ lit) = dsExpr lit
+dsOverLit (HsFractional _ lit) = dsExpr lit
+\end{code}
+
+%************************************************************************
+%* *
+ Tidying lit pats
+%* *
+%************************************************************************
+
+\begin{code}
+tidyLitPat :: HsLit -> LPat Id -> LPat Id
+-- Result has only the following HsLits:
+-- HsIntPrim, HsCharPrim, HsFloatPrim
+-- HsDoublePrim, HsStringPrim, HsString
+-- * HsInteger, HsRat, HsInt can't show up in LitPats
+-- * We get rid of HsChar right here
+tidyLitPat (HsChar c) pat = mkCharLitPat c
+tidyLitPat (HsString s) pat
+ | lengthFS s <= 1 -- Short string literals only
+ = foldr (\c pat -> mkPrefixConPat consDataCon [mkCharLitPat c,pat] stringTy)
+ (mkNilPat stringTy) (unpackFS s)
+ -- The stringTy is the type of the whole pattern, not
+ -- the type to instantiate (:) or [] with!
+tidyLitPat lit pat = pat
+
+----------------
+tidyNPat :: HsOverLit Id -> Maybe (SyntaxExpr Id) -> Type -> LPat Id -> LPat Id
+tidyNPat over_lit mb_neg lit_ty default_pat
+ | isIntTy lit_ty = mk_con_pat intDataCon (HsIntPrim int_val)
+ | isFloatTy lit_ty = mk_con_pat floatDataCon (HsFloatPrim rat_val)
+ | isDoubleTy lit_ty = mk_con_pat doubleDataCon (HsDoublePrim rat_val)
+ | otherwise = default_pat
+ where
+ mk_con_pat con lit = mkPrefixConPat con [noLoc $ LitPat lit] lit_ty
+ neg_lit = case (mb_neg, over_lit) of
+ (Nothing, _) -> over_lit
+ (Just _, HsIntegral i s) -> HsIntegral (-i) s
+ (Just _, HsFractional f s) -> HsFractional (-f) s
+
+ int_val :: Integer
+ int_val = case neg_lit of
+ HsIntegral i _ -> i
+ HsFractional f _ -> panic "tidyNPat"
+
+ rat_val :: Rational
+ rat_val = case neg_lit of
+ HsIntegral i _ -> fromInteger i
+ HsFractional f _ -> f
+\end{code}
+
+
+%************************************************************************
+%* *
+ Pattern matching on LitPat
+%* *
+%************************************************************************
+
+\begin{code}
+matchLiterals :: [Id]
+ -> Type -- Type of the whole case expression
+ -> [EquationInfo]
+ -> DsM MatchResult
+-- All the EquationInfos have LitPats at the front
+
+matchLiterals (var:vars) ty eqns
+ = do { -- Group by literal
+ let groups :: [[(Literal, EquationInfo)]]
+ groups = equivClasses cmpTaggedEqn (tagLitEqns eqns)
+
+ -- Deal with each group
+ ; alts <- mapM match_group groups
+
+ -- Combine results. For everything except String
+ -- we can use a case expression; for String we need
+ -- a chain of if-then-else
+ ; if isStringTy (idType var) then
+ do { mrs <- mapM wrap_str_guard alts
+ ; return (foldr1 combineMatchResults mrs) }
+ else
+ return (mkCoPrimCaseMatchResult var ty alts)
+ }
+ where
+ match_group :: [(Literal, EquationInfo)] -> DsM (Literal, MatchResult)
+ match_group group
+ = do { let (lits, eqns) = unzip group
+ ; match_result <- match vars ty (shiftEqns eqns)
+ ; return (head lits, match_result) }
+
+ wrap_str_guard :: (Literal,MatchResult) -> DsM MatchResult
+ -- Equality check for string literals
+ wrap_str_guard (MachStr s, mr)
+ = do { eq_str <- dsLookupGlobalId eqStringName
+ ; lit <- mkStringExprFS s
+ ; let pred = mkApps (Var eq_str) [Var var, lit]
+ ; return (mkGuardedMatchResult pred mr) }
+\end{code}
+
+%************************************************************************
+%* *
+ Pattern matching on NPat
+%* *
+%************************************************************************
+
+\begin{code}
+matchNPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult
+-- All the EquationInfos have NPat at the front
+
+matchNPats (var:vars) ty eqns
+ = do { let groups :: [[(Literal, EquationInfo)]]
+ groups = equivClasses cmpTaggedEqn (tagLitEqns eqns)
+
+ ; match_results <- mapM (match_group . map snd) groups
+
+ ; ASSERT( not (null match_results) )
+ return (foldr1 combineMatchResults match_results) }
+ where
+ match_group :: [EquationInfo] -> DsM MatchResult
+ match_group (eqn1:eqns)
+ = do { lit_expr <- dsOverLit lit
+ ; neg_lit <- case mb_neg of
+ Nothing -> return lit_expr
+ Just neg -> do { neg_expr <- dsExpr neg
+ ; return (App neg_expr lit_expr) }
+ ; eq_expr <- dsExpr eq_chk
+ ; let pred_expr = mkApps eq_expr [Var var, neg_lit]
+ ; match_result <- match vars ty (eqn1' : shiftEqns eqns)
+ ; return (adjustMatchResult (eqn_wrap eqn1) $
+ -- Bring the eqn1 wrapper stuff into scope because
+ -- it may be used in pred_expr
+ mkGuardedMatchResult pred_expr match_result) }
+ where
+ NPat lit mb_neg eq_chk _ : pats1 = eqn_pats eqn1
+ eqn1' = eqn1 { eqn_wrap = idWrapper, eqn_pats = pats1 }
+\end{code}
+
+
+%************************************************************************
+%* *
+ Pattern matching on n+k patterns
+%* *
+%************************************************************************
+
+For an n+k pattern, we use the various magic expressions we've been given.
+We generate:
+\begin{verbatim}
+ if ge var lit then
+ let n = sub var lit
+ in <expr-for-a-successful-match>
+ else
+ <try-next-pattern-or-whatever>
+\end{verbatim}
+
+WATCH OUT! Consider
+
+ f (n+1) = ...
+ f (n+2) = ...
+ f (n+1) = ...
+
+We can't group the first and third together, because the second may match
+the same thing as the first. Contrast
+ f 1 = ...
+ f 2 = ...
+ f 1 = ...
+where we can group the first and third. Hence 'runs' rather than 'equivClasses'
+
+\begin{code}
+matchNPlusKPats all_vars@(var:vars) ty eqns
+ = do { let groups :: [[(Literal, EquationInfo)]]
+ groups = runs eqTaggedEqn (tagLitEqns eqns)
+
+ ; match_results <- mapM (match_group . map snd) groups
+
+ ; ASSERT( not (null match_results) )
+ return (foldr1 combineMatchResults match_results) }
+ where
+ match_group :: [EquationInfo] -> DsM MatchResult
+ match_group (eqn1:eqns)
+ = do { ge_expr <- dsExpr ge
+ ; minus_expr <- dsExpr minus
+ ; lit_expr <- dsOverLit lit
+ ; let pred_expr = mkApps ge_expr [Var var, lit_expr]
+ minusk_expr = mkApps minus_expr [Var var, lit_expr]
+ ; match_result <- match vars ty (eqn1' : map shift eqns)
+ ; return (adjustMatchResult (eqn_wrap eqn1) $
+ -- Bring the eqn1 wrapper stuff into scope because
+ -- it may be used in ge_expr, minusk_expr
+ mkGuardedMatchResult pred_expr $
+ mkCoLetMatchResult (NonRec n1 minusk_expr) $
+ match_result) }
+ where
+ NPlusKPat (L _ n1) lit ge minus : pats1 = eqn_pats eqn1
+ eqn1' = eqn1 { eqn_wrap = idWrapper, eqn_pats = pats1 }
+
+ shift eqn@(EqnInfo { eqn_wrap = wrap,
+ eqn_pats = NPlusKPat (L _ n) _ _ _ : pats })
+ = eqn { eqn_wrap = wrap . wrapBind n n1, eqn_pats = pats }
+\end{code}
+
+
+%************************************************************************
+%* *
+ Grouping functions
+%* *
+%************************************************************************
+
+Given a blob of @LitPat@s/@NPat@s, we want to split them into those
+that are ``same''/different as one we are looking at. We need to know
+whether we're looking at a @LitPat@/@NPat@, and what literal we're after.
+
+\begin{code}
+-- Tag equations by the leading literal
+-- NB: we have ordering on Core Literals, but not on HsLits
+cmpTaggedEqn :: (Literal,EquationInfo) -> (Literal,EquationInfo) -> Ordering
+cmpTaggedEqn (lit1,_) (lit2,_) = lit1 `compare` lit2
+
+eqTaggedEqn :: (Literal,EquationInfo) -> (Literal,EquationInfo) -> Bool
+eqTaggedEqn (lit1,_) (lit2,_) = lit1 == lit2
+
+tagLitEqns :: [EquationInfo] -> [(Literal, EquationInfo)]
+tagLitEqns eqns = [(get_lit (firstPat eqn), eqn) | eqn <- eqns]
+
+get_lit :: Pat Id -> Literal
+-- Get a Core literal to use (only) a grouping key
+-- Hence its type doesn't need to match the type of the original literal
+get_lit (LitPat (HsIntPrim i)) = mkMachInt i
+get_lit (LitPat (HsCharPrim c)) = MachChar c
+get_lit (LitPat (HsStringPrim s)) = MachStr s
+get_lit (LitPat (HsFloatPrim f)) = MachFloat f
+get_lit (LitPat (HsDoublePrim d)) = MachDouble d
+get_lit (LitPat (HsString s)) = MachStr s
+
+get_lit (NPat (HsIntegral i _) Nothing _ _) = MachInt i
+get_lit (NPat (HsIntegral i _) (Just _) _ _) = MachInt (-i)
+get_lit (NPat (HsFractional r _) Nothing _ _) = MachFloat r
+get_lit (NPat (HsFractional r _) (Just _) _ _) = MachFloat (-r)
+
+get_lit (NPlusKPat _ (HsIntegral i _) _ _) = MachInt i
+
+-- These ones can't happen
+-- get_lit (LitPat (HsChar c))
+-- get_lit (LitPat (HsInt i))
+get_lit other = pprPanic "get_lit:bad pattern" (ppr other)
+\end{code}
+
diff --git a/compiler/deSugar/deSugar.tex b/compiler/deSugar/deSugar.tex
new file mode 100644
index 0000000000..02cb285742
--- /dev/null
+++ b/compiler/deSugar/deSugar.tex
@@ -0,0 +1,23 @@
+\documentstyle{report}
+\input{lit-style}
+
+\begin{document}
+\centerline{{\Large{deSugar}}}
+\tableofcontents
+
+\input{Desugar} % {@deSugar@: the main function}
+\input{DsBinds} % {Pattern-matching bindings (HsBinds and MonoBinds)}
+\input{DsGRHSs} % {Matching guarded right-hand-sides (GRHSs)}
+\input{DsExpr} % {Matching expressions (Exprs)}
+\input{DsHsSyn} % {Haskell abstract syntax---added things for desugarer}
+\input{DsListComp} % {Desugaring list comprehensions}
+\input{DsMonad} % {@DsMonad@: monadery used in desugaring}
+\input{DsUtils} % {Utilities for desugaring}
+\input{Check} % {Module @Check@ in @deSugar@}
+\input{Match} % {The @match@ function}
+\input{MatchCon} % {Pattern-matching constructors}
+\input{MatchLit} % {Pattern-matching literal patterns}
+\input{DsForeign} % {Desugaring \tr{foreign} declarations}
+\input{DsCCall} % {Desugaring \tr{_ccall_}s and \tr{_casm_}s}
+
+\end{document}