[project @ 2003-12-10 14:15:16 by simonmar]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsUtils.lhs
index 290ee47..79e757c 100644 (file)
@@ -12,7 +12,7 @@ module DsUtils (
 
        tidyLitPat, tidyNPat,
 
-       mkDsLet, mkDsLets,
+       mkDsLet,
 
        cantFailMatchResult, extractMatchResult,
        combineMatchResults, 
@@ -25,24 +25,29 @@ module DsUtils (
        mkStringLit, mkStringLitFS, mkIntegerExpr, 
 
        mkSelectorBinds, mkTupleExpr, mkTupleSelector, 
-       mkCoreTup, mkCoreSel, mkCoreTupTy,
+       mkTupleType, mkTupleCase, mkBigCoreTup,
+       mkCoreTup, mkCoreTupTy,
+       
+       dsReboundNames, lookupReboundName,
 
-       selectMatchVar
+       selectMatchVarL, selectMatchVar
     ) where
 
 #include "HsVersions.h"
 
-import {-# SOURCE #-} Match ( matchSimply )
+import {-# SOURCE #-}  Match ( matchSimply )
+import {-# SOURCE #-}  DsExpr( dsLExpr )
 
 import HsSyn
-import TcHsSyn         ( TypecheckedPat, hsPatType )
+import TcHsSyn         ( hsPatType )
 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,21 @@ 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 SrcLoc          ( Located(..), unLoc, noLoc )
 import Util             ( isSingleton, notNull, zipEqual )
+import ListSetOps      ( assocDefault )
 import FastString
 \end{code}
 
@@ -72,38 +80,69 @@ 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, L _ (HsVar id)) = return ([], (std_name, id))
+    mk_bind (std_name, expr)
+        = dsLExpr 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}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-tidyLitPat :: HsLit -> TypecheckedPat -> TypecheckedPat
+tidyLitPat :: HsLit -> LPat Id -> LPat Id
 tidyLitPat (HsChar c) pat = mkCharLitPat c
-tidyLitPat lit        pat = pat
+tidyLitPat lit       pat = pat
 
-tidyNPat :: HsLit -> Type -> TypecheckedPat -> TypecheckedPat
+tidyNPat :: HsLit -> Type -> LPat Id -> LPat Id
 tidyNPat (HsString s) _ pat
   | lengthFS s <= 1    -- Short string literals only
   = foldr (\c pat -> mkPrefixConPat consDataCon [mkCharLitPat c,pat] stringTy)
-         (mkNilPat stringTy) (unpackIntFS s)
+         (mkNilPat stringTy) (unpackFS s)
        -- The stringTy is the type of the whole pattern, not 
        -- the type to instantiate (:) or [] with!
   where
 
 tidyNPat lit lit_ty default_pat
-  | isIntTy lit_ty             = mkPrefixConPat intDataCon    [LitPat (mk_int lit)]    lit_ty 
-  | isFloatTy lit_ty   = mkPrefixConPat floatDataCon  [LitPat (mk_float lit)]  lit_ty 
-  | isDoubleTy lit_ty  = mkPrefixConPat doubleDataCon [LitPat (mk_double lit)] lit_ty 
+  | isIntTy lit_ty             = mkPrefixConPat intDataCon    [noLoc $ LitPat (mk_int lit)]    lit_ty 
+  | isFloatTy lit_ty   = mkPrefixConPat floatDataCon  [noLoc $ LitPat (mk_float lit)]  lit_ty 
+  | isDoubleTy lit_ty  = mkPrefixConPat doubleDataCon [noLoc $ LitPat (mk_double lit)] lit_ty 
   | 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}
 
 
@@ -140,11 +179,14 @@ hand, which should indeed be bound to the pattern as a whole, then use it;
 otherwise, make one up.
 
 \begin{code}
-selectMatchVar :: TypecheckedPat -> DsM Id
+selectMatchVarL :: LPat Id -> DsM Id
+selectMatchVarL pat = selectMatchVar (unLoc pat)
+
 selectMatchVar (VarPat var)     = returnDs var
-selectMatchVar (AsPat var pat)         = returnDs var
-selectMatchVar (LazyPat pat)           = selectMatchVar pat
-selectMatchVar other_pat               = newSysLocalDs (hsPatType other_pat) -- OK, better make up one...
+selectMatchVar (AsPat var pat)  = returnDs (unLoc var)
+selectMatchVar (LazyPat pat)    = selectMatchVarL pat
+selectMatchVar other_pat        = newSysLocalDs (hsPatType (noLoc other_pat))
+                                -- OK, better make up one...
 \end{code}
 
 
@@ -172,7 +214,7 @@ data EquationInfo
                        -- of the *first* thing matched in this group.
                        -- Should perhaps be a list of them all!
 
-       [TypecheckedPat]    -- The patterns for an eqn
+       [Pat Id]        -- The patterns for an eqn
 
        MatchResult         -- Encapsulates the guards and bindings
 \end{code}
@@ -250,7 +292,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 +333,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 +392,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
@@ -386,7 +428,7 @@ mkErrorAppDs :: Id          -- The error function
             -> DsM CoreExpr
 
 mkErrorAppDs err_id ty msg
-  = getSrcLocDs                        `thenDs` \ src_loc ->
+  = getSrcSpanDs               `thenDs` \ src_loc ->
     let
        full_msg = showSDoc (hcat [ppr src_loc, text "|", text msg])
        core_msg = Lit (MachStr (mkFastString (stringToUtf8 full_msg)))
@@ -402,7 +444,7 @@ mkErrorAppDs err_id ty msg
 %************************************************************************
 
 \begin{code}
-mkCharExpr    :: Int       -> CoreExpr      -- Returns C# c :: Int
+mkCharExpr    :: Char      -> CoreExpr      -- Returns C# c :: Int
 mkIntExpr     :: Integer    -> CoreExpr             -- Returns I# i :: Int
 mkIntegerExpr :: Integer    -> DsM CoreExpr  -- Result :: Integer
 mkStringLit   :: String     -> DsM CoreExpr  -- Result :: String
@@ -413,7 +455,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 +464,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)
 
@@ -449,7 +494,7 @@ mkStringLitFS str
 
   | lengthFS str == 1
   = let
-       the_char = mkCharExpr (headIntFS str)
+       the_char = mkCharExpr (headFS str)
     in
     returnDs (mkConsExpr charTy the_char (mkNilExpr charTy))
 
@@ -490,15 +535,15 @@ even more helpful.  Something very similar happens for pattern-bound
 expressions.
 
 \begin{code}
-mkSelectorBinds :: TypecheckedPat      -- The pattern
-               -> CoreExpr             -- Expression to which the pattern is bound
+mkSelectorBinds :: LPat Id     -- The pattern
+               -> CoreExpr     -- Expression to which the pattern is bound
                -> DsM [(Id,CoreExpr)]
 
-mkSelectorBinds (VarPat v) val_expr
+mkSelectorBinds (L _ (VarPat v)) val_expr
   = returnDs [(v, val_expr)]
 
 mkSelectorBinds pat val_expr
-  | isSingleton binders || is_simple_pat pat
+  | 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)
@@ -510,7 +555,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 +569,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 )
@@ -555,15 +600,19 @@ mkSelectorBinds pat val_expr
       where
         error_expr = mkCoerce (idType bndr_var) (Var err_var)
 
-    is_simple_pat (TuplePat ps Boxed)    = all is_triv_pat ps
-    is_simple_pat (ConPatOut _ ps _ _ _) = all is_triv_pat (hsConArgs ps)
+    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_pat p
+    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_pat p
+    is_triv_pat (ParPat p)  = is_triv_lpat p
     is_triv_pat other       = False
 \end{code}
 
@@ -586,21 +635,28 @@ 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 = pprTrace "Small" (ppr n_xs) [xs] 
-  | otherwise             = pprTrace "Big" (ppr n_xs) (split 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 [] = []
@@ -650,6 +706,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}
 
 %************************************************************************
 %*                                                                     *