%
+% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
-\section[DsUtils]{Utilities for desugaring}
+
+Utilities for desugaring
This module exports some utility functions of no great interest.
\begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
module DsUtils (
EquationInfo(..),
firstPat, shiftEqns,
- mkDsLet, mkDsLets,
+ mkDsLet, mkDsLets, mkDsApp, mkDsApps,
MatchResult(..), CanItFail(..),
cantFailMatchResult, alwaysFailMatchResult,
extractMatchResult, combineMatchResults,
adjustMatchResult, adjustMatchResultDs,
mkCoLetMatchResult, mkGuardedMatchResult,
- matchCanFail,
+ matchCanFail, mkEvalMatchResult,
mkCoPrimCaseMatchResult, mkCoAlgCaseMatchResult,
wrapBind, wrapBinds,
dsSyntaxTable, lookupEvidence,
- selectSimpleMatchVarL, selectMatchVars, selectMatchVar
+ selectSimpleMatchVarL, selectMatchVars, selectMatchVar,
+ mkTickBox, mkOptTickBox, mkBinaryTickBox
) where
#include "HsVersions.h"
import {-# SOURCE #-} DsExpr( dsExpr )
import HsSyn
-import TcHsSyn ( hsPatType )
+import TcHsSyn
import CoreSyn
-import Constants ( mAX_TUPLE_SIZE )
+import Constants
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(..), mkStringLit, inIntRange, tARGET_MAX_INT )
-import TyCon ( isNewTyCon, tyConDataCons )
-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,
- isPArrFakeCon )
-import BasicTypes ( Boxity(..) )
-import UniqSet ( mkUniqSet, minusUniqSet, isEmptyUniqSet )
-import UniqSupply ( splitUniqSupply, uniqFromSupply, uniqsFromSupply )
-import PrelNames ( unpackCStringName, unpackCStringUtf8Name,
- plusIntegerName, timesIntegerName, smallIntegerDataConName,
- lengthPName, indexPName )
+import CoreUtils
+import MkId
+import Id
+import Var
+import Name
+import Literal
+import TyCon
+import DataCon
+import Type
+import Coercion
+import TysPrim
+import TysWiredIn
+import BasicTypes
+import UniqSet
+import UniqSupply
+import PrelNames
import Outputable
-import SrcLoc ( Located(..), unLoc )
-import Util ( isSingleton, zipEqual, sortWith )
-import ListSetOps ( assocDefault )
+import SrcLoc
+import Util
+import ListSetOps
import FastString
-import Data.Char ( ord )
+import StaticFlags
+
+import Data.Char
-#ifdef DEBUG
-import Util ( notNull ) -- Used in an assertion
-#endif
+infixl 4 `mkDsApp`, `mkDsApps`
\end{code}
\begin{code}
mkDsLet :: CoreBind -> CoreExpr -> CoreExpr
-mkDsLet (NonRec bndr rhs) body
- | isUnLiftedType (idType bndr)
+mkDsLet (NonRec bndr rhs) body -- See Note [CoreSyn let/app invariant]
+ | isUnLiftedType (idType bndr) && not (exprOkForSpeculation rhs)
= Case rhs bndr (exprType body) [(DEFAULT,[],body)]
mkDsLet bind body
= Let bind body
mkDsLets :: [CoreBind] -> CoreExpr -> CoreExpr
mkDsLets binds body = foldr mkDsLet body binds
+
+-----------
+mkDsApp :: CoreExpr -> CoreExpr -> CoreExpr
+-- Check the invariant that the arg of an App is ok-for-speculation if unlifted
+-- See CoreSyn Note [CoreSyn let/app invariant]
+mkDsApp fun (Type ty) = App fun (Type ty)
+mkDsApp fun arg = mk_val_app fun arg arg_ty res_ty
+ where
+ (arg_ty, res_ty) = splitFunTy (exprType fun)
+
+-----------
+mkDsApps :: CoreExpr -> [CoreExpr] -> CoreExpr
+-- Slightly more efficient version of (foldl mkDsApp)
+mkDsApps fun args
+ = go fun (exprType fun) args
+ where
+ go fun fun_ty [] = fun
+ go fun fun_ty (Type ty : args) = go (App fun (Type ty)) (applyTy fun_ty ty) args
+ go fun fun_ty (arg : args) = go (mk_val_app fun arg arg_ty res_ty) res_ty args
+ where
+ (arg_ty, res_ty) = splitFunTy fun_ty
+-----------
+mk_val_app fun arg arg_ty res_ty -- See Note [CoreSyn let/app invariant]
+ | not (isUnLiftedType arg_ty) || exprOkForSpeculation arg
+ = App fun arg -- The vastly common case
+
+mk_val_app (Var f `App` Type ty1 `App` Type ty2 `App` arg1) arg2 _ res_ty
+ | f == seqId -- Note [Desugaring seq]
+ = Case arg1 (mkWildId ty1) res_ty [(DEFAULT,[],arg2)]
+
+mk_val_app fun arg arg_ty res_ty
+ = Case arg (mkWildId arg_ty) res_ty [(DEFAULT,[],App fun (Var arg_id))]
+ where
+ arg_id = mkWildId arg_ty -- Lots of shadowing, but it doesn't matter,
+ -- because 'fun ' should not have a free wild-id
\end{code}
+Note [Desugaring seq] cf Trac #1031
+~~~~~~~~~~~~~~~~~~~~~
+ f x y = x `seq` (y `seq` (# x,y #))
+
+The [CoreSyn let/app invariant] means that, other things being equal, because
+the argument to the outer 'seq' has an unlifted type, we'll use call-by-value thus:
+
+ f x y = case (y `seq` (# x,y #)) of v -> x `seq` v
+
+But that is bad for two reasons:
+ (a) we now evaluate y before x, and
+ (b) we can't bind v to an unboxed pair
+
+Seq is very, very special! So we recognise it right here, and desugar to
+ case x of _ -> case y of _ -> (# x,y #)
+
+The special case would be valid for all calls to 'seq', but it's only *necessary*
+for ones whose second argument has an unlifted type. So we only catch the latter
+case here, to avoid unnecessary tests.
+
%************************************************************************
%* *
\begin{code}
selectSimpleMatchVarL :: LPat Id -> DsM Id
-selectSimpleMatchVarL pat = selectMatchVar (unLoc pat) (hsPatType pat)
+selectSimpleMatchVarL pat = selectMatchVar (unLoc 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
+--
+-- OLD, but interesting note:
+-- 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 (BangPat pat) pat_ty = selectMatchVar (unLoc pat) pat_ty
-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
+-- Then we must not choose (x::Int) as the matching variable!
+-- And nowadays we won't, because the (x::Int) will be wrapped in a CoPat
+
+selectMatchVars :: [Pat Id] -> DsM [Id]
+selectMatchVars ps = mapM selectMatchVar ps
+
+selectMatchVar (BangPat pat) = selectMatchVar (unLoc pat)
+selectMatchVar (LazyPat pat) = selectMatchVar (unLoc pat)
+selectMatchVar (ParPat pat) = selectMatchVar (unLoc pat)
+selectMatchVar (VarPat var) = return var
+selectMatchVar (AsPat var pat) = return (unLoc var)
+selectMatchVar other_pat = newSysLocalDs (hsPatType other_pat)
+ -- OK, better make up one...
\end{code}
\begin{code}
firstPat :: EquationInfo -> Pat Id
-firstPat eqn = head (eqn_pats eqn)
+firstPat eqn = ASSERT( notNull (eqn_pats eqn) ) head (eqn_pats eqn)
shiftEqns :: [EquationInfo] -> [EquationInfo]
-- Drop the first pattern in each equation
combineMatchResults match_result1@(MatchResult CantFail body_fn1) match_result2
= match_result1
-adjustMatchResult :: (CoreExpr -> CoreExpr) -> MatchResult -> MatchResult
+adjustMatchResult :: DsWrapper -> MatchResult -> MatchResult
adjustMatchResult encl_fn (MatchResult can_it_fail body_fn)
= MatchResult can_it_fail (\fail -> body_fn fail `thenDs` \ body ->
returnDs (encl_fn body))
[(DEFAULT, [], body)]
mkCoLetMatchResult :: CoreBind -> MatchResult -> MatchResult
-mkCoLetMatchResult bind match_result
- = adjustMatchResult (mkDsLet bind) match_result
+mkCoLetMatchResult bind = adjustMatchResult (mkDsLet bind)
+
+mkEvalMatchResult :: Id -> Type -> MatchResult -> MatchResult
+mkEvalMatchResult var ty
+ = adjustMatchResult (\e -> Case (Var var) var ty [(DEFAULT, [], e)])
mkGuardedMatchResult :: CoreExpr -> MatchResult -> MatchResult
mkGuardedMatchResult pred_expr (MatchResult can_it_fail body_fn)
-- the scrutinised Id to be sufficiently refined to have a TyCon in it]
-- Stuff for newtype
- (con1, arg_ids1, match_result1) = head match_alts
- arg_id1 = head arg_ids1
- newtype_rhs = mkNewTypeBody tycon (idType arg_id1) (Var var)
+ (con1, arg_ids1, match_result1) = ASSERT( notNull match_alts ) head match_alts
+ arg_id1 = ASSERT( notNull arg_ids1 ) head arg_ids1
+ var_ty = idType var
+ (tc, ty_args) = splitNewTyConApp var_ty
+ newtype_rhs = unwrapNewTypeBody tc ty_args (Var var)
-- Stuff for data types
data_cons = tyConDataCons tycon
--
-- So to get the type of 'v', use the pattern not the rhs. Often more
-- efficient too.
- newSysLocalDs (hsPatType pat) `thenDs` \ val_var ->
+ newSysLocalDs (hsLPatType 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
(Var bndr_var) error_expr `thenDs` \ rhs_expr ->
returnDs (bndr_var, rhs_expr)
where
- error_expr = mkCoerce (idType bndr_var) (Var err_var)
+ error_expr = mkCoerce co (Var err_var)
+ co = mkUnsafeCoercion (exprType (Var err_var)) (idType bndr_var)
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_simple_pat (TuplePat ps Boxed _) = all is_triv_lpat ps
+ is_simple_pat (ConPatOut{ pat_args = ps }) = all is_triv_lpat (hsConPatArgs 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)
[(DataAlt (tupleCon Boxed (length vars)), vars, Var the_var)]
\end{code}
-
%************************************************************************
%* *
\subsection[mkFailurePair]{Code for pattern-matching and other failures}
ty = exprType expr
\end{code}
-
+\begin{code}
+mkOptTickBox :: Maybe (Int,[Id]) -> CoreExpr -> DsM CoreExpr
+mkOptTickBox Nothing e = return e
+mkOptTickBox (Just (ix,ids)) e = mkTickBox ix ids e
+
+mkTickBox :: Int -> [Id] -> CoreExpr -> DsM CoreExpr
+mkTickBox ix vars e = do
+ uq <- newUnique
+ mod <- getModuleDs
+ let tick | opt_Hpc = mkTickBoxOpId uq mod ix
+ | otherwise = mkBreakPointOpId uq mod ix
+ uq2 <- newUnique
+ let occName = mkVarOcc "tick"
+ let name = mkInternalName uq2 occName noSrcSpan -- use mkSysLocal?
+ let var = Id.mkLocalId name realWorldStatePrimTy
+ scrut <-
+ if opt_Hpc
+ then return (Var tick)
+ else do
+ let tickVar = Var tick
+ let tickType = mkFunTys (map idType vars) realWorldStatePrimTy
+ let scrutApTy = App tickVar (Type tickType)
+ return (mkApps scrutApTy (map Var vars) :: Expr Id)
+ return $ Case scrut var ty [(DEFAULT,[],e)]
+ where
+ ty = exprType e
+
+mkBinaryTickBox :: Int -> Int -> CoreExpr -> DsM CoreExpr
+mkBinaryTickBox ixT ixF e = do
+ mod <- getModuleDs
+ uq <- newUnique
+ mod <- getModuleDs
+ let bndr1 = mkSysLocal FSLIT("t1") uq boolTy
+ falseBox <- mkTickBox ixF [] $ Var falseDataConId
+ trueBox <- mkTickBox ixT [] $ Var trueDataConId
+ return $ Case e bndr1 boolTy
+ [ (DataAlt falseDataCon, [], falseBox)
+ , (DataAlt trueDataCon, [], trueBox)
+ ]
+\end{code}