\begin{code}
module DsUtils (
- CanItFail(..), EquationInfo(..), MatchResult(..),
- EqnNo, EqnSet,
-
- tidyLitPat, tidyNPat,
-
- mkDsLet,
-
- cantFailMatchResult, extractMatchResult,
- combineMatchResults,
- adjustMatchResult, adjustMatchResultDs,
- mkCoLetsMatchResult, mkGuardedMatchResult,
+ 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,
- mkStringLit, mkStringLitFS, mkIntegerExpr,
+ mkStringExpr, mkStringExprFS, mkIntegerExpr,
mkSelectorBinds, mkTupleExpr, mkTupleSelector,
mkTupleType, mkTupleCase, mkBigCoreTup,
mkCoreTup, mkCoreTupTy,
- dsReboundNames, lookupReboundName,
+ dsSyntaxTable, lookupEvidence,
- selectMatchVar
+ selectSimpleMatchVarL, selectMatchVars
) where
#include "HsVersions.h"
import {-# SOURCE #-} DsExpr( dsExpr )
import HsSyn
-import TcHsSyn ( TypecheckedPat, hsPatType )
+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(..), inIntRange, tARGET_MAX_INT )
+import Literal ( Literal(..), mkStringLit, inIntRange, tARGET_MAX_INT )
import TyCon ( isNewTyCon, tyConDataCons )
-import DataCon ( DataCon, dataConSourceArity )
-import Type ( mkFunTy, isUnLiftedType, Type, splitTyConApp )
-import TcType ( tcTyConAppTyCon, isIntTy, isFloatTy, isDoubleTy )
+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,
- floatDataCon,
- doubleDataCon,
- stringTy, isPArrFakeCon )
+ isPArrFakeCon )
import BasicTypes ( Boxity(..) )
-import UniqSet ( mkUniqSet, minusUniqSet, isEmptyUniqSet, UniqSet )
+import UniqSet ( mkUniqSet, minusUniqSet, isEmptyUniqSet )
import UniqSupply ( splitUniqSupply, uniqFromSupply, uniqsFromSupply )
import PrelNames ( unpackCStringName, unpackCStringUtf8Name,
plusIntegerName, timesIntegerName, smallIntegerDataConName,
lengthPName, indexPName )
import Outputable
-import UnicodeUtil ( intsToUtf8, stringToUtf8 )
-import Util ( isSingleton, notNull, zipEqual )
+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}
%************************************************************************
\begin{code}
-dsReboundNames :: ReboundNames Id
+dsSyntaxTable :: SyntaxTable Id
-> DsM ([CoreBind], -- Auxiliary bindings
[(Name,Id)]) -- Maps the standard name to its value
-dsReboundNames rebound_ids
+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))
-
-lookupReboundName :: [(Name,Id)] -> Name -> CoreExpr
-lookupReboundName prs std_name
- = Var (assocDefault (mk_panic std_name) prs std_name)
+ 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 "dsReboundNames" (ptext SLIT("Not found:") <+> ppr std_name)
-\end{code}
-
-
-%************************************************************************
-%* *
-\subsection{Tidying lit pats}
-%* *
-%************************************************************************
-
-\begin{code}
-tidyLitPat :: HsLit -> TypecheckedPat -> TypecheckedPat
-tidyLitPat (HsChar c) pat = mkCharLitPat c
-tidyLitPat lit pat = pat
-
-tidyNPat :: HsLit -> Type -> TypecheckedPat -> TypecheckedPat
-tidyNPat (HsString s) _ pat
- | 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
-
-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
- | otherwise = default_pat
-
- where
- mk_int (HsInteger i _) = HsIntPrim i
-
- 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_panic std_name = pprPanic "dsSyntaxTable" (ptext SLIT("Not found:") <+> ppr std_name)
\end{code}
\begin{code}
mkDsLet :: CoreBind -> CoreExpr -> CoreExpr
mkDsLet (NonRec bndr rhs) body
- | isUnLiftedType (idType bndr) = Case rhs bndr [(DEFAULT,[],body)]
+ | isUnLiftedType (idType bndr)
+ = Case rhs bndr (exprType body) [(DEFAULT,[],body)]
mkDsLet bind body
= Let bind body
otherwise, make one up.
\begin{code}
-selectMatchVar :: TypecheckedPat -> DsM Id
-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...
+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 (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}
worthy of a type synonym and a few handy functions.
\begin{code}
+firstPat :: EquationInfo -> Pat Id
+firstPat eqn = head (eqn_pats eqn)
-type EqnNo = Int
-type EqnSet = UniqSet EqnNo
-
-data EquationInfo
- = EqnInfo
- EqnNo -- The number of the equation
-
- DsMatchContext -- The context info is used when producing warnings
- -- about shadowed patterns. It's the context
- -- of the *first* thing matched in this group.
- -- Should perhaps be a list of them all!
-
- [TypecheckedPat] -- The patterns for an eqn
-
- MatchResult -- Encapsulates the guards and bindings
-\end{code}
-
-\begin{code}
-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
+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)
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 ->
= 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)
-mkCoLetsMatchResult :: [CoreBind] -> MatchResult -> MatchResult
-mkCoLetsMatchResult binds match_result
- = adjustMatchResult (mkDsLets binds) match_result
+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
+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)
returnDs (mkIfThenElse pred_expr body fail))
mkCoPrimCaseMatchResult :: Id -- Scrutinee
+ -> Type -- Type of the case
-> [(Literal, MatchResult)] -- Alternatives
-> MatchResult
-mkCoPrimCaseMatchResult var match_alts
+mkCoPrimCaseMatchResult var ty match_alts
= MatchResult CanFail mk_case
where
mk_case fail
- = mappM (mk_alt fail) match_alts `thenDs` \ alts ->
- returnDs (Case (Var var) var ((DEFAULT, [], fail) : alts))
+ = 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 match_alts
+mkCoAlgCaseMatchResult var ty match_alts
| isNewTyCon tycon -- Newtype case; use a let
- = ASSERT( null (tail match_alts) && null (tail arg_ids) )
- mkCoLetsMatchResult [NonRec arg_id newtype_rhs] match_result
+ = 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
- -- Common stuff
- scrut_ty = idType var
- tycon = tcTyConAppTyCon scrut_ty -- Newtypes must be opaque here
+ 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
- (_, arg_ids, match_result) = head match_alts
- arg_id = head arg_ids
- newtype_rhs = mkNewTypeBody tycon (idType arg_id) (Var var)
+ (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
= CanFail
wild_var = mkWildId (idType var)
- mk_case fail = mappM (mk_alt fail) match_alts `thenDs` \ alts ->
- returnDs (Case (Var var) wild_var (mk_default fail ++ alts))
+ 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 ->
-- Stuff for parallel arrays
--
- -- * the following is to desugar cases over fake constructors for
+ -- * 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
+ -- * 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
mk_parrCase fail =
dsLookupGlobalId lengthPName `thenDs` \lengthP ->
unboxAlt `thenDs` \alt ->
- returnDs (Case (len lengthP) (mkWildId intTy) [alt])
+ returnDs (Case (len lengthP) (mkWildId intTy) ty [alt])
where
elemTy = case splitTyConApp (idType var) of
(_, [elemTy]) -> elemTy
--
unboxAlt =
newSysLocalDs intPrimTy `thenDs` \l ->
- dsLookupGlobalId indexPName `thenDs` \indexP ->
- mappM (mkAlt indexP) match_alts `thenDs` \alts ->
- returnDs (DataAlt intDataCon, [l], (Case (Var l) wild (dft : alts)))
+ 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)
-> 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)))
+ 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}
%************************************************************************
\begin{code}
-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
+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)]
mkSmallIntegerLit small_integer_data_con i = mkConApp small_integer_data_con [mkIntLit i]
-mkStringLit str = mkStringLitFS (mkFastString str)
+mkStringExpr str = mkStringExprFS (mkFastString str)
-mkStringLitFS str
- | nullFastString str
+mkStringExprFS str
+ | nullFS str
= returnDs (mkNilExpr charTy)
| lengthFS str == 1
= let
- the_char = mkCharExpr (headIntFS str)
+ the_char = mkCharExpr (headFS str)
in
returnDs (mkConsExpr charTy the_char (mkNilExpr charTy))
- | all safeChar int_chars
+ | 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 (mkFastString (intsToUtf8 int_chars)))))
+ returnDs (App (Var unpack_id) (Lit (MachStr str)))
where
- int_chars = unpackIntFS str
- safeChar c = c >= 1 && c <= 0xFF
+ chars = unpackFS str
+ safeChar c = ord c >= 1 && ord c <= 0x7F
\end{code}
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)
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_pat (VarPat _) = True
- is_simple_pat (ParPat p) = is_simple_pat p
- is_simple_pat other = False
+ 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_pat p
+ is_triv_pat (ParPat p) = is_triv_lpat p
is_triv_pat other = False
\end{code}
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)]
+-- One branch no refinement?
+ = Case scrut scrut_var (exprType body) [(DataAlt (tupleCon Boxed (length vars)), vars, body)]
\end{code}
%************************************************************************
mkCoreSel vars the_var scrut_var scrut
= ASSERT( notNull vars )
- Case scrut scrut_var
+ Case scrut scrut_var (idType the_var)
[(DataAlt (tupleCon Boxed (length vars)), vars, Var the_var)]
\end{code}