[project @ 2003-10-30 09:03:15 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsUtils.lhs
index 5191c9d..e7f88fe 100644 (file)
@@ -25,14 +25,18 @@ module DsUtils (
        mkStringLit, mkStringLitFS, mkIntegerExpr, 
 
        mkSelectorBinds, mkTupleExpr, mkTupleSelector, 
+       mkTupleType, mkTupleCase, mkBigCoreTup,
        mkCoreTup, mkCoreSel, mkCoreTupTy,
+       
+       dsReboundNames, lookupReboundName,
 
        selectMatchVar
     ) where
 
 #include "HsVersions.h"
 
-import {-# SOURCE #-} Match ( matchSimply )
+import {-# SOURCE #-}  Match ( matchSimply )
+import {-# SOURCE #-}  DsExpr( dsExpr )
 
 import HsSyn
 import TcHsSyn         ( TypecheckedPat, hsPatType )
@@ -40,9 +44,10 @@ import CoreSyn
 import Constants       ( mAX_TUPLE_SIZE )
 import DsMonad
 
-import CoreUtils       ( exprType, mkIfThenElse, mkCoerce )
+import CoreUtils       ( exprType, mkIfThenElse, mkCoerce, bindNonRec )
 import MkId            ( iRREFUT_PAT_ERROR_ID, mkReboxingAlt, mkNewTypeBody )
-import Id              ( idType, Id, mkWildId, mkTemplateLocals )
+import Id              ( idType, Id, mkWildId, mkTemplateLocals, mkSysLocal )
+import Name            ( Name )
 import Literal         ( Literal(..), inIntRange, tARGET_MAX_INT )
 import TyCon           ( isNewTyCon, tyConDataCons )
 import DataCon         ( DataCon, dataConSourceArity )
@@ -53,18 +58,20 @@ import TysWiredIn   ( nilDataCon, consDataCon,
                           tupleCon, mkTupleTy,
                          unitDataConId, unitTy,
                           charTy, charDataCon, 
-                          intTy, intDataCon, smallIntegerDataCon, 
+                          intTy, intDataCon, 
                          floatDataCon, 
                           doubleDataCon,
                          stringTy, isPArrFakeCon )
 import BasicTypes      ( Boxity(..) )
 import UniqSet         ( mkUniqSet, minusUniqSet, isEmptyUniqSet, UniqSet )
+import UniqSupply      ( splitUniqSupply, uniqFromSupply, uniqsFromSupply )
 import PrelNames       ( unpackCStringName, unpackCStringUtf8Name, 
-                         plusIntegerName, timesIntegerName, 
+                         plusIntegerName, timesIntegerName, smallIntegerDataConName, 
                          lengthPName, indexPName )
 import Outputable
 import UnicodeUtil      ( intsToUtf8, stringToUtf8 )
 import Util             ( isSingleton, notNull, zipEqual )
+import ListSetOps      ( assocDefault )
 import FastString
 \end{code}
 
@@ -72,6 +79,36 @@ import FastString
 
 %************************************************************************
 %*                                                                     *
+               Rebindable syntax
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+dsReboundNames :: ReboundNames Id 
+              -> DsM ([CoreBind],      -- Auxiliary bindings
+                      [(Name,Id)])     -- Maps the standard name to its value
+
+dsReboundNames 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))
+
+lookupReboundName :: [(Name,Id)] -> Name -> CoreExpr
+lookupReboundName prs std_name
+  = Var (assocDefault (mk_panic std_name) prs std_name)
+  where
+    mk_panic std_name = pprPanic "dsReboundNames" (ptext SLIT("Not found:") <+> ppr std_name)
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
 \subsection{Tidying lit pats}
 %*                                                                     *
 %************************************************************************
@@ -97,13 +134,13 @@ tidyNPat lit lit_ty default_pat
   | otherwise          = default_pat
 
   where
-    mk_int    (HsInteger i) = HsIntPrim i
+    mk_int    (HsInteger i _) = HsIntPrim i
 
-    mk_float  (HsInteger i) = HsFloatPrim (fromInteger i)
-    mk_float  (HsRat f _)   = HsFloatPrim f
+    mk_float  (HsInteger i _) = HsFloatPrim (fromInteger i)
+    mk_float  (HsRat f _)     = HsFloatPrim f
 
-    mk_double (HsInteger i) = HsDoublePrim (fromInteger i)
-    mk_double (HsRat f _)   = HsDoublePrim f
+    mk_double (HsInteger i _) = HsDoublePrim (fromInteger i)
+    mk_double (HsRat f _)     = HsDoublePrim f
 \end{code}
 
 
@@ -250,7 +287,7 @@ mkCoPrimCaseMatchResult var match_alts
   = MatchResult CanFail mk_case
   where
     mk_case fail
-      = mapDs (mk_alt fail) match_alts         `thenDs` \ alts ->
+      = mappM (mk_alt fail) match_alts         `thenDs` \ alts ->
        returnDs (Case (Var var) var ((DEFAULT, [], fail) : alts))
 
     mk_alt fail (lit, MatchResult _ body_fn) = body_fn fail    `thenDs` \ body ->
@@ -291,13 +328,13 @@ mkCoAlgCaseMatchResult var match_alts
              = CanFail
 
     wild_var = mkWildId (idType var)
-    mk_case fail = mapDs (mk_alt fail) match_alts      `thenDs` \ alts ->
+    mk_case fail = mappM (mk_alt fail) match_alts      `thenDs` \ alts ->
                   returnDs (Case (Var var) wild_var (mk_default fail ++ alts))
 
     mk_alt fail (con, args, MatchResult _ body_fn)
        = body_fn fail                          `thenDs` \ body ->
-         getUniquesDs                          `thenDs` \ us ->
-         returnDs (mkReboxingAlt us con args body)
+         newUniqueSupply                       `thenDs` \ us ->
+         returnDs (mkReboxingAlt (uniqsFromSupply us) con args body)
 
     mk_default fail | exhaustive_case = []
                    | otherwise       = [(DEFAULT, [], fail)]
@@ -350,7 +387,7 @@ mkCoAlgCaseMatchResult var match_alts
        unboxAlt = 
          newSysLocalDs intPrimTy                       `thenDs` \l        ->
          dsLookupGlobalId indexPName           `thenDs` \indexP   ->
-         mapDs (mkAlt indexP) match_alts               `thenDs` \alts     ->
+         mappM (mkAlt indexP) match_alts               `thenDs` \alts     ->
          returnDs (DataAlt intDataCon, [l], (Case (Var l) wild (dft : alts)))
           where
            wild = mkWildId intPrimTy
@@ -413,7 +450,8 @@ mkCharExpr c = mkConApp charDataCon [mkLit (MachChar c)]
 
 mkIntegerExpr i
   | inIntRange i       -- Small enough, so start from an Int
-  = returnDs (mkSmallIntegerLit i)
+  = 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
@@ -421,25 +459,27 @@ mkIntegerExpr i
 
   | otherwise          -- Big, so start from a string
   = dsLookupGlobalId plusIntegerName           `thenDs` \ plus_id ->
-    dsLookupGlobalId timesIntegerName  `thenDs` \ times_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 mkSmallIntegerLit i 
-                                 else mkSmallIntegerLit r `plus` mkSmallIntegerLit (i-r)
-                  | r == 0     =                             horner b q `times` mkSmallIntegerLit b
-                  | otherwise  = mkSmallIntegerLit r `plus` (horner b q `times` mkSmallIntegerLit b)
+                                 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 i = mkConApp smallIntegerDataCon [mkIntLit i]
+mkSmallIntegerLit small_integer_data_con i = mkConApp small_integer_data_con [mkIntLit i]
 
 mkStringLit str        = mkStringLitFS (mkFastString str)
 
@@ -510,7 +550,7 @@ mkSelectorBinds pat val_expr
        -- 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 SourceType, which is opaque
+       -- 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) => ...)
@@ -524,7 +564,7 @@ mkSelectorBinds pat val_expr
     mkErrorAppDs iRREFUT_PAT_ERROR_ID 
                 unitTy (showSDoc (ppr pat))    `thenDs` \ err_expr ->
     newSysLocalDs unitTy                       `thenDs` \ err_var ->
-    mapDs (mk_bind val_var err_var) binders    `thenDs` \ binds ->
+    mappM (mk_bind val_var err_var) binders    `thenDs` \ binds ->
     returnDs ( (val_var, val_expr) : 
               (err_var, err_expr) :
               binds )
@@ -586,28 +626,32 @@ a 10-tuple of 2-tuples (11 objects).  So we want the leaves to be big.
 
 \begin{code}
 mkTupleExpr :: [Id] -> CoreExpr
-mkTupleExpr ids 
-  = mk_tuple_expr (chunkify (map Var ids))
+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
-    mk_tuple_expr :: [[CoreExpr]] -> CoreExpr
        -- Each sub-list is short enough to fit in a tuple
-    mk_tuple_expr [exprs] = mkCoreTup exprs
-    mk_tuple_expr exprs_s = mk_tuple_expr (chunkify (map mkCoreTup exprs_s))
+    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 = [xs]
-  | otherwise             = split xs
+  | n_xs <= mAX_TUPLE_SIZE = {- pprTrace "Small" (ppr n_xs) -} [xs] 
+  | otherwise             = {- pprTrace "Big"   (ppr n_xs) -} (split xs)
   where
-       -- n_chunks_m1 = numbe of chunks - 1
-    n_xs        = length xs
-    n_chunks_m1 = n_xs `div` mAX_TUPLE_SIZE
-    chunk_size  = n_xs `div` n_chunks_m1
-
+    n_xs     = length xs
     split [] = []
-    split xs = take chunk_size xs : split (drop chunk_size xs)
+    split xs = take mAX_TUPLE_SIZE xs : split (drop mAX_TUPLE_SIZE xs)
 \end{code}
 
 
@@ -653,6 +697,64 @@ mkTupleSelector vars the_var scrut_var scrut
                                         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
+  = Case scrut scrut_var [(DataAlt (tupleCon Boxed (length vars)), vars, body)]
+\end{code}
 
 %************************************************************************
 %*                                                                     *