diff options
author | Simon Marlow <simonmar@microsoft.com> | 2006-04-07 02:05:11 +0000 |
---|---|---|
committer | Simon Marlow <simonmar@microsoft.com> | 2006-04-07 02:05:11 +0000 |
commit | 0065d5ab628975892cea1ec7303f968c3338cbe1 (patch) | |
tree | 8e2afe0ab48ee33cf95009809d67c9649573ef92 /compiler/deSugar | |
parent | 28a464a75e14cece5db40f2765a29348273ff2d2 (diff) | |
download | haskell-0065d5ab628975892cea1ec7303f968c3338cbe1.tar.gz |
Reorganisation of the source tree
Most of the other users of the fptools build system have migrated to
Cabal, and with the move to darcs we can now flatten the source tree
without losing history, so here goes.
The main change is that the ghc/ subdir is gone, and most of what it
contained is now at the top level. The build system now makes no
pretense at being multi-project, it is just the GHC build system.
No doubt this will break many things, and there will be a period of
instability while we fix the dependencies. A straightforward build
should work, but I haven't yet fixed binary/source distributions.
Changes to the Building Guide will follow, too.
Diffstat (limited to 'compiler/deSugar')
-rw-r--r-- | compiler/deSugar/Check.lhs | 698 | ||||
-rw-r--r-- | compiler/deSugar/Desugar.lhs | 298 | ||||
-rw-r--r-- | compiler/deSugar/DsArrows.lhs | 1055 | ||||
-rw-r--r-- | compiler/deSugar/DsBinds.lhs | 417 | ||||
-rw-r--r-- | compiler/deSugar/DsCCall.lhs | 456 | ||||
-rw-r--r-- | compiler/deSugar/DsExpr.hi-boot-5 | 5 | ||||
-rw-r--r-- | compiler/deSugar/DsExpr.hi-boot-6 | 6 | ||||
-rw-r--r-- | compiler/deSugar/DsExpr.lhs | 781 | ||||
-rw-r--r-- | compiler/deSugar/DsExpr.lhs-boot | 11 | ||||
-rw-r--r-- | compiler/deSugar/DsForeign.lhs | 646 | ||||
-rw-r--r-- | compiler/deSugar/DsGRHSs.lhs | 128 | ||||
-rw-r--r-- | compiler/deSugar/DsListComp.lhs | 516 | ||||
-rw-r--r-- | compiler/deSugar/DsMeta.hs | 1732 | ||||
-rw-r--r-- | compiler/deSugar/DsMonad.lhs | 285 | ||||
-rw-r--r-- | compiler/deSugar/DsUtils.lhs | 884 | ||||
-rw-r--r-- | compiler/deSugar/Match.hi-boot-5 | 6 | ||||
-rw-r--r-- | compiler/deSugar/Match.hi-boot-6 | 27 | ||||
-rw-r--r-- | compiler/deSugar/Match.lhs | 740 | ||||
-rw-r--r-- | compiler/deSugar/Match.lhs-boot | 35 | ||||
-rw-r--r-- | compiler/deSugar/MatchCon.lhs | 174 | ||||
-rw-r--r-- | compiler/deSugar/MatchLit.lhs | 329 | ||||
-rw-r--r-- | compiler/deSugar/deSugar.tex | 23 |
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} |