[project @ 2003-06-25 16:24:56 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsUtils.lhs
index 42bd271..4705082 100644 (file)
@@ -24,25 +24,29 @@ module DsUtils (
        mkIntExpr, mkCharExpr,
        mkStringLit, mkStringLitFS, mkIntegerExpr, 
 
-       mkSelectorBinds, mkTupleExpr, mkTupleSelector, mkCoreTup,
+       mkSelectorBinds, mkTupleExpr, mkTupleSelector, 
+       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 )
 import CoreSyn
-
+import Constants       ( mAX_TUPLE_SIZE )
 import DsMonad
 
 import CoreUtils       ( exprType, mkIfThenElse, mkCoerce )
-import PrelInfo                ( iRREFUT_PAT_ERROR_ID )
-import MkId            ( mkReboxingAlt, mkNewTypeBody )
-import Id              ( idType, Id, mkWildId )
+import MkId            ( iRREFUT_PAT_ERROR_ID, mkReboxingAlt, mkNewTypeBody )
+import Id              ( idType, Id, mkWildId, mkTemplateLocals )
+import Name            ( Name )
 import Literal         ( Literal(..), inIntRange, tARGET_MAX_INT )
 import TyCon           ( isNewTyCon, tyConDataCons )
 import DataCon         ( DataCon, dataConSourceArity )
@@ -50,7 +54,7 @@ import Type           ( mkFunTy, isUnLiftedType, Type, splitTyConApp )
 import TcType          ( tcTyConAppTyCon, isIntTy, isFloatTy, isDoubleTy )
 import TysPrim         ( intPrimTy )
 import TysWiredIn      ( nilDataCon, consDataCon, 
-                          tupleCon,
+                          tupleCon, mkTupleTy,
                          unitDataConId, unitTy,
                           charTy, charDataCon, 
                           intTy, intDataCon, smallIntegerDataCon, 
@@ -64,7 +68,8 @@ import PrelNames      ( unpackCStringName, unpackCStringUtf8Name,
                          lengthPName, indexPName )
 import Outputable
 import UnicodeUtil      ( intsToUtf8, stringToUtf8 )
-import Util             ( isSingleton, notNull )
+import Util             ( isSingleton, notNull, zipEqual )
+import ListSetOps      ( assocDefault )
 import FastString
 \end{code}
 
@@ -72,6 +77,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}
 %*                                                                     *
 %************************************************************************
@@ -402,9 +437,11 @@ mkErrorAppDs err_id ty msg
 %************************************************************************
 
 \begin{code}
-mkCharExpr    :: Int    -> CoreExpr      -- Returns    C# c :: Int
-mkIntExpr     :: Integer -> CoreExpr     -- Returns    I# i :: Int
-mkIntegerExpr :: Integer -> DsM CoreExpr  -- Result :: Integer
+mkCharExpr    :: Int       -> CoreExpr      -- Returns C# c :: Int
+mkIntExpr     :: Integer    -> CoreExpr             -- Returns I# i :: Int
+mkIntegerExpr :: Integer    -> DsM CoreExpr  -- Result :: Integer
+mkStringLit   :: String     -> DsM CoreExpr  -- Result :: String
+mkStringLitFS :: FastString -> DsM CoreExpr  -- Result :: String
 
 mkIntExpr  i = mkConApp intDataCon  [mkIntLit i]
 mkCharExpr c = mkConApp charDataCon [mkLit (MachChar c)]
@@ -439,10 +476,8 @@ mkIntegerExpr i
 
 mkSmallIntegerLit i = mkConApp smallIntegerDataCon [mkIntLit i]
 
-mkStringLit   :: String       -> DsM CoreExpr
 mkStringLit str        = mkStringLitFS (mkFastString str)
 
-mkStringLitFS :: FastString  -> DsM CoreExpr
 mkStringLitFS str
   | nullFastString str
   = returnDs (mkNilExpr charTy)
@@ -499,7 +534,25 @@ mkSelectorBinds (VarPat v) val_expr
 
 mkSelectorBinds pat val_expr
   | isSingleton binders || is_simple_pat pat
-  = newSysLocalDs (exprType val_expr)  `thenDs` \ val_var ->
+  =    -- 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 SourceType, 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
@@ -550,27 +603,43 @@ mkSelectorBinds pat val_expr
 \end{code}
 
 
-@mkTupleExpr@ builds a tuple; the inverse to @mkTupleSelector@.  If it
-has only one element, it is the identity function.
+%************************************************************************
+%*                                                                     *
+               Tuples
+%*                                                                     *
+%************************************************************************
 
-\begin{code}
-mkTupleExpr :: [Id] -> CoreExpr
+@mkTupleExpr@ builds a tuple; the inverse to @mkTupleSelector@.  
 
-{- This code has been replaced by mkCoreTup below
-mkTupleExpr []  = Var unitDataConId
-mkTupleExpr [id] = Var id
-mkTupleExpr ids         = mkConApp (tupleCon Boxed (length ids))
-                           (map (Type . idType) ids ++ [ Var i | i <-ids])
--}
+* If it has only one element, it is the identity function.
 
-mkTupleExpr ids = mkCoreTup(map Var ids)                           
-                           
-mkCoreTup :: [CoreExpr] -> CoreExpr                        
-mkCoreTup []   = Var unitDataConId
-mkCoreTup [c]  = c
-mkCoreTup cs  = mkConApp (tupleCon Boxed (length cs))
-                        (map (Type . exprType) cs ++ cs)
-                           
+* 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 
+  = mk_tuple_expr (chunkify (map Var ids))
+  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))
+
+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}
 
 
@@ -583,6 +652,19 @@ 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
@@ -590,13 +672,17 @@ mkTupleSelector :: [Id]           -- The tuple args
                -> CoreExpr     -- Scrutinee
                -> CoreExpr
 
-mkTupleSelector [var] should_be_the_same_var scrut_var scrut
-  = ASSERT(var == should_be_the_same_var)
-    scrut
-
 mkTupleSelector vars the_var scrut_var scrut
-  = ASSERT( notNull vars )
-    Case scrut scrut_var [(DataAlt (tupleCon Boxed (length vars)), vars, Var the_var)]
+  = 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}
 
 
@@ -618,7 +704,37 @@ 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 
+        [(DataAlt (tupleCon Boxed (length vars)), vars, Var the_var)]
 \end{code}