[project @ 2003-06-02 13:28:08 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsUtils.lhs
index b1e950e..31f11d6 100644 (file)
@@ -20,10 +20,11 @@ module DsUtils (
        mkCoLetsMatchResult, mkGuardedMatchResult, 
        mkCoPrimCaseMatchResult, mkCoAlgCaseMatchResult,
 
-       mkErrorAppDs, mkNilExpr, mkConsExpr,
-       mkStringLit, mkStringLitFS, mkIntegerLit, 
+       mkErrorAppDs, mkNilExpr, mkConsExpr, mkListExpr,
+       mkIntExpr, mkCharExpr,
+       mkStringLit, mkStringLitFS, mkIntegerExpr, 
 
-       mkSelectorBinds, mkTupleExpr, mkTupleSelector,
+       mkSelectorBinds, mkTupleExpr, mkTupleSelector, mkCoreTup,
 
        selectMatchVar
     ) where
@@ -33,23 +34,22 @@ module DsUtils (
 import {-# SOURCE #-} Match ( matchSimply )
 
 import HsSyn
-import TcHsSyn         ( TypecheckedPat, outPatType, collectTypedPatBinders )
+import TcHsSyn         ( TypecheckedPat, hsPatType )
 import CoreSyn
-
+import Constants       ( mAX_TUPLE_SIZE )
 import DsMonad
 
-import CoreUtils       ( exprType, mkIfThenElse )
-import PrelInfo                ( iRREFUT_PAT_ERROR_ID )
-import MkId            ( mkReboxingAlt, mkNewTypeBody )
-import Id              ( idType, Id, mkWildId )
+import CoreUtils       ( exprType, mkIfThenElse, mkCoerce )
+import MkId            ( iRREFUT_PAT_ERROR_ID, mkReboxingAlt, mkNewTypeBody )
+import Id              ( idType, Id, mkWildId, mkTemplateLocals )
 import Literal         ( Literal(..), inIntRange, tARGET_MAX_INT )
-import TyCon           ( isNewTyCon, tyConDataCons, isRecursiveTyCon )
+import TyCon           ( isNewTyCon, tyConDataCons )
 import DataCon         ( DataCon, dataConSourceArity )
 import Type            ( mkFunTy, isUnLiftedType, Type, splitTyConApp )
 import TcType          ( tcTyConAppTyCon, isIntTy, isFloatTy, isDoubleTy )
-import TysPrim         ( intPrimTy, charPrimTy, floatPrimTy, doublePrimTy )
+import TysPrim         ( intPrimTy )
 import TysWiredIn      ( nilDataCon, consDataCon, 
-                          tupleCon,
+                          tupleCon, mkTupleTy,
                          unitDataConId, unitTy,
                           charTy, charDataCon, 
                           intTy, intDataCon, smallIntegerDataCon, 
@@ -62,8 +62,9 @@ import PrelNames      ( unpackCStringName, unpackCStringUtf8Name,
                          plusIntegerName, timesIntegerName, 
                          lengthPName, indexPName )
 import Outputable
-import UnicodeUtil      ( stringToUtf8 )
-import Util             ( isSingleton, notNull )
+import UnicodeUtil      ( intsToUtf8, stringToUtf8 )
+import Util             ( isSingleton, notNull, zipEqual )
+import FastString
 \end{code}
 
 
@@ -76,23 +77,22 @@ import Util             ( isSingleton, notNull )
 
 \begin{code}
 tidyLitPat :: HsLit -> TypecheckedPat -> TypecheckedPat
-tidyLitPat (HsChar c) pat = ConPat charDataCon   charTy [] [] [LitPat (HsCharPrim c)   charPrimTy]
+tidyLitPat (HsChar c) pat = mkCharLitPat c
 tidyLitPat lit        pat = pat
 
 tidyNPat :: HsLit -> Type -> TypecheckedPat -> TypecheckedPat
 tidyNPat (HsString s) _ pat
-  | _LENGTH_ s <= 1    -- Short string literals only
-  = foldr (\c pat -> ConPat consDataCon stringTy [] [] [mk_char_lit c,pat])
-         (ConPat nilDataCon stringTy [] [] []) (_UNPK_INT_ s)
+  | lengthFS s <= 1    -- Short string literals only
+  = foldr (\c pat -> mkPrefixConPat consDataCon [mkCharLitPat c,pat] stringTy)
+         (mkNilPat stringTy) (unpackIntFS s)
        -- The stringTy is the type of the whole pattern, not 
        -- the type to instantiate (:) or [] with!
   where
-    mk_char_lit c = ConPat charDataCon charTy [] [] [LitPat (HsCharPrim c) charPrimTy]
 
 tidyNPat lit lit_ty default_pat
-  | isIntTy lit_ty             = ConPat intDataCon    lit_ty [] [] [LitPat (mk_int lit)    intPrimTy]
-  | isFloatTy lit_ty   = ConPat floatDataCon  lit_ty [] [] [LitPat (mk_float lit)  floatPrimTy]
-  | isDoubleTy lit_ty  = ConPat doubleDataCon lit_ty [] [] [LitPat (mk_double lit) doublePrimTy]
+  | 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 
   | otherwise          = default_pat
 
   where
@@ -143,7 +143,7 @@ selectMatchVar :: TypecheckedPat -> DsM Id
 selectMatchVar (VarPat var)     = returnDs var
 selectMatchVar (AsPat var pat)         = returnDs var
 selectMatchVar (LazyPat pat)           = selectMatchVar pat
-selectMatchVar other_pat               = newSysLocalDs (outPatType other_pat) -- OK, better make up one...
+selectMatchVar other_pat               = newSysLocalDs (hsPatType other_pat) -- OK, better make up one...
 \end{code}
 
 
@@ -336,7 +336,7 @@ mkCoAlgCaseMatchResult var match_alts
          panic "DsUtils: You may not mix `[:...:]' with `PArr' patterns"
     --
     mk_parrCase fail =                    
-      dsLookupGlobalValue lengthPName                  `thenDs` \lengthP  ->
+      dsLookupGlobalId lengthPName                     `thenDs` \lengthP  ->
       unboxAlt                                         `thenDs` \alt      ->
       returnDs (Case (len lengthP) (mkWildId intTy) [alt])
       where
@@ -348,7 +348,7 @@ mkCoAlgCaseMatchResult var match_alts
        --
        unboxAlt = 
          newSysLocalDs intPrimTy                       `thenDs` \l        ->
-         dsLookupGlobalValue indexPName                `thenDs` \indexP   ->
+         dsLookupGlobalId indexPName           `thenDs` \indexP   ->
          mapDs (mkAlt indexP) match_alts               `thenDs` \alts     ->
          returnDs (DataAlt intDataCon, [l], (Case (Var l) wild (dft : alts)))
           where
@@ -368,8 +368,7 @@ mkCoAlgCaseMatchResult var match_alts
            lit   = MachInt $ toInteger (dataConSourceArity con)
            binds = [NonRec arg (indexExpr i) | (i, arg) <- zip [1..] args]
            --
-           indexExpr i = mkApps (Var indexP) [Type elemTy, Var var, toInt i]
-           toInt     i = mkConApp intDataCon [Lit $ MachInt i]
+           indexExpr i = mkApps (Var indexP) [Type elemTy, Var var, mkIntExpr i]
 \end{code}
 
 
@@ -389,8 +388,8 @@ mkErrorAppDs err_id ty msg
   = getSrcLocDs                        `thenDs` \ src_loc ->
     let
        full_msg = showSDoc (hcat [ppr src_loc, text "|", text msg])
+       core_msg = Lit (MachStr (mkFastString (stringToUtf8 full_msg)))
     in
-    mkStringLit full_msg               `thenDs` \ core_msg ->
     returnDs (mkApps (Var err_id) [Type ty, core_msg])
 \end{code}
 
@@ -402,8 +401,16 @@ mkErrorAppDs err_id ty msg
 %************************************************************************
 
 \begin{code}
-mkIntegerLit :: Integer -> DsM CoreExpr
-mkIntegerLit i
+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)]
+
+mkIntegerExpr i
   | inIntRange i       -- Small enough, so start from an Int
   = returnDs (mkSmallIntegerLit i)
 
@@ -412,8 +419,8 @@ mkIntegerLit i
 -- integral literals. This improves constant folding.
 
   | otherwise          -- Big, so start from a string
-  = dsLookupGlobalValue plusIntegerName                `thenDs` \ plus_id ->
-    dsLookupGlobalValue timesIntegerName       `thenDs` \ times_id ->
+  = dsLookupGlobalId plusIntegerName           `thenDs` \ plus_id ->
+    dsLookupGlobalId timesIntegerName  `thenDs` \ times_id ->
     let 
         plus a b  = Var plus_id  `App` a `App` b
         times a b = Var times_id `App` a `App` b
@@ -433,30 +440,28 @@ mkIntegerLit i
 
 mkSmallIntegerLit i = mkConApp smallIntegerDataCon [mkIntLit i]
 
-mkStringLit   :: String       -> DsM CoreExpr
-mkStringLit str        = mkStringLitFS (_PK_ str)
+mkStringLit str        = mkStringLitFS (mkFastString str)
 
-mkStringLitFS :: FAST_STRING  -> DsM CoreExpr
 mkStringLitFS str
-  | _NULL_ str
+  | nullFastString str
   = returnDs (mkNilExpr charTy)
 
-  | _LENGTH_ str == 1
+  | lengthFS str == 1
   = let
-       the_char = mkConApp charDataCon [mkLit (MachChar (_HEAD_INT_ str))]
+       the_char = mkCharExpr (headIntFS str)
     in
     returnDs (mkConsExpr charTy the_char (mkNilExpr charTy))
 
-  | all safeChar chars
-  = dsLookupGlobalValue unpackCStringName      `thenDs` \ unpack_id ->
+  | all safeChar int_chars
+  = dsLookupGlobalId unpackCStringName `thenDs` \ unpack_id ->
     returnDs (App (Var unpack_id) (Lit (MachStr str)))
 
   | otherwise
-  = dsLookupGlobalValue unpackCStringUtf8Name  `thenDs` \ unpack_id ->
-    returnDs (App (Var unpack_id) (Lit (MachStr (_PK_ (stringToUtf8 chars)))))
+  = dsLookupGlobalId unpackCStringUtf8Name     `thenDs` \ unpack_id ->
+    returnDs (App (Var unpack_id) (Lit (MachStr (mkFastString (intsToUtf8 int_chars)))))
 
   where
-    chars = _UNPK_INT_ str
+    int_chars = unpackIntFS str
     safeChar c = c >= 1 && c <= 0xFF
 \end{code}
 
@@ -493,19 +498,34 @@ mkSelectorBinds (VarPat v) val_expr
 
 mkSelectorBinds pat val_expr
   | isSingleton binders || is_simple_pat pat
-  = newSysLocalDs (exprType val_expr)  `thenDs` \ val_var ->
-
-       -- For the error message we don't use mkErrorAppDs to avoid
-       -- duplicating the string literal each time
-    newSysLocalDs stringTy                     `thenDs` \ msg_var ->
-    getSrcLocDs                                        `thenDs` \ src_loc ->
-    let
-       full_msg = showSDoc (hcat [ppr src_loc, text "|", ppr pat])
-    in
-    mkStringLit full_msg                       `thenDs` \ core_msg -> 
-    mapDs (mk_bind val_var msg_var) binders    `thenDs` \ binds ->
+  =    -- 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
+    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 ->
     returnDs ( (val_var, val_expr) : 
-              (msg_var, core_msg) :
+              (err_var, err_expr) :
               binds )
 
 
@@ -520,43 +540,73 @@ mkSelectorBinds pat val_expr
     in
     returnDs ( (tuple_var, tuple_expr) : map mk_tup_bind binders )
   where
-    binders    = collectTypedPatBinders pat
+    binders    = collectPatBinders pat
     local_tuple = mkTupleExpr binders
     tuple_ty    = exprType local_tuple
 
-    mk_bind scrut_var msg_var bndr_var
-    -- (mk_bind sv bv) generates
-    --         bv = case sv of { pat -> bv; other -> error-msg }
+    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
-        binder_ty = idType bndr_var
-        error_expr = mkApps (Var iRREFUT_PAT_ERROR_ID) [Type binder_ty, Var msg_var]
+        error_expr = mkCoerce (idType bndr_var) (Var err_var)
 
-    is_simple_pat (TuplePat ps Boxed)  = all is_triv_pat ps
-    is_simple_pat (ConPat _ _ _ _ ps)  = all is_triv_pat ps
-    is_simple_pat (VarPat _)          = True
-    is_simple_pat (RecPat _ _ _ _ ps)  = and [is_triv_pat p | (_,p,_) <- ps]
-    is_simple_pat other                       = False
+    is_simple_pat (TuplePat ps Boxed)    = all is_triv_pat ps
+    is_simple_pat (ConPatOut _ ps _ _ _) = all is_triv_pat (hsConArgs ps)
+    is_simple_pat (VarPat _)            = True
+    is_simple_pat (ParPat p)            = is_simple_pat p
+    is_simple_pat other                         = False
 
     is_triv_pat (VarPat v)  = True
     is_triv_pat (WildPat _) = True
+    is_triv_pat (ParPat p)  = is_triv_pat p
     is_triv_pat other       = False
 \end{code}
 
 
-@mkTupleExpr@ builds a tuple; the inverse to @mkTupleSelector@.  If it
-has only one element, it is the identity function.
+%************************************************************************
+%*                                                                     *
+               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 
+  = 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
+chunkify xs
+  | n_xs <= mAX_TUPLE_SIZE = [xs]
+  | otherwise             = 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
 
-mkTupleExpr []  = Var unitDataConId
-mkTupleExpr [id] = Var id
-mkTupleExpr ids         = mkConApp (tupleCon Boxed (length ids))
-                           (map (Type . idType) ids ++ [ Var i | i <- ids ])
+    split [] = []
+    split xs = take chunk_size xs : split (drop chunk_size xs)
 \end{code}
 
 
@@ -569,6 +619,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
@@ -576,13 +639,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 = [mkTupleTy Boxed (length gp) (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}
 
 
@@ -601,6 +668,33 @@ 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
+                           
+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}