summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDavid Waern <david.waern@gmail.com>2011-11-29 02:09:28 +0100
committerDavid Waern <david.waern@gmail.com>2011-11-29 02:09:28 +0100
commite26443e75fdf33301df22d6da4911e888bb10282 (patch)
tree73bf733972ee973e0d5011bcd94c96a908753f56 /compiler
parentfdf98d6255deba9582dd475e6953b1bb49fba660 (diff)
parent36f8cabecd5a8320ee174abb56e73841a5cbc9c7 (diff)
downloadhaskell-e26443e75fdf33301df22d6da4911e888bb10282.tar.gz
Merge branch 'master' of http://darcs.haskell.org/ghc
Diffstat (limited to 'compiler')
-rw-r--r--compiler/basicTypes/Var.lhs5
-rw-r--r--compiler/cmm/PprC.hs3
-rw-r--r--compiler/codeGen/CgForeignCall.hs209
-rw-r--r--compiler/codeGen/StgCmmForeign.hs191
-rw-r--r--compiler/coreSyn/CoreUtils.lhs7
-rw-r--r--compiler/deSugar/Desugar.lhs8
-rw-r--r--compiler/deSugar/DsForeign.lhs79
-rw-r--r--compiler/llvmGen/LlvmCodeGen/CodeGen.hs1
-rw-r--r--compiler/main/DynFlags.hs2
-rw-r--r--compiler/main/HscMain.hs13
-rw-r--r--compiler/main/StaticFlagParser.hs1
-rw-r--r--compiler/main/StaticFlags.hs6
-rw-r--r--compiler/parser/Lexer.x5
-rw-r--r--compiler/parser/Parser.y.pp4
-rw-r--r--compiler/prelude/ForeignCall.lhs17
-rw-r--r--compiler/typecheck/TcCanonical.lhs336
-rw-r--r--compiler/typecheck/TcForeign.lhs1
-rw-r--r--compiler/typecheck/TcHsSyn.lhs70
-rw-r--r--compiler/typecheck/TcInteract.lhs365
-rw-r--r--compiler/typecheck/TcRnDriver.lhs1
-rw-r--r--compiler/typecheck/TcRnMonad.lhs2
-rw-r--r--compiler/typecheck/TcRnTypes.lhs21
-rw-r--r--compiler/typecheck/TcSMonad.lhs190
-rw-r--r--compiler/typecheck/TcSimplify.lhs6
-rw-r--r--compiler/types/Coercion.lhs1
-rw-r--r--compiler/utils/UniqFM.lhs13
-rw-r--r--compiler/vectorise/Vectorise/Builtins.hs3
-rw-r--r--compiler/vectorise/Vectorise/Builtins/Base.hs8
-rw-r--r--compiler/vectorise/Vectorise/Builtins/Initialise.hs30
-rw-r--r--compiler/vectorise/Vectorise/Env.hs7
-rw-r--r--compiler/vectorise/Vectorise/Monad.hs2
-rw-r--r--compiler/vectorise/Vectorise/Monad/Global.hs41
32 files changed, 941 insertions, 707 deletions
diff --git a/compiler/basicTypes/Var.lhs b/compiler/basicTypes/Var.lhs
index 1692520858..8e31fef8ea 100644
--- a/compiler/basicTypes/Var.lhs
+++ b/compiler/basicTypes/Var.lhs
@@ -85,6 +85,8 @@ import FastTypes
import FastString
import Outputable
+import StaticFlags ( opt_SuppressVarKinds )
+
import Data.Data
\end{code}
@@ -211,7 +213,8 @@ After CoreTidy, top-level LocalIds are turned into GlobalIds
\begin{code}
instance Outputable Var where
ppr var = ifPprDebug (text "(") <+> ppr (varName var) <+> ifPprDebug (brackets (ppr_debug var))
- <+> ifPprDebug (text "::" <+> ppr (tyVarKind var) <+> text ")")
+ <+> if (not opt_SuppressVarKinds) then ifPprDebug (text "::" <+> ppr (tyVarKind var) <+> text ")")
+ else empty
ppr_debug :: Var -> SDoc
ppr_debug (TyVar {}) = ptext (sLit "tv")
diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs
index a2ffd18649..4f8a061bdd 100644
--- a/compiler/cmm/PprC.hs
+++ b/compiler/cmm/PprC.hs
@@ -254,7 +254,7 @@ pprStmt platform stmt = case stmt of
pprCFunType :: SDoc -> CCallConv -> [HintedCmmFormal] -> [HintedCmmActual] -> SDoc
pprCFunType ppr_fn cconv ress args
= res_type ress <+>
- parens (text (ccallConvAttribute cconv) <> ppr_fn) <>
+ parens (ccallConvAttribute cconv <> ppr_fn) <>
parens (commafy (map arg_type args))
where
res_type [] = ptext (sLit "void")
@@ -845,6 +845,7 @@ pprCall platform ppr_fn cconv results args _
-- change in the future...
is_cishCC :: CCallConv -> Bool
is_cishCC CCallConv = True
+is_cishCC CApiConv = True
is_cishCC StdCallConv = True
is_cishCC CmmCallConv = False
is_cishCC PrimCallConv = False
diff --git a/compiler/codeGen/CgForeignCall.hs b/compiler/codeGen/CgForeignCall.hs
index 295d76344a..d96e9f8cfc 100644
--- a/compiler/codeGen/CgForeignCall.hs
+++ b/compiler/codeGen/CgForeignCall.hs
@@ -6,13 +6,6 @@
--
-----------------------------------------------------------------------------
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
module CgForeignCall (
cgForeignCall,
emitForeignCall,
@@ -50,32 +43,32 @@ import Control.Monad
-- Code generation for Foreign Calls
cgForeignCall
- :: [HintedCmmFormal] -- where to put the results
- -> ForeignCall -- the op
- -> [StgArg] -- arguments
- -> StgLiveVars -- live vars, in case we need to save them
- -> Code
+ :: [HintedCmmFormal] -- where to put the results
+ -> ForeignCall -- the op
+ -> [StgArg] -- arguments
+ -> StgLiveVars -- live vars, in case we need to save them
+ -> Code
cgForeignCall results fcall stg_args live
- = do
+ = do
reps_n_amodes <- getArgAmodes stg_args
let
- -- Get the *non-void* args, and jiggle them with shimForeignCall
- arg_exprs = [ shimForeignCallArg stg_arg expr
- | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
- nonVoidArg rep]
+ -- Get the *non-void* args, and jiggle them with shimForeignCall
+ arg_exprs = [ shimForeignCallArg stg_arg expr
+ | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
+ nonVoidArg rep]
- arg_hints = zipWith CmmHinted
+ arg_hints = zipWith CmmHinted
arg_exprs (map (typeForeignHint.stgArgType) stg_args)
-- in
emitForeignCall results fcall arg_hints live
emitForeignCall
- :: [HintedCmmFormal] -- where to put the results
- -> ForeignCall -- the op
- -> [CmmHinted CmmExpr] -- arguments
- -> StgLiveVars -- live vars, in case we need to save them
- -> Code
+ :: [HintedCmmFormal] -- where to put the results
+ -> ForeignCall -- the op
+ -> [CmmHinted CmmExpr] -- arguments
+ -> StgLiveVars -- live vars, in case we need to save them
+ -> Code
emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
= do vols <- getVolatileRegs live
@@ -84,34 +77,34 @@ emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
(CmmCallee cmm_target cconv) call_args (Just vols) srt CmmMayReturn
where
(call_args, cmm_target)
- = case target of
- -- If the packageId is Nothing then the label is taken to be in the
- -- package currently being compiled.
- StaticTarget lbl mPkgId
- -> let labelSource
- = case mPkgId of
- Nothing -> ForeignLabelInThisPackage
- Just pkgId -> ForeignLabelInPackage pkgId
- in ( args
- , CmmLit (CmmLabel
- (mkForeignLabel lbl call_size labelSource IsFunction)))
-
- -- A label imported with "foreign import ccall "dynamic" ..."
- -- Note: "dynamic" here doesn't mean "dynamic library".
- -- Read the FFI spec for details.
- DynamicTarget -> case args of
- (CmmHinted fn _):rest -> (rest, fn)
- [] -> panic "emitForeignCall: DynamicTarget []"
-
- -- in the stdcall calling convention, the symbol needs @size appended
- -- to it, where size is the total number of bytes of arguments. We
- -- attach this info to the CLabel here, and the CLabel pretty printer
- -- will generate the suffix when the label is printed.
+ = case target of
+ -- If the packageId is Nothing then the label is taken to be in the
+ -- package currently being compiled.
+ StaticTarget lbl mPkgId
+ -> let labelSource
+ = case mPkgId of
+ Nothing -> ForeignLabelInThisPackage
+ Just pkgId -> ForeignLabelInPackage pkgId
+ in ( args
+ , CmmLit (CmmLabel
+ (mkForeignLabel lbl call_size labelSource IsFunction)))
+
+ -- A label imported with "foreign import ccall "dynamic" ..."
+ -- Note: "dynamic" here doesn't mean "dynamic library".
+ -- Read the FFI spec for details.
+ DynamicTarget -> case args of
+ (CmmHinted fn _):rest -> (rest, fn)
+ [] -> panic "emitForeignCall: DynamicTarget []"
+
+ -- in the stdcall calling convention, the symbol needs @size appended
+ -- to it, where size is the total number of bytes of arguments. We
+ -- attach this info to the CLabel here, and the CLabel pretty printer
+ -- will generate the suffix when the label is printed.
call_size
- | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprType.hintlessCmm) args))
- | otherwise = Nothing
+ | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprType.hintlessCmm) args))
+ | otherwise = Nothing
- -- ToDo: this might not be correct for 64-bit API
+ -- ToDo: this might not be correct for 64-bit API
arg_size rep = max (widthInBytes (typeWidth rep)) wORD_SIZE
@@ -120,14 +113,14 @@ emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
-- which should be used instead of this (the equivalent emitForeignCall
-- is not presently exported.)
emitForeignCall'
- :: Safety
- -> [HintedCmmFormal] -- where to put the results
- -> CmmCallTarget -- the op
- -> [CmmHinted CmmExpr] -- arguments
- -> Maybe [GlobalReg] -- live vars, in case we need to save them
+ :: Safety
+ -> [HintedCmmFormal] -- where to put the results
+ -> CmmCallTarget -- the op
+ -> [CmmHinted CmmExpr] -- arguments
+ -> Maybe [GlobalReg] -- live vars, in case we need to save them
-> C_SRT -- the SRT of the calls continuation
-> CmmReturnInfo
- -> Code
+ -> Code
emitForeignCall' safety results target args vols _srt ret
| not (playSafe safety) = do
temp_args <- load_args_into_temps args
@@ -152,16 +145,16 @@ emitForeignCall' safety results target args vols _srt ret
-- Once that happens, this function will just emit a (CmmSafe srt) call,
-- and the CPS will be the one to convert that
-- to this sequence of three CmmUnsafe calls.
- stmtC (CmmCall (CmmCallee suspendThread CCallConv)
- [ CmmHinted id AddrHint ]
- [ CmmHinted (CmmReg (CmmGlobal BaseReg)) AddrHint
- , CmmHinted (CmmLit (CmmInt (fromIntegral (fromEnum (playInterruptible safety))) wordWidth)) NoHint]
- CmmUnsafe ret)
+ stmtC (CmmCall (CmmCallee suspendThread CCallConv)
+ [ CmmHinted id AddrHint ]
+ [ CmmHinted (CmmReg (CmmGlobal BaseReg)) AddrHint
+ , CmmHinted (CmmLit (CmmInt (fromIntegral (fromEnum (playInterruptible safety))) wordWidth)) NoHint]
+ CmmUnsafe ret)
stmtC (CmmCall temp_target results temp_args CmmUnsafe ret)
- stmtC (CmmCall (CmmCallee resumeThread CCallConv)
- [ CmmHinted new_base AddrHint ]
- [ CmmHinted (CmmReg (CmmLocal id)) AddrHint ]
- CmmUnsafe ret)
+ stmtC (CmmCall (CmmCallee resumeThread CCallConv)
+ [ CmmHinted new_base AddrHint ]
+ [ CmmHinted (CmmReg (CmmLocal id)) AddrHint ]
+ CmmUnsafe ret)
-- Assign the result to BaseReg: we
-- might now have a different Capability!
stmtC (CmmAssign (CmmGlobal BaseReg) (CmmReg (CmmLocal new_base)))
@@ -183,11 +176,11 @@ resumeThread = CmmLit (CmmLabel (mkCmmCodeLabel rtsPackageId (fsLit "resumeThre
load_args_into_temps :: [CmmHinted CmmExpr] -> FCode [CmmHinted CmmExpr]
load_args_into_temps = mapM arg_assign_temp
where arg_assign_temp (CmmHinted e hint) = do
- tmp <- maybe_assign_temp e
- return (CmmHinted tmp hint)
-
+ tmp <- maybe_assign_temp e
+ return (CmmHinted tmp hint)
+
load_target_into_temp :: CmmCallTarget -> FCode CmmCallTarget
-load_target_into_temp (CmmCallee expr conv) = do
+load_target_into_temp (CmmCallee expr conv) = do
tmp <- maybe_assign_temp expr
return (CmmCallee tmp conv)
load_target_into_temp other_target =
@@ -196,13 +189,13 @@ load_target_into_temp other_target =
maybe_assign_temp :: CmmExpr -> FCode CmmExpr
maybe_assign_temp e
| hasNoGlobalRegs e = return e
- | otherwise = do
- -- don't use assignTemp, it uses its own notion of "trivial"
- -- expressions, which are wrong here.
+ | otherwise = do
+ -- don't use assignTemp, it uses its own notion of "trivial"
+ -- expressions, which are wrong here.
-- this is a NonPtr because it only duplicates an existing
- reg <- newTemp (cmmExprType e) --TODO FIXME NOW
- stmtC (CmmAssign (CmmLocal reg) e)
- return (CmmReg (CmmLocal reg))
+ reg <- newTemp (cmmExprType e) --TODO FIXME NOW
+ stmtC (CmmAssign (CmmLocal reg) e)
+ return (CmmReg (CmmLocal reg))
-- -----------------------------------------------------------------------------
-- Save/restore the thread state in the TSO
@@ -218,7 +211,7 @@ emitSaveThreadState = do
emitCloseNursery
-- and save the current cost centre stack in the TSO when profiling:
when opt_SccProfilingOn $
- stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
+ stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
-- CurrentNursery->free = Hp+1;
emitCloseNursery :: Code
@@ -238,7 +231,7 @@ emitLoadThreadState = do
bWord),
-- SpLim = stack->stack + RESERVED_STACK_WORDS;
CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal stack)) stack_STACK)
- rESERVED_STACK_WORDS),
+ rESERVED_STACK_WORDS),
-- HpAlloc = 0;
-- HpAlloc is assumed to be set to non-zero only by a failed
-- a heap check, see HeapStackCheck.cmm:GC_GENERIC
@@ -247,28 +240,28 @@ emitLoadThreadState = do
emitOpenNursery
-- and load the current cost centre stack from the TSO when profiling:
when opt_SccProfilingOn $
- stmtC (CmmStore curCCSAddr
+ stmtC (CmmStore curCCSAddr
(CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) bWord))
emitOpenNursery :: Code
emitOpenNursery = stmtsC [
-- Hp = CurrentNursery->free - 1;
- CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free gcWord) (-1)),
-
- -- HpLim = CurrentNursery->start +
- -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
- CmmAssign hpLim
- (cmmOffsetExpr
- (CmmLoad nursery_bdescr_start bWord)
- (cmmOffset
- (CmmMachOp mo_wordMul [
- CmmMachOp (MO_SS_Conv W32 wordWidth)
- [CmmLoad nursery_bdescr_blocks b32],
- CmmLit (mkIntCLit bLOCK_SIZE)
- ])
- (-1)
- )
- )
+ CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free gcWord) (-1)),
+
+ -- HpLim = CurrentNursery->start +
+ -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
+ CmmAssign hpLim
+ (cmmOffsetExpr
+ (CmmLoad nursery_bdescr_start bWord)
+ (cmmOffset
+ (CmmMachOp mo_wordMul [
+ CmmMachOp (MO_SS_Conv W32 wordWidth)
+ [CmmLoad nursery_bdescr_blocks b32],
+ CmmLit (mkIntCLit bLOCK_SIZE)
+ ])
+ (-1)
+ )
+ )
]
nursery_bdescr_free, nursery_bdescr_start, nursery_bdescr_blocks :: CmmExpr
@@ -286,19 +279,19 @@ closureField :: ByteOff -> ByteOff
closureField off = off + fixedHdrSize * wORD_SIZE
stgSp, stgHp, stgCurrentTSO, stgCurrentNursery :: CmmExpr
-stgSp = CmmReg sp
-stgHp = CmmReg hp
-stgCurrentTSO = CmmReg currentTSO
+stgSp = CmmReg sp
+stgHp = CmmReg hp
+stgCurrentTSO = CmmReg currentTSO
stgCurrentNursery = CmmReg currentNursery
sp, spLim, hp, hpLim, currentTSO, currentNursery, hpAlloc :: CmmReg
-sp = CmmGlobal Sp
-spLim = CmmGlobal SpLim
-hp = CmmGlobal Hp
-hpLim = CmmGlobal HpLim
-currentTSO = CmmGlobal CurrentTSO
-currentNursery = CmmGlobal CurrentNursery
-hpAlloc = CmmGlobal HpAlloc
+sp = CmmGlobal Sp
+spLim = CmmGlobal SpLim
+hp = CmmGlobal Hp
+hpLim = CmmGlobal HpLim
+currentTSO = CmmGlobal CurrentTSO
+currentNursery = CmmGlobal CurrentNursery
+hpAlloc = CmmGlobal HpAlloc
-- -----------------------------------------------------------------------------
-- For certain types passed to foreign calls, we adjust the actual
@@ -308,12 +301,12 @@ hpAlloc = CmmGlobal HpAlloc
shimForeignCallArg :: StgArg -> CmmExpr -> CmmExpr
shimForeignCallArg arg expr
| tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon
- = cmmOffsetB expr arrPtrsHdrSize
+ = cmmOffsetB expr arrPtrsHdrSize
| tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon
- = cmmOffsetB expr arrWordsHdrSize
+ = cmmOffsetB expr arrWordsHdrSize
| otherwise = expr
- where
- -- should be a tycon app, since this is a foreign call
- tycon = tyConAppTyCon (repType (stgArgType arg))
+ where
+ -- should be a tycon app, since this is a foreign call
+ tycon = tyConAppTyCon (repType (stgArgType arg))
diff --git a/compiler/codeGen/StgCmmForeign.hs b/compiler/codeGen/StgCmmForeign.hs
index f07fd6c6bc..78aabd82ce 100644
--- a/compiler/codeGen/StgCmmForeign.hs
+++ b/compiler/codeGen/StgCmmForeign.hs
@@ -6,13 +6,6 @@
--
-----------------------------------------------------------------------------
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
module StgCmmForeign (
cgForeignCall, loadThreadState, saveThreadState,
emitPrimCall, emitCCall,
@@ -52,63 +45,63 @@ import Control.Monad
-- Code generation for Foreign Calls
-----------------------------------------------------------------------------
-cgForeignCall :: [LocalReg] -- r1,r2 where to put the results
- -> [ForeignHint]
- -> ForeignCall -- the op
- -> [StgArg] -- x,y arguments
- -> FCode ()
+cgForeignCall :: [LocalReg] -- r1,r2 where to put the results
+ -> [ForeignHint]
+ -> ForeignCall -- the op
+ -> [StgArg] -- x,y arguments
+ -> FCode ()
-- Emits code for an unsafe foreign call: r1, r2 = foo( x, y, z )
cgForeignCall results result_hints (CCall (CCallSpec target cconv safety)) stg_args
- = do { cmm_args <- getFCallArgs stg_args
+ = do { cmm_args <- getFCallArgs stg_args
; let ((call_args, arg_hints), cmm_target)
= case target of
- StaticTarget lbl mPkgId
- -> let labelSource
- = case mPkgId of
- Nothing -> ForeignLabelInThisPackage
- Just pkgId -> ForeignLabelInPackage pkgId
- size = call_size cmm_args
- in ( unzip cmm_args
- , CmmLit (CmmLabel
- (mkForeignLabel lbl size labelSource IsFunction)))
-
+ StaticTarget lbl mPkgId
+ -> let labelSource
+ = case mPkgId of
+ Nothing -> ForeignLabelInThisPackage
+ Just pkgId -> ForeignLabelInPackage pkgId
+ size = call_size cmm_args
+ in ( unzip cmm_args
+ , CmmLit (CmmLabel
+ (mkForeignLabel lbl size labelSource IsFunction)))
+
DynamicTarget -> case cmm_args of
(fn,_):rest -> (unzip rest, fn)
[] -> panic "cgForeignCall []"
fc = ForeignConvention cconv arg_hints result_hints
call_target = ForeignTarget cmm_target fc
-
- ; srt <- getSRTInfo NoSRT -- SLPJ: Not sure what SRT
+
+ ; srt <- getSRTInfo NoSRT -- SLPJ: Not sure what SRT
-- is right here
-- JD: Does it matter in the new codegen?
; emitForeignCall safety results call_target call_args srt CmmMayReturn }
where
- -- in the stdcall calling convention, the symbol needs @size appended
- -- to it, where size is the total number of bytes of arguments. We
- -- attach this info to the CLabel here, and the CLabel pretty printer
- -- will generate the suffix when the label is printed.
+ -- in the stdcall calling convention, the symbol needs @size appended
+ -- to it, where size is the total number of bytes of arguments. We
+ -- attach this info to the CLabel here, and the CLabel pretty printer
+ -- will generate the suffix when the label is printed.
call_size args
- | StdCallConv <- cconv = Just (sum (map arg_size args))
- | otherwise = Nothing
+ | StdCallConv <- cconv = Just (sum (map arg_size args))
+ | otherwise = Nothing
- -- ToDo: this might not be correct for 64-bit API
+ -- ToDo: this might not be correct for 64-bit API
arg_size (arg, _) = max (widthInBytes $ typeWidth $ cmmExprType arg) wORD_SIZE
emitCCall :: [(CmmFormal,ForeignHint)]
- -> CmmExpr
- -> [(CmmActual,ForeignHint)]
- -> FCode ()
+ -> CmmExpr
+ -> [(CmmActual,ForeignHint)]
+ -> FCode ()
emitCCall hinted_results fn hinted_args
= emitForeignCall PlayRisky results target args
- NoC_SRT -- No SRT b/c we PlayRisky
- CmmMayReturn
+ NoC_SRT -- No SRT b/c we PlayRisky
+ CmmMayReturn
where
(args, arg_hints) = unzip hinted_args
(results, result_hints) = unzip hinted_results
target = ForeignTarget fn fc
fc = ForeignConvention CCallConv arg_hints result_hints
-
+
emitPrimCall :: [CmmFormal] -> CallishMachOp -> [CmmActual] -> FCode ()
emitPrimCall res op args
@@ -138,7 +131,7 @@ emitForeignCall safety results target args _srt _ret
{-
--- THINK ABOUT THIS (used to happen)
+-- THINK ABOUT THIS (used to happen)
-- we might need to load arguments into temporaries before
-- making the call, because certain global registers might
-- overlap with registers that the C calling convention uses
@@ -148,12 +141,12 @@ emitForeignCall safety results target args _srt _ret
-- it's easier to generate the temporaries here.
load_args_into_temps = mapM arg_assign_temp
where arg_assign_temp (e,hint) = do
- tmp <- maybe_assign_temp e
- return (tmp,hint)
+ tmp <- maybe_assign_temp e
+ return (tmp,hint)
-}
-
+
load_target_into_temp :: ForeignTarget -> FCode ForeignTarget
-load_target_into_temp (ForeignTarget expr conv) = do
+load_target_into_temp (ForeignTarget expr conv) = do
tmp <- maybe_assign_temp expr
return (ForeignTarget tmp conv)
load_target_into_temp other_target@(PrimTarget _) =
@@ -162,13 +155,13 @@ load_target_into_temp other_target@(PrimTarget _) =
maybe_assign_temp :: CmmExpr -> FCode CmmExpr
maybe_assign_temp e
| hasNoGlobalRegs e = return e
- | otherwise = do
- -- don't use assignTemp, it uses its own notion of "trivial"
- -- expressions, which are wrong here.
+ | otherwise = do
+ -- don't use assignTemp, it uses its own notion of "trivial"
+ -- expressions, which are wrong here.
-- this is a NonPtr because it only duplicates an existing
- reg <- newTemp (cmmExprType e) --TODO FIXME NOW
- emit (mkAssign (CmmLocal reg) e)
- return (CmmReg (CmmLocal reg))
+ reg <- newTemp (cmmExprType e) --TODO FIXME NOW
+ emit (mkAssign (CmmLocal reg) e)
+ return (CmmReg (CmmLocal reg))
-- -----------------------------------------------------------------------------
-- Save/restore the thread state in the TSO
@@ -183,7 +176,7 @@ saveThreadState =
<*> closeNursery
-- and save the current cost centre stack in the TSO when profiling:
<*> if opt_SccProfilingOn then
- mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS
+ mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS
else mkNop
emitSaveThreadState :: BlockId -> FCode ()
@@ -194,7 +187,7 @@ emitSaveThreadState bid = do
emit closeNursery
-- and save the current cost centre stack in the TSO when profiling:
when opt_SccProfilingOn $
- emit (mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
+ emit (mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
-- CurrentNursery->free = Hp+1;
closeNursery :: CmmAGraph
@@ -205,19 +198,19 @@ loadThreadState tso stack = do
-- tso <- newTemp gcWord -- TODO FIXME NOW
-- stack <- newTemp gcWord -- TODO FIXME NOW
catAGraphs [
- -- tso = CurrentTSO;
- mkAssign (CmmLocal tso) stgCurrentTSO,
- -- stack = tso->stackobj;
- mkAssign (CmmLocal stack) (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_stackobj) bWord),
- -- Sp = stack->sp;
- mkAssign sp (CmmLoad (cmmOffset (CmmReg (CmmLocal stack)) stack_SP) bWord),
- -- SpLim = stack->stack + RESERVED_STACK_WORDS;
- mkAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal stack)) stack_STACK)
- rESERVED_STACK_WORDS),
+ -- tso = CurrentTSO;
+ mkAssign (CmmLocal tso) stgCurrentTSO,
+ -- stack = tso->stackobj;
+ mkAssign (CmmLocal stack) (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_stackobj) bWord),
+ -- Sp = stack->sp;
+ mkAssign sp (CmmLoad (cmmOffset (CmmReg (CmmLocal stack)) stack_SP) bWord),
+ -- SpLim = stack->stack + RESERVED_STACK_WORDS;
+ mkAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal stack)) stack_STACK)
+ rESERVED_STACK_WORDS),
openNursery,
-- and load the current cost centre stack from the TSO when profiling:
if opt_SccProfilingOn then
- mkStore curCCSAddr
+ mkStore curCCSAddr
(CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) ccsType)
else mkNop]
emitLoadThreadState :: LocalReg -> LocalReg -> FCode ()
@@ -226,22 +219,22 @@ emitLoadThreadState tso stack = emit $ loadThreadState tso stack
openNursery :: CmmAGraph
openNursery = catAGraphs [
-- Hp = CurrentNursery->free - 1;
- mkAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free bWord) (-1)),
-
- -- HpLim = CurrentNursery->start +
- -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
- mkAssign hpLim
- (cmmOffsetExpr
- (CmmLoad nursery_bdescr_start bWord)
- (cmmOffset
- (CmmMachOp mo_wordMul [
- CmmMachOp (MO_SS_Conv W32 wordWidth)
- [CmmLoad nursery_bdescr_blocks b32],
- CmmLit (mkIntCLit bLOCK_SIZE)
- ])
- (-1)
- )
- )
+ mkAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free bWord) (-1)),
+
+ -- HpLim = CurrentNursery->start +
+ -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
+ mkAssign hpLim
+ (cmmOffsetExpr
+ (CmmLoad nursery_bdescr_start bWord)
+ (cmmOffset
+ (CmmMachOp mo_wordMul [
+ CmmMachOp (MO_SS_Conv W32 wordWidth)
+ [CmmLoad nursery_bdescr_blocks b32],
+ CmmLit (mkIntCLit bLOCK_SIZE)
+ ])
+ (-1)
+ )
+ )
]
emitOpenNursery :: FCode ()
emitOpenNursery = emit openNursery
@@ -262,18 +255,18 @@ closureField :: ByteOff -> ByteOff
closureField off = off + fixedHdrSize * wORD_SIZE
stgSp, stgHp, stgCurrentTSO, stgCurrentNursery :: CmmExpr
-stgSp = CmmReg sp
-stgHp = CmmReg hp
-stgCurrentTSO = CmmReg currentTSO
+stgSp = CmmReg sp
+stgHp = CmmReg hp
+stgCurrentTSO = CmmReg currentTSO
stgCurrentNursery = CmmReg currentNursery
sp, spLim, hp, hpLim, currentTSO, currentNursery :: CmmReg
-sp = CmmGlobal Sp
-spLim = CmmGlobal SpLim
-hp = CmmGlobal Hp
-hpLim = CmmGlobal HpLim
-currentTSO = CmmGlobal CurrentTSO
-currentNursery = CmmGlobal CurrentNursery
+sp = CmmGlobal Sp
+spLim = CmmGlobal SpLim
+hp = CmmGlobal Hp
+hpLim = CmmGlobal HpLim
+currentTSO = CmmGlobal CurrentTSO
+currentNursery = CmmGlobal CurrentNursery
-- -----------------------------------------------------------------------------
-- For certain types passed to foreign calls, we adjust the actual
@@ -286,18 +279,18 @@ getFCallArgs :: [StgArg] -> FCode [(CmmExpr, ForeignHint)]
-- It's (b) that makes this differ from getNonVoidArgAmodes
getFCallArgs args
- = do { mb_cmms <- mapM get args
- ; return (catMaybes mb_cmms) }
+ = do { mb_cmms <- mapM get args
+ ; return (catMaybes mb_cmms) }
where
- get arg | isVoidRep arg_rep
- = return Nothing
- | otherwise
- = do { cmm <- getArgAmode (NonVoid arg)
- ; return (Just (add_shim arg_ty cmm, hint)) }
- where
- arg_ty = stgArgType arg
- arg_rep = typePrimRep arg_ty
- hint = typeForeignHint arg_ty
+ get arg | isVoidRep arg_rep
+ = return Nothing
+ | otherwise
+ = do { cmm <- getArgAmode (NonVoid arg)
+ ; return (Just (add_shim arg_ty cmm, hint)) }
+ where
+ arg_ty = stgArgType arg
+ arg_rep = typePrimRep arg_ty
+ hint = typeForeignHint arg_ty
add_shim :: Type -> CmmExpr -> CmmExpr
add_shim arg_ty expr
@@ -308,6 +301,6 @@ add_shim arg_ty expr
= cmmOffsetB expr arrWordsHdrSize
| otherwise = expr
- where
+ where
tycon = tyConAppTyCon (repType arg_ty)
- -- should be a tycon app, since this is a foreign call
+ -- should be a tycon app, since this is a foreign call
diff --git a/compiler/coreSyn/CoreUtils.lhs b/compiler/coreSyn/CoreUtils.lhs
index e11acbf563..d3a2ca5cbb 100644
--- a/compiler/coreSyn/CoreUtils.lhs
+++ b/compiler/coreSyn/CoreUtils.lhs
@@ -1282,6 +1282,13 @@ altSize (c,bs,e) = c `seq` varsSize bs + exprSize e
\begin{code}
data CoreStats = CS { cs_tm, cs_ty, cs_co :: Int }
+
+instance Outputable CoreStats where
+ ppr (CS { cs_tm = i1, cs_ty = i2, cs_co = i3 }) =
+ text "size of" <+> vcat [ text "terms =" <+> int i1
+ , text "types =" <+> int i2
+ , text "coercions =" <+> int i3 ]
+
plusCS :: CoreStats -> CoreStats -> CoreStats
plusCS (CS { cs_tm = p1, cs_ty = q1, cs_co = r1 })
(CS { cs_tm = p2, cs_ty = q2, cs_co = r2 })
diff --git a/compiler/deSugar/Desugar.lhs b/compiler/deSugar/Desugar.lhs
index d0713bcf99..cb23075134 100644
--- a/compiler/deSugar/Desugar.lhs
+++ b/compiler/deSugar/Desugar.lhs
@@ -153,14 +153,8 @@ deSugar hsc_env
-- You might think it doesn't matter, but the simplifier brings all top-level
-- things into the in-scope set before simplifying; so we get no unfolding for F#!
- -- Lint result if necessary, and print
-{-
- ; dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared, before opt" $
- (vcat [ pprCoreBindings final_pgm
- , pprRules rules_for_imps ])
--}
-
#ifdef DEBUG
+ -- Debug only as pre-simple-optimisation program may be really big
; endPass dflags CoreDesugar final_pgm rules_for_imps
#endif
; (ds_binds, ds_rules_for_imps, ds_vects)
diff --git a/compiler/deSugar/DsForeign.lhs b/compiler/deSugar/DsForeign.lhs
index 22a4a7bdde..6f9bbc2ef8 100644
--- a/compiler/deSugar/DsForeign.lhs
+++ b/compiler/deSugar/DsForeign.lhs
@@ -125,8 +125,8 @@ dsFImport :: Id
-> Coercion
-> ForeignImport
-> DsM ([Binding], SDoc, SDoc)
-dsFImport id co (CImport cconv safety _ spec) = do
- (ids, h, c) <- dsCImport id co spec cconv safety
+dsFImport id co (CImport cconv safety header spec) = do
+ (ids, h, c) <- dsCImport id co spec cconv safety header
return (ids, h, c)
dsCImport :: Id
@@ -134,8 +134,9 @@ dsCImport :: Id
-> CImportSpec
-> CCallConv
-> Safety
+ -> FastString -- header
-> DsM ([Binding], SDoc, SDoc)
-dsCImport id co (CLabel cid) cconv _ = do
+dsCImport id co (CLabel cid) cconv _ _ = do
let ty = pFst $ coercionKind co
fod = case tyConAppTyCon_maybe ty of
Just tycon
@@ -151,11 +152,11 @@ dsCImport id co (CLabel cid) cconv _ = do
in
return ([(id, rhs')], empty, empty)
-dsCImport id co (CFunction target) cconv@PrimCallConv safety
+dsCImport id co (CFunction target) cconv@PrimCallConv safety _
= dsPrimCall id co (CCall (CCallSpec target cconv safety))
-dsCImport id co (CFunction target) cconv safety
- = dsFCall id co (CCall (CCallSpec target cconv safety))
-dsCImport id co CWrapper cconv _
+dsCImport id co (CFunction target) cconv safety header
+ = dsFCall id co (CCall (CCallSpec target cconv safety)) header
+dsCImport id co CWrapper cconv _ _
= dsFExportDynamic id co cconv
-- For stdcall labels, if the type was a FunPtr or newtype thereof,
@@ -181,8 +182,9 @@ fun_type_arg_stdcall_info _other_conv _
%************************************************************************
\begin{code}
-dsFCall :: Id -> Coercion -> ForeignCall -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
-dsFCall fn_id co fcall = do
+dsFCall :: Id -> Coercion -> ForeignCall -> FastString
+ -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
+dsFCall fn_id co fcall headerFilename = do
let
ty = pFst $ coercionKind co
(tvs, fun_ty) = tcSplitForAllTys ty
@@ -200,10 +202,48 @@ dsFCall fn_id co fcall = do
ccall_uniq <- newUnique
work_uniq <- newUnique
+
+ (fcall', cDoc) <-
+ case fcall of
+ CCall (CCallSpec (StaticTarget cName mPackageId) CApiConv safety) ->
+ do fcall_uniq <- newUnique
+ let wrapperName = mkFastString "ghc_wrapper_" `appendFS`
+ mkFastString (showSDoc (ppr fcall_uniq)) `appendFS`
+ mkFastString "_" `appendFS`
+ cName
+ fcall' = CCall (CCallSpec (StaticTarget wrapperName mPackageId) CApiConv safety)
+ c = include
+ $$ fun_proto <+> braces (cRet <> semi)
+ include
+ | nullFS headerFilename = empty
+ | otherwise = text "#include <" <> ftext headerFilename <> text ">"
+ fun_proto = cResType <+> pprCconv <+> ppr wrapperName <> parens argTypes
+ cRet
+ | isVoidRes = cCall
+ | otherwise = text "return" <+> cCall
+ cCall = ppr cName <> parens argVals
+ raw_res_ty = case tcSplitIOType_maybe io_res_ty of
+ Just (_ioTyCon, res_ty) -> res_ty
+ Nothing -> io_res_ty
+ isVoidRes = raw_res_ty `eqType` unitTy
+ cResType | isVoidRes = text "void"
+ | otherwise = showStgType raw_res_ty
+ pprCconv = ccallConvAttribute CApiConv
+ argTypes
+ | null arg_tys = text "void"
+ | otherwise = hsep $ punctuate comma
+ [ showStgType t <+> char 'a' <> int n
+ | (t, n) <- zip arg_tys [1..] ]
+ argVals = hsep $ punctuate comma
+ [ char 'a' <> int n
+ | (_, n) <- zip arg_tys [1..] ]
+ return (fcall', c)
+ _ ->
+ return (fcall, empty)
let
-- Build the worker
worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
- the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty
+ the_ccall_app = mkFCall ccall_uniq fcall' val_args ccall_result_ty
work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)
work_id = mkSysLocal (fsLit "$wccall") work_uniq worker_ty
@@ -214,7 +254,7 @@ dsFCall fn_id co fcall = do
wrap_rhs' = Cast wrap_rhs co
fn_id_w_inl = fn_id `setIdUnfolding` mkInlineUnfolding (Just (length args)) wrap_rhs'
- return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs')], empty, empty)
+ return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs')], empty, cDoc)
\end{code}
@@ -299,13 +339,11 @@ dsFExport fn_id co ext_name cconv isDyn = do
-- Look at the result type of the exported function, orig_res_ty
-- If it's IO t, return (t, True)
-- If it's plain t, return (t, False)
- (res_ty, -- t
- is_IO_res_ty) <- -- Bool
- case tcSplitIOType_maybe orig_res_ty of
- Just (_ioTyCon, res_ty) -> return (res_ty, True)
- -- The function already returns IO t
- Nothing -> return (orig_res_ty, False)
- -- The function returns t
+ (res_ty, is_IO_res_ty) = case tcSplitIOType_maybe orig_res_ty of
+ -- The function already returns IO t
+ Just (_ioTyCon, res_ty) -> (res_ty, True)
+ -- The function returns t
+ Nothing -> (orig_res_ty, False)
dflags <- getDOpts
return $
@@ -511,10 +549,7 @@ mkFExportCBits dflags c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
int64TyConKey, word64TyConKey]
-- Now we can cook up the prototype for the exported function.
- pprCconv = case cc of
- CCallConv -> empty
- StdCallConv -> text (ccallConvAttribute cc)
- _ -> panic ("mkFExportCBits/pprCconv " ++ showPpr cc)
+ pprCconv = ccallConvAttribute cc
header_bits = ptext (sLit "extern") <+> fun_proto <> semi
diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
index b2ad4c501f..b039d39960 100644
--- a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
+++ b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
@@ -239,6 +239,7 @@ genCall env target res args ret = do
ArchX86_64 -> CC_X86_Stdcc
_ -> CC_Ccc
CCallConv -> CC_Ccc
+ CApiConv -> CC_Ccc
PrimCallConv -> CC_Ccc
CmmCallConv -> panic "CmmCallConv not supported here!"
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index fce75b0bff..9d6d15c0df 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -378,6 +378,7 @@ data ExtensionFlag
| Opt_ForeignFunctionInterface
| Opt_UnliftedFFITypes
| Opt_InterruptibleFFI
+ | Opt_CApiFFI
| Opt_GHCForeignImportPrim
| Opt_ParallelArrays -- Syntactic support for parallel arrays
| Opt_Arrows -- Arrow-notation syntax
@@ -1898,6 +1899,7 @@ xFlags = [
( "ForeignFunctionInterface", Opt_ForeignFunctionInterface, nop ),
( "UnliftedFFITypes", Opt_UnliftedFFITypes, nop ),
( "InterruptibleFFI", Opt_InterruptibleFFI, nop ),
+ ( "CApiFFI", Opt_CApiFFI, nop ),
( "GHCForeignImportPrim", Opt_GHCForeignImportPrim, nop ),
( "LiberalTypeSynonyms", Opt_LiberalTypeSynonyms, nop ),
( "Rank2Types", Opt_Rank2Types, nop ),
diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs
index 4d106bd67e..b4cfbf403f 100644
--- a/compiler/main/HscMain.hs
+++ b/compiler/main/HscMain.hs
@@ -404,14 +404,14 @@ hscTypecheckRename hsc_env mod_summary rdr_module = runHsc hsc_env $ do
-- | Convert a typechecked module to Core
hscDesugar :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts
hscDesugar hsc_env mod_summary tc_result =
- runHsc hsc_env $ hscDesugar' mod_summary tc_result
+ runHsc hsc_env $ hscDesugar' (ms_location mod_summary) tc_result
-hscDesugar' :: ModSummary -> TcGblEnv -> Hsc ModGuts
-hscDesugar' mod_summary tc_result = do
+hscDesugar' :: ModLocation -> TcGblEnv -> Hsc ModGuts
+hscDesugar' mod_location tc_result = do
hsc_env <- getHscEnv
r <- ioMsgMaybe $
{-# SCC "deSugar" #-}
- deSugar hsc_env (ms_location mod_summary) tc_result
+ deSugar hsc_env mod_location tc_result
-- always check -Werror after desugaring, this is the last opportunity for
-- warnings to arise before the backend.
@@ -616,7 +616,7 @@ genericHscBackend compiler tc_result mod_summary mb_old_hash
| HsBootFile <- ms_hsc_src mod_summary =
hscGenBootOutput compiler tc_result mod_summary mb_old_hash
| otherwise = do
- guts <- hscDesugar' mod_summary tc_result
+ guts <- hscDesugar' (ms_location mod_summary) tc_result
hscGenOutput compiler guts mod_summary mb_old_hash
compilerBackend :: HsCompiler a -> TcGblEnv -> Compiler a
@@ -1423,8 +1423,7 @@ hscDeclsWithLocation hsc_env str source linenumber = runHsc hsc_env $ do
let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing,
ml_hi_file = undefined,
ml_obj_file = undefined}
- ds_result <- ioMsgMaybe $ deSugar hsc_env iNTERACTIVELoc tc_gblenv
- handleWarnings
+ ds_result <- hscDesugar' iNTERACTIVELoc tc_gblenv
{- Simplify -}
simpl_mg <- liftIO $ hscSimplify hsc_env ds_result
diff --git a/compiler/main/StaticFlagParser.hs b/compiler/main/StaticFlagParser.hs
index 1db5ef63e0..07eb214f74 100644
--- a/compiler/main/StaticFlagParser.hs
+++ b/compiler/main/StaticFlagParser.hs
@@ -132,6 +132,7 @@ static_flags = [
, Flag "dsuppress-module-prefixes" (PassFlag addOpt)
, Flag "dsuppress-type-applications" (PassFlag addOpt)
, Flag "dsuppress-idinfo" (PassFlag addOpt)
+ , Flag "dsuppress-var-kinds" (PassFlag addOpt)
, Flag "dsuppress-type-signatures" (PassFlag addOpt)
, Flag "dopt-fuel" (AnySuffix addOpt)
, Flag "dtrace-level" (AnySuffix addOpt)
diff --git a/compiler/main/StaticFlags.hs b/compiler/main/StaticFlags.hs
index e89d9b32a4..c2f8674aa9 100644
--- a/compiler/main/StaticFlags.hs
+++ b/compiler/main/StaticFlags.hs
@@ -41,6 +41,7 @@ module StaticFlags (
opt_SuppressTypeApplications,
opt_SuppressIdInfo,
opt_SuppressTypeSignatures,
+ opt_SuppressVarKinds,
-- profiling opts
opt_SccProfilingOn,
@@ -223,6 +224,11 @@ opt_SuppressCoercions
= lookUp (fsLit "-dsuppress-all")
|| lookUp (fsLit "-dsuppress-coercions")
+opt_SuppressVarKinds :: Bool
+opt_SuppressVarKinds
+ = lookUp (fsLit "-dsuppress-all")
+ || lookUp (fsLit "-dsuppress-var-kinds")
+
-- | Suppress module id prefixes on variables.
opt_SuppressModulePrefixes :: Bool
opt_SuppressModulePrefixes
diff --git a/compiler/parser/Lexer.x b/compiler/parser/Lexer.x
index ea01070c94..f235465758 100644
--- a/compiler/parser/Lexer.x
+++ b/compiler/parser/Lexer.x
@@ -457,6 +457,7 @@ data Token
| ITunsafe
| ITstdcallconv
| ITccallconv
+ | ITcapiconv
| ITprimcallconv
| ITmdo
| ITfamily
@@ -642,6 +643,7 @@ reservedWordsFM = listToUFM $
( "unsafe", ITunsafe, bit ffiBit),
( "stdcall", ITstdcallconv, bit ffiBit),
( "ccall", ITccallconv, bit ffiBit),
+ ( "capi", ITcapiconv, bit cApiFfiBit),
( "prim", ITprimcallconv, bit ffiBit),
( "rec", ITrec, bit recBit),
@@ -1754,6 +1756,8 @@ ffiBit :: Int
ffiBit= 0
interruptibleFfiBit :: Int
interruptibleFfiBit = 1
+cApiFfiBit :: Int
+cApiFfiBit = 2
parrBit :: Int
parrBit = 3
arrowsBit :: Int
@@ -1879,6 +1883,7 @@ mkPState flags buf loc =
where
bitmap = ffiBit `setBitIf` xopt Opt_ForeignFunctionInterface flags
.|. interruptibleFfiBit `setBitIf` xopt Opt_InterruptibleFFI flags
+ .|. cApiFfiBit `setBitIf` xopt Opt_CApiFFI flags
.|. parrBit `setBitIf` xopt Opt_ParallelArrays flags
.|. arrowsBit `setBitIf` xopt Opt_Arrows flags
.|. thBit `setBitIf` xopt Opt_TemplateHaskell flags
diff --git a/compiler/parser/Parser.y.pp b/compiler/parser/Parser.y.pp
index de15f1cf2f..8a57504e68 100644
--- a/compiler/parser/Parser.y.pp
+++ b/compiler/parser/Parser.y.pp
@@ -244,6 +244,7 @@ incorrect.
'family' { L _ ITfamily }
'stdcall' { L _ ITstdcallconv }
'ccall' { L _ ITccallconv }
+ 'capi' { L _ ITcapiconv }
'prim' { L _ ITprimcallconv }
'proc' { L _ ITproc } -- for arrow notation extension
'rec' { L _ ITrec } -- for arrow notation extension
@@ -922,6 +923,7 @@ fdecl : 'import' callconv safety fspec
callconv :: { CCallConv }
: 'stdcall' { StdCallConv }
| 'ccall' { CCallConv }
+ | 'capi' { CApiConv }
| 'prim' { PrimCallConv}
safety :: { Safety }
@@ -1394,6 +1396,7 @@ scc_annot :: { Located FastString }
: '_scc_' STRING {% (addWarning Opt_WarnWarningsDeprecations (getLoc $1) (text "_scc_ is deprecated; use an SCC pragma instead")) >>= \_ ->
( do scc <- getSCC $2; return $ LL scc ) }
| '{-# SCC' STRING '#-}' {% do scc <- getSCC $2; return $ LL scc }
+ | '{-# SCC' VARID '#-}' { LL (getVARID $2) }
hpc_annot :: { Located (FastString,(Int,Int),(Int,Int)) }
: '{-# GENERATED' STRING INTEGER ':' INTEGER '-' INTEGER ':' INTEGER '#-}'
@@ -1944,6 +1947,7 @@ special_id
| 'dynamic' { L1 (fsLit "dynamic") }
| 'stdcall' { L1 (fsLit "stdcall") }
| 'ccall' { L1 (fsLit "ccall") }
+ | 'capi' { L1 (fsLit "capi") }
| 'prim' { L1 (fsLit "prim") }
| 'group' { L1 (fsLit "group") }
diff --git a/compiler/prelude/ForeignCall.lhs b/compiler/prelude/ForeignCall.lhs
index 5e0f9ec5c0..f959fb08d4 100644
--- a/compiler/prelude/ForeignCall.lhs
+++ b/compiler/prelude/ForeignCall.lhs
@@ -151,13 +151,15 @@ platforms.
See: http://www.programmersheaven.com/2/Calling-conventions
\begin{code}
-data CCallConv = CCallConv | StdCallConv | CmmCallConv | PrimCallConv
+data CCallConv = CCallConv | CApiConv | StdCallConv
+ | CmmCallConv | PrimCallConv
deriving (Eq, Data, Typeable)
{-! derive: Binary !-}
instance Outputable CCallConv where
ppr StdCallConv = ptext (sLit "stdcall")
ppr CCallConv = ptext (sLit "ccall")
+ ppr CApiConv = ptext (sLit "capi")
ppr CmmCallConv = ptext (sLit "C--")
ppr PrimCallConv = ptext (sLit "prim")
@@ -167,6 +169,7 @@ defaultCCallConv = CCallConv
ccallConvToInt :: CCallConv -> Int
ccallConvToInt StdCallConv = 0
ccallConvToInt CCallConv = 1
+ccallConvToInt CApiConv = panic "ccallConvToInt CApiConv"
ccallConvToInt (CmmCallConv {}) = panic "ccallConvToInt CmmCallConv"
ccallConvToInt (PrimCallConv {}) = panic "ccallConvToInt PrimCallConv"
\end{code}
@@ -175,9 +178,10 @@ Generate the gcc attribute corresponding to the given
calling convention (used by PprAbsC):
\begin{code}
-ccallConvAttribute :: CCallConv -> String
-ccallConvAttribute StdCallConv = "__attribute__((__stdcall__))"
-ccallConvAttribute CCallConv = ""
+ccallConvAttribute :: CCallConv -> SDoc
+ccallConvAttribute StdCallConv = text "__attribute__((__stdcall__))"
+ccallConvAttribute CCallConv = empty
+ccallConvAttribute CApiConv = empty
ccallConvAttribute (CmmCallConv {}) = panic "ccallConvAttribute CmmCallConv"
ccallConvAttribute (PrimCallConv {}) = panic "ccallConvAttribute PrimCallConv"
\end{code}
@@ -294,11 +298,14 @@ instance Binary CCallConv where
putByte bh 2
put_ bh CmmCallConv = do
putByte bh 3
+ put_ bh CApiConv = do
+ putByte bh 4
get bh = do
h <- getByte bh
case h of
0 -> do return CCallConv
1 -> do return StdCallConv
2 -> do return PrimCallConv
- _ -> do return CmmCallConv
+ 3 -> do return CmmCallConv
+ _ -> do return CApiConv
\end{code}
diff --git a/compiler/typecheck/TcCanonical.lhs b/compiler/typecheck/TcCanonical.lhs
index 09a5403508..726c9a57b9 100644
--- a/compiler/typecheck/TcCanonical.lhs
+++ b/compiler/typecheck/TcCanonical.lhs
@@ -32,7 +32,7 @@ import Name ( Name )
import Var
import VarEnv
import Outputable
-import Control.Monad ( when, unless, zipWithM, zipWithM_, foldM )
+import Control.Monad ( when, unless, zipWithM, foldM )
import MonadUtils
import Control.Applicative ( (<|>) )
@@ -166,25 +166,29 @@ are again good.
canonicalize :: Ct -> TcS StopOrContinue
canonicalize ct@(CNonCanonical { cc_id = ev, cc_flavor = fl, cc_depth = d })
= do { traceTcS "canonicalize (non-canonical)" (ppr ct)
- ; canEvVar ev (classifyPredType (evVarPred ev)) d fl }
+ ; {-# SCC "canEvVar" #-}
+ canEvVar ev (classifyPredType (evVarPred ev)) d fl }
canonicalize (CDictCan { cc_id = ev, cc_depth = d
, cc_flavor = fl
, cc_class = cls
, cc_tyargs = xis })
- = canClass d fl ev cls xis -- Do not add any superclasses
+ = {-# SCC "canClass" #-}
+ canClass d fl ev cls xis -- Do not add any superclasses
canonicalize (CTyEqCan { cc_id = ev, cc_depth = d
, cc_flavor = fl
, cc_tyvar = tv
, cc_rhs = xi })
- = canEqLeafTyVarLeftRec d fl ev tv xi
+ = {-# SCC "canEqLeafTyVarLeftRec" #-}
+ canEqLeafTyVarLeftRec d fl ev tv xi
canonicalize (CFunEqCan { cc_id = ev, cc_depth = d
, cc_flavor = fl
, cc_fun = fn
, cc_tyargs = xis1
, cc_rhs = xi2 })
- = canEqLeafFunEqLeftRec d fl ev (fn,xis1) xi2
+ = {-# SCC "canEqLeafFunEqLeftRec" #-}
+ canEqLeafFunEqLeftRec d fl ev (fn,xis1) xi2
canonicalize (CIPCan { cc_id = ev, cc_depth = d
, cc_flavor = fl
@@ -225,16 +229,19 @@ canTuple :: SubGoalDepth -- Depth
canTuple d fl ev tys
= do { traceTcS "can_pred" (text "TuplePred!")
; evs <- zipWithM can_pred_tup_one tys [0..]
- ; when (isWanted fl) $ setEvBind ev (EvTupleMk evs)
- ; return Stop }
+ ; if (isWanted fl) then
+ do {_unused_fl <- setEvBind ev (EvTupleMk evs) fl
+ ; return Stop }
+ else return Stop }
where
can_pred_tup_one ty n
= do { evc <- newEvVar fl ty
- ; let ev' = evc_the_evvar evc
- ; when (isGivenOrSolved fl) $
- setEvBind ev' (EvTupleSel ev n)
- ; when (isNewEvVar evc) $
- addToWork (canEvVar ev' (classifyPredType (evVarPred ev')) d fl)
+ ; let ev' = evc_the_evvar evc
+ ; fl' <- if isGivenOrSolved fl then
+ setEvBind ev' (EvTupleSel ev n) fl
+ else return fl
+ ; when (isNewEvVar evc) $
+ addToWork (canEvVar ev' (classifyPredType (evVarPred ev')) d fl')
; return ev' }
-- Implicit Parameter Canonicalization
@@ -247,21 +254,21 @@ canIP d fl v nm ty
= -- Note [Canonical implicit parameter constraints] explains why it's
-- possible in principle to not flatten, but since flattening applies
-- the inert substitution we choose to flatten anyway.
- do { (xi,co) <- flatten d fl (mkIPPred nm ty)
- ; if isReflCo co then
+ do { (xi,co,no_flattening) <- flatten d fl (mkIPPred nm ty)
+ ; if no_flattening then
continueWith $ CIPCan { cc_id = v, cc_flavor = fl
, cc_ip_nm = nm, cc_ip_ty = ty
, cc_depth = d }
else do { evc <- newEvVar fl xi
; let v_new = evc_the_evvar evc
IPPred _ ip_xi = classifyPredType xi
- ; case fl of
- Wanted {} -> setEvBind v (EvCast v_new co)
- Given {} -> setEvBind v_new (EvCast v (mkSymCo co))
- Derived {} -> return ()
+ ; fl_new <- case fl of
+ Wanted {} -> setEvBind v (EvCast v_new co) fl
+ Given {} -> setEvBind v_new (EvCast v (mkSymCo co)) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
continueWith $ CIPCan { cc_id = v_new
- , cc_flavor = fl, cc_ip_nm = nm
+ , cc_flavor = fl_new, cc_ip_nm = nm
, cc_ip_ty = ip_xi
, cc_depth = d }
else return Stop } }
@@ -289,25 +296,25 @@ canClass :: SubGoalDepth -- Depth
-- Note: Does NOT add superclasses, but the /caller/ is responsible for adding them!
canClass d fl v cls tys
= do { -- sctx <- getTcSContext
- ; (xis, cos) <- flattenMany d fl tys
+ ; (xis, cos, no_flattening) <- flattenMany d fl tys
; let co = mkTyConAppCo (classTyCon cls) cos
xi = mkClassPred cls xis
-- No flattening, continue with canonical
- ; if isReflCo co then
+ ; if no_flattening then
continueWith $ CDictCan { cc_id = v, cc_flavor = fl
, cc_tyargs = xis, cc_class = cls
, cc_depth = d }
-- Flattening happened
else do { evc <- newEvVar fl xi
; let v_new = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEvBind v (EvCast v_new co)
- Given {} -> setEvBind v_new (EvCast v (mkSymCo co))
- Derived {} -> return ()
+ ; fl_new <- case fl of
+ Wanted {} -> setEvBind v (EvCast v_new co) fl
+ Given {} -> setEvBind v_new (EvCast v (mkSymCo co)) fl
+ Derived {} -> return fl
-- Continue only if flat constraint is new
; if isNewEvVar evc then
- continueWith $ CDictCan { cc_id = v_new, cc_flavor = fl
+ continueWith $ CDictCan { cc_id = v_new, cc_flavor = fl_new
, cc_tyargs = xis, cc_class = cls
, cc_depth = d }
else return Stop } }
@@ -392,7 +399,8 @@ newSCWorkFromFlavored d ev flavor cls xis
; sc_vars <- mapM (newEvVar flavor) sc_theta
; sc_cts <- zipWithM (\scv ev_trm ->
do { let sc_evvar = evc_the_evvar scv
- ; setEvBind sc_evvar ev_trm
+ ; _unused_fl <- setEvBind sc_evvar ev_trm flavor
+ -- unused because it's the same
; return $
CNonCanonical { cc_id = sc_evvar
, cc_flavor = flavor
@@ -402,7 +410,7 @@ newSCWorkFromFlavored d ev flavor cls xis
; traceTcS "newSCWorkFromFlavored" $
text "Emitting superclass work:" <+> ppr sc_cts
; updWorkListTcS $ appendWorkListCt sc_cts }
- GivenSolved -> return ()
+ GivenSolved {} -> return ()
-- Seems very dangerous to add the superclasses for dictionaries that may be
-- partially solved because we may end up with evidence loops.
@@ -447,8 +455,7 @@ canIrred :: SubGoalDepth -- Depth
-- Precondition: ty not a tuple and no other evidence form
canIrred d fl v ty
= do { traceTcS "can_pred" (text "IrredPred = " <+> ppr ty)
- ; (xi,co) <- flatten d fl ty -- co :: xi ~ ty
- ; let no_flattening = isReflCo co
+ ; (xi,co,no_flattening) <- flatten d fl ty -- co :: xi ~ ty
; if no_flattening then
continueWith $ CIrredEvCan { cc_id = v, cc_flavor = fl
, cc_ty = xi, cc_depth = d }
@@ -458,13 +465,13 @@ canIrred d fl v ty
-- canonicalise the resulting evidence variable
evc <- newEvVar fl xi
; let v' = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEvBind v (EvCast v' co)
- Given {} -> setEvBind v' (EvCast v (mkSymCo co))
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEvBind v (EvCast v' co) fl
+ Given {} -> setEvBind v' (EvCast v (mkSymCo co)) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
- canEvVar v' (classifyPredType (evVarPred v')) d fl
+ canEvVar v' (classifyPredType (evVarPred v')) d fl'
else
return Stop }
}
@@ -516,64 +523,70 @@ transitive expansion contains any type function applications. If so,
it expands the synonym and proceeds; if not, it simply returns the
unexpanded synonym.
-TODO: caching the information about whether transitive synonym
-expansions contain any type function applications would speed things
-up a bit; right now we waste a lot of energy traversing the same types
-multiple times.
-
\begin{code}
-- Flatten a bunch of types all at once.
flattenMany :: SubGoalDepth -- Depth
- -> CtFlavor -> [Type] -> TcS ([Xi], [LCoercion])
+ -> CtFlavor -> [Type] -> TcS ([Xi], [LCoercion],Bool)
-- Coercions :: Xi ~ Type
+-- Returns True iff (no flattening happened)
flattenMany d ctxt tys
- = do { (xis, cos) <- mapAndUnzipM (flatten d ctxt) tys
- ; return (xis, cos) }
+ = -- pprTrace "flattenMany" empty $
+ go tys
+ where go [] = return ([],[],True)
+ go (ty:tys) = do { (xi,co,flag_ty) <- flatten d ctxt ty
+ ; (xis,cos,flag_tys) <- go tys
+ ; return (xi:xis,co:cos,flag_ty && flag_tys) }
-- Flatten a type to get rid of type function applications, returning
-- the new type-function-free type, and a collection of new equality
-- constraints. See Note [Flattening] for more detail.
flatten :: SubGoalDepth -- Depth
- -> CtFlavor -> TcType -> TcS (Xi, LCoercion)
+ -> CtFlavor -> TcType -> TcS (Xi, LCoercion,Bool)
-- Postcondition: Coercion :: Xi ~ TcType
+-- Boolean flag to return: True iff (no flattening happened)
+-- Notice the returned flag is NOT equal to isReflCo of the returned coercion
+-- because of spontaneously solved equalities, whose evidence IS refl, but the
+-- types are substituted!
flatten d ctxt ty
| Just ty' <- tcView ty
- = do { (xi, co) <- flatten d ctxt ty'
+ = do { (xi, co, no_flattening) <- flatten d ctxt ty'
-- Preserve type synonyms if possible
- ; if isReflCo co
- then return (ty, mkReflCo ty) -- Importantly, not xi!
- else return (xi, co)
+ ; if no_flattening
+ then return (ty, mkReflCo ty,no_flattening) -- Importantly, not xi!
+ else return (xi,co,no_flattening)
}
flatten _d ctxt v@(TyVarTy _)
= do { ieqs <- getInertEqs
- ; let co = liftInertEqsTy ieqs ctxt v -- co :: v ~ xi
- ; return (pSnd (liftedCoercionKind co), mkSymCo co) } -- return xi ~ v
+ ; let co = liftInertEqsTy ieqs ctxt v -- co :: v ~ xi
+ new_ty = pSnd (liftedCoercionKind co)
+ no_substitution = new_ty `eqType` v -- Very cheap
+ ; return (new_ty, mkSymCo co,no_substitution) } -- return xi ~ v
flatten d ctxt (AppTy ty1 ty2)
- = do { (xi1,co1) <- flatten d ctxt ty1
- ; (xi2,co2) <- flatten d ctxt ty2
- ; return (mkAppTy xi1 xi2, mkAppCo co1 co2) }
+ = do { (xi1,co1,no_flat1) <- flatten d ctxt ty1
+ ; (xi2,co2,no_flat2) <- flatten d ctxt ty2
+ ; return (mkAppTy xi1 xi2, mkAppCo co1 co2,no_flat1 && no_flat2) }
flatten d ctxt (FunTy ty1 ty2)
- = do { (xi1,co1) <- flatten d ctxt ty1
- ; (xi2,co2) <- flatten d ctxt ty2
- ; return (mkFunTy xi1 xi2, mkFunCo co1 co2) }
+ = do { (xi1,co1,no_flat1) <- flatten d ctxt ty1
+ ; (xi2,co2,no_flat2) <- flatten d ctxt ty2
+ ; return (mkFunTy xi1 xi2, mkFunCo co1 co2, no_flat1 && no_flat2) }
flatten d fl (TyConApp tc tys)
-- For a normal type constructor or data family application, we just
-- recursively flatten the arguments.
| not (isSynFamilyTyCon tc)
- = do { (xis,cos) <- flattenMany d fl tys
- ; return (mkTyConApp tc xis, mkTyConAppCo tc cos) }
+ = do { (xis,cos,no_flattening) <- flattenMany d fl tys
+ ; return (mkTyConApp tc xis, mkTyConAppCo tc cos,no_flattening) }
-- Otherwise, it's a type function application, and we have to
-- flatten it away as well, and generate a new given equality constraint
-- between the application and a newly generated flattening skolem variable.
| otherwise
= ASSERT( tyConArity tc <= length tys ) -- Type functions are saturated
- do { (xis, cos) <- flattenMany d fl tys
+ do { (xis, cos, _no_flattening) <- flattenMany d fl tys
; let (xi_args, xi_rest) = splitAt (tyConArity tc) xis
-- The type function might be *over* saturated
-- in which case the remaining arguments should
@@ -588,16 +601,16 @@ flatten d fl (TyConApp tc tys)
Nothing
| isGivenOrSolved fl ->
do { rhs_xi_var <- newFlattenSkolemTy fam_ty
- ; eqv <- newGivenEqVar fl fam_ty rhs_xi_var (mkReflCo fam_ty)
+ ; (fl',eqv)
+ <- newGivenEqVar fl fam_ty rhs_xi_var (mkReflCo fam_ty)
; let ct = CFunEqCan { cc_id = eqv
- , cc_flavor = fl -- Given
+ , cc_flavor = fl' -- Given
, cc_fun = tc
, cc_tyargs = xi_args
, cc_rhs = rhs_xi_var
, cc_depth = d }
-- Update the flat cache: just an optimisation!
- ; updateFlatCache eqv fl tc xi_args rhs_xi_var WhileFlattening
-
+ ; updateFlatCache eqv fl' tc xi_args rhs_xi_var WhileFlattening
; return (mkEqVarLCo eqv, rhs_xi_var, [ct]) }
| otherwise ->
-- Derived or Wanted: make a new /unification/ flatten variable
@@ -623,7 +636,8 @@ flatten d fl (TyConApp tc tys)
; return ( mkAppTys rhs_xi xi_rest -- NB mkAppTys: rhs_xi might not be a type variable
-- cf Trac #5655
, foldl AppCo (mkSymCo ret_co `mkTransCo` mkTyConAppCo tc cos_args)
- cos_rest) }
+ cos_rest
+ , False ) } -- no_flattening is False since we ARE flattening here!
flatten d ctxt ty@(ForAllTy {})
@@ -631,8 +645,8 @@ flatten d ctxt ty@(ForAllTy {})
-- applications inside the forall involve the bound type variables.
= do { let (tvs, rho) = splitForAllTys ty
; when (under_families tvs rho) $ flattenForAllErrorTcS ctxt ty
- ; (rho', co) <- flatten d ctxt rho
- ; return (mkForAllTys tvs rho', foldr mkForAllCo co tvs) }
+ ; (rho', co, no_flattening) <- flatten d ctxt rho
+ ; return (mkForAllTys tvs rho', foldr mkForAllCo co tvs, no_flattening) }
where under_families tvs rho
= go (mkVarSet tvs) rho
@@ -658,15 +672,19 @@ getCachedFlatEq tc xi_args fl feq_origin
; flat_cache <- getTcSEvVarFlatCache
; inerts <- getTcSInerts
; case lookupFunEq pty fl (inert_funeqs inerts) of
- Nothing -> lookup_in_flat_cache pty flat_cache
- res -> return res }
+ Nothing
+ -> lookup_in_flat_cache pty flat_cache
+ res -> return res }
where lookup_in_flat_cache pty flat_cache
= case lookupTM pty flat_cache of
Just (co',(xi',fl',when_generated)) -- ev' :: (TyConApp tc xi_args) ~ xi'
| fl' `canRewrite` fl
, feq_origin `origin_matches` when_generated
-> do { traceTcS "getCachedFlatEq" $ text "success!"
- ; (xi'',co) <- flatten 0 fl' xi' -- co :: xi'' ~ xi'
+ ; (xi'',co,_) <- flatten 0 fl' xi' -- co :: xi'' ~ xi'
+ -- The only purpose of this flattening is to apply the
+ -- inert substitution (since everything in the flat cache
+ -- by construction will have a family-free RHS.
; return $ Just (xi'', co' `mkTransCo` (mkSymCo co)) }
_ -> do { traceTcS "getCachedFlatEq" $ text "failure!" <+> pprEvVarCache flat_cache
; return Nothing }
@@ -684,11 +702,11 @@ addToWork tcs_action = tcs_action >>= stop_or_emit
stop_or_emit (ContinueWith ct) = updWorkListTcS $
extendWorkListCt ct
-canEqEvVarsCreated :: SubGoalDepth -> CtFlavor
- -> [EvVarCreated] -> [Type] -> [Type]
+canEqEvVarsCreated :: SubGoalDepth
+ -> [CtFlavor] -> [EvVarCreated] -> [Type] -> [Type]
-> TcS StopOrContinue
canEqEvVarsCreated _d _fl [] _ _ = return Stop
-canEqEvVarsCreated d fl (evc:evcs) (ty1:tys1) (ty2:tys2)
+canEqEvVarsCreated d (fl:fls) (evc:evcs) (ty1:tys1) (ty2:tys2)
| isNewEvVar evc
= let do_one evc0 sy1 sy2
| isNewEvVar evc0
@@ -697,7 +715,7 @@ canEqEvVarsCreated d fl (evc:evcs) (ty1:tys1) (ty2:tys2)
in do { _unused <- zipWith3M do_one evcs tys1 tys2
; canEq d fl (evc_the_evvar evc) ty1 ty2 }
| otherwise
- = canEqEvVarsCreated d fl evcs tys1 tys2
+ = canEqEvVarsCreated d fls evcs tys1 tys2
canEqEvVarsCreated _ _ _ _ _ = return Stop
@@ -710,7 +728,8 @@ canEq :: SubGoalDepth
canEq _d fl eqv ty1 ty2
| eqType ty1 ty2 -- Dealing with equality here avoids
-- later spurious occurs checks for a~a
- = do { when (isWanted fl) (setEqBind eqv (mkReflCo ty1))
+ = do { when (isWanted fl) $
+ do { _ <- setEqBind eqv (mkReflCo ty1) fl; return () }
; return Stop }
-- Split up an equality between function types into two equalities.
@@ -719,16 +738,19 @@ canEq d fl eqv (FunTy s1 t1) (FunTy s2 t2)
; reseqv <- newEqVar fl t1 t2
; let argeqv_v = evc_the_evvar argeqv
reseqv_v = evc_the_evvar reseqv
- ; case fl of
+ ; (fl1,fl2) <- case fl of
Wanted {} ->
- setEqBind eqv (mkFunCo (mkEqVarLCo argeqv_v) (mkEqVarLCo reseqv_v))
+ do { _ <- setEqBind eqv (mkFunCo (mkEqVarLCo argeqv_v) (mkEqVarLCo reseqv_v)) fl
+ ; return (fl,fl) }
Given {} ->
- do { setEqBind argeqv_v (mkNthCo 0 (mkEqVarLCo eqv))
- ; setEqBind reseqv_v (mkNthCo 1 (mkEqVarLCo eqv)) }
+ do { fl1 <- setEqBind argeqv_v (mkNthCo 0 (mkEqVarLCo eqv)) fl
+ ; fl2 <- setEqBind reseqv_v (mkNthCo 1 (mkEqVarLCo eqv)) fl
+ ; return (fl1,fl2)
+ }
Derived {} ->
- return ()
+ return (fl,fl)
- ; canEqEvVarsCreated d fl [reseqv,argeqv] [t1,s1] [t2,s2] }
+ ; canEqEvVarsCreated d [fl2,fl1] [reseqv,argeqv] [t1,s1] [t2,s2] }
-- If one side is a variable, orient and flatten,
-- WITHOUT expanding type synonyms, so that we tend to
@@ -755,17 +777,18 @@ canEq d fl eqv (TyConApp tc1 tys1) (TyConApp tc2 tys2)
; let kicos = map mkReflCo kis1
; argeqvs <- zipWithM (newEqVar fl) tys1' tys2'
- ; case fl of
+ ; fls <- case fl of
Wanted {} ->
- setEqBind eqv $
- mkTyConAppCo tc1 (kicos ++ map (mkEqVarLCo . evc_the_evvar) argeqvs)
+ do { _ <- setEqBind eqv
+ (mkTyConAppCo tc1 (kicos ++ map (mkEqVarLCo . evc_the_evvar) argeqvs)) fl
+ ; return (map (\_ -> fl) argeqvs) }
Given {} ->
let do_one argeqv n = setEqBind (evc_the_evvar argeqv)
- (mkNthCo n (mkEqVarLCo eqv))
- in zipWithM_ do_one argeqvs [(length kicos)..]
- Derived {} -> return ()
+ (mkNthCo n (mkEqVarLCo eqv)) fl
+ in zipWithM do_one argeqvs [(length kicos)..]
+ Derived {} -> return (map (\_ -> fl) argeqvs)
- ; canEqEvVarsCreated d fl argeqvs tys1' tys2' }
+ ; canEqEvVarsCreated d fls argeqvs tys1' tys2' }
-- See Note [Equality between type applications]
-- Note [Care with type applications] in TcUnify
@@ -789,9 +812,10 @@ canEq d fl eqv ty1 ty2
eqv2 = evc_the_evvar evc2
; when (isWanted fl) $
- setEqBind eqv (mkAppCo (mkEqVarLCo eqv1) (mkEqVarLCo eqv2))
+ do { _ <- setEqBind eqv (mkAppCo (mkEqVarLCo eqv1) (mkEqVarLCo eqv2)) fl
+ ; return () }
- ; canEqEvVarsCreated d fl [evc1,evc2] [s1,t1] [s2,t2] }
+ ; canEqEvVarsCreated d [fl,fl] [evc1,evc2] [s1,t1] [s2,t2] }
canEq d fl eqv s1@(ForAllTy {}) s2@(ForAllTy {})
@@ -1019,15 +1043,15 @@ canEqLeaf :: SubGoalDepth -- Depth
canEqLeaf d fl eqv s1 s2
| cls1 `re_orient` cls2
= do { traceTcS "canEqLeaf (reorienting)" $ ppr (evVarPred eqv)
- ; delCachedEvVar eqv
+ ; delCachedEvVar eqv fl
; evc <- newEqVar fl s2 s1
; let eqv' = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEqBind eqv (mkSymCo (mkEqVarLCo eqv'))
- Given {} -> setEqBind eqv' (mkSymCo (mkEqVarLCo eqv))
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEqBind eqv (mkSymCo (mkEqVarLCo eqv')) fl
+ Given {} -> setEqBind eqv' (mkSymCo (mkEqVarLCo eqv)) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
- do { canEqLeafOriented d fl eqv' s2 s1 }
+ do { canEqLeafOriented d fl' eqv' s2 s1 }
else return Stop
}
| otherwise
@@ -1071,15 +1095,22 @@ canEqLeafFunEqLeftRec :: SubGoalDepth
-> (TyCon,[TcType]) -> TcType -> TcS StopOrContinue
canEqLeafFunEqLeftRec d fl eqv (fn,tys1) ty2 -- eqv :: F tys1 ~ ty2
= do { traceTcS "canEqLeafFunEqLeftRec" $ ppr (evVarPred eqv)
- ; (xis1,cos1) <- flattenMany d fl tys1 -- Flatten type function arguments
- -- cos1 :: xis1 ~ tys1
+ ; (xis1,cos1,no_flattening) <-
+ {-# SCC "flattenMany" #-}
+ flattenMany d fl tys1 -- Flatten type function arguments
+ -- cos1 :: xis1 ~ tys1
- ; let no_flattening = all isReflCo cos1
+-- ; inerts <- getTcSInerts
+-- ; let fam_eqs = inert_funeqs inerts
- ; inerts <- getTcSInerts
- ; let fam_eqs = inert_funeqs inerts
+ ; let flat_ty = mkTyConApp fn xis1
- ; let is_cached = lookupFunEq (mkTyConApp fn xis1) fl fam_eqs
+ ; is_cached <- getCachedFlatEq fn xis1 fl WhenSolved
+ -- Lookup if we have solved this goal already
+{-
+ ; let is_cached = {-# SCC "lookupFunEq" #-}
+ lookupFunEq flat_ty fl fam_eqs
+-}
; if no_flattening && isNothing is_cached then
canEqLeafFunEqLeft d fl eqv (fn,xis1) ty2
@@ -1089,23 +1120,24 @@ canEqLeafFunEqLeftRec d fl eqv (fn,tys1) ty2 -- eqv :: F tys1 ~ ty2
, Just (rhs_ty, ret_eq) <- is_cached
= (mkSymCo ret_eq, rhs_ty)
| Nothing <- is_cached -- Just flattening
- = (mkTyConAppCo fn cos1, mkTyConApp fn xis1)
+ = (mkTyConAppCo fn cos1, flat_ty)
| Just (rhs_ty, ret_eq) <- is_cached -- Both
= (mkSymCo ret_eq `mkTransCo` mkTyConAppCo fn cos1, rhs_ty)
| otherwise = panic "No flattening and not cached!"
- ; delCachedEvVar eqv
+ ; delCachedEvVar eqv fl
; evc <- newEqVar fl final_ty ty2
; let new_eqv = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEqBind eqv $
- mkSymCo final_co `mkTransCo` (mkEqVarLCo new_eqv)
- Given {} -> setEqBind new_eqv $ final_co `mkTransCo` (mkEqVarLCo eqv)
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEqBind eqv
+ (mkSymCo final_co `mkTransCo` (mkEqVarLCo new_eqv)) fl
+ Given {} -> setEqBind new_eqv (final_co `mkTransCo` (mkEqVarLCo eqv)) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
if isNothing is_cached then
- canEqLeafFunEqLeft d fl new_eqv (fn,xis1) ty2
+ {-# SCC "canEqLeafFunEqLeft" #-}
+ canEqLeafFunEqLeft d fl' new_eqv (fn,xis1) ty2
else
- canEq (d+1) fl new_eqv final_ty ty2
+ canEq (d+1) fl' new_eqv final_ty ty2
else return Stop
}
}
@@ -1119,34 +1151,16 @@ lookupFunEq pty fl fam_eqs = lookup_funeq pty fam_eqs
| otherwise
= Nothing
-{- Original, not using inert family equations:
- ; if no_flattening then
- canEqLeafFunEqLeft d fl eqv (fn,xis1) ty2
- else do -- There was flattening
- { let (final_co, final_ty) = (mkTyConAppCo fn cos1, mkTyConApp fn xis1)
- ; delCachedEvVar eqv
- ; evc <- newEqVar fl final_ty ty2
- ; let new_eqv = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEqBind eqv $ mkSymCo final_co `mkTransCo` (mkEqVarLCo new_eqv)
- Given {} -> setEqBind new_eqv $ final_co `mkTransCo` (mkEqVarLCo eqv)
- Derived {} -> return ()
- ; if isNewEvVar evc then
- canEqLeafFunEqLeft d fl new_eqv (fn,xis1) ty2
- else return Stop
- }
- }
--}
-
-
canEqLeafFunEqLeft :: SubGoalDepth -- Depth
-> CtFlavor -> EqVar -> (TyCon,[Xi])
-> TcType -> TcS StopOrContinue
-- Precondition: No more flattening is needed for the LHS
canEqLeafFunEqLeft d fl eqv (fn,xis1) s2
- = do { traceTcS "canEqLeafFunEqLeft" $ ppr (evVarPred eqv)
- ; (xi2,co2) <- flatten d fl s2 -- co2 :: xi2 ~ s2
- ; let no_flattening_happened = isReflCo co2
+ = {-# SCC "canEqLeafFunEqLeft" #-}
+ do { traceTcS "canEqLeafFunEqLeft" $ ppr (evVarPred eqv)
+ ; (xi2,co2,no_flattening_happened) <-
+ {-# SCC "flatten" #-}
+ flatten d fl s2 -- co2 :: xi2 ~ s2
; if no_flattening_happened then
continueWith $ CFunEqCan { cc_id = eqv
, cc_flavor = fl
@@ -1154,19 +1168,21 @@ canEqLeafFunEqLeft d fl eqv (fn,xis1) s2
, cc_tyargs = xis1
, cc_rhs = xi2
, cc_depth = d }
- else do { delCachedEvVar eqv
- ; evc <- newEqVar fl (mkTyConApp fn xis1) xi2
+ else do { delCachedEvVar eqv fl
+ ; evc <-
+ {-# SCC "newEqVar" #-}
+ newEqVar fl (mkTyConApp fn xis1) xi2
; let new_eqv = evc_the_evvar evc -- F xis1 ~ xi2
new_cv = mkEqVarLCo new_eqv
cv = mkEqVarLCo eqv -- F xis1 ~ s2
- ; case fl of
- Wanted {} -> setEqBind eqv $ new_cv `mkTransCo` co2
- Given {} -> setEqBind new_eqv $ cv `mkTransCo` mkSymCo co2
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEqBind eqv (new_cv `mkTransCo` co2) fl
+ Given {} -> setEqBind new_eqv (cv `mkTransCo` mkSymCo co2) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
do { continueWith $
CFunEqCan { cc_id = new_eqv
- , cc_flavor = fl
+ , cc_flavor = fl'
, cc_fun = fn
, cc_tyargs = xis1
, cc_rhs = xi2
@@ -1179,20 +1195,20 @@ canEqLeafTyVarLeftRec :: SubGoalDepth
-> TcTyVar -> TcType -> TcS StopOrContinue
canEqLeafTyVarLeftRec d fl eqv tv s2 -- eqv :: tv ~ s2
= do { traceTcS "canEqLeafTyVarLeftRec" $ ppr (evVarPred eqv)
- ; (xi1,co1) <- flatten d fl (mkTyVarTy tv) -- co1 :: xi1 ~ tv
- ; if isReflCo co1 then
+ ; (xi1,co1,no_flattening) <- flatten d fl (mkTyVarTy tv) -- co1 :: xi1 ~ tv
+ ; if no_flattening then
canEqLeafTyVarLeft d fl eqv tv s2
- else do { delCachedEvVar eqv
+ else do { delCachedEvVar eqv fl
; evc <- newEqVar fl xi1 s2 -- new_ev :: xi1 ~ s2
; let new_ev = evc_the_evvar evc
- ; case fl of
- Wanted {} -> setEqBind eqv $
- mkSymCo co1 `mkTransCo` mkEqVarLCo new_ev
- Given {} -> setEqBind new_ev $
- co1 `mkTransCo` mkEqVarLCo eqv
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEqBind eqv
+ (mkSymCo co1 `mkTransCo` mkEqVarLCo new_ev) fl
+ Given {} -> setEqBind new_ev
+ (co1 `mkTransCo` mkEqVarLCo eqv) fl
+ Derived {} -> return fl
; if isNewEvVar evc then
- do { canEq d fl new_ev xi1 s2 }
+ do { canEq d fl' new_ev xi1 s2 }
else return Stop
}
}
@@ -1203,7 +1219,7 @@ canEqLeafTyVarLeft :: SubGoalDepth -- Depth
-- Precondition LHS is fully rewritten from inerts (but not RHS)
canEqLeafTyVarLeft d fl eqv tv s2 -- eqv : tv ~ s2
= do { traceTcS "canEqLeafTyVarLeft" (ppr (evVarPred eqv))
- ; (xi2, co) <- flatten d fl s2 -- Flatten RHS co : xi2 ~ s2
+ ; (xi2, co, no_flattening_happened) <- flatten d fl s2 -- Flatten RHS co : xi2 ~ s2
; traceTcS "canEqLeafTyVarLeft" (nest 2 (vcat [ text "tv =" <+> ppr tv
, text "s2 =" <+> ppr s2
, text "xi2 =" <+> ppr xi2]))
@@ -1215,8 +1231,9 @@ canEqLeafTyVarLeft d fl eqv tv s2 -- eqv : tv ~ s2
= True
| otherwise = False
; if is_same_tv then
- do { delCachedEvVar eqv
- ; when (isWanted fl) $ setEqBind eqv co
+ do { delCachedEvVar eqv fl
+ ; when (isWanted fl) $
+ do { _ <- setEqBind eqv co fl; return () }
; return Stop }
else
do { -- Do an occurs check, and return a possibly
@@ -1229,7 +1246,6 @@ canEqLeafTyVarLeft d fl eqv tv s2 -- eqv : tv ~ s2
= xi2_unfolded
| otherwise = xi2
- ; let no_flattening_happened = isReflCo co
; if no_flattening_happened then
if isNothing occ_check_result then
@@ -1242,21 +1258,21 @@ canEqLeafTyVarLeft d fl eqv tv s2 -- eqv : tv ~ s2
, cc_depth = d }
else -- Flattening happened, in any case we have to create new variable
-- even if we report an occurs check error
- do { delCachedEvVar eqv
+ do { delCachedEvVar eqv fl
; evc <- newEqVar fl (mkTyVarTy tv) xi2'
; let eqv' = evc_the_evvar evc -- eqv' : tv ~ xi2'
cv = mkEqVarLCo eqv -- cv : tv ~ s2
cv' = mkEqVarLCo eqv' -- cv': tv ~ xi2'
- ; case fl of
- Wanted {} -> setEqBind eqv (cv' `mkTransCo` co) -- tv ~ xi2' ~ s2
- Given {} -> setEqBind eqv' (cv `mkTransCo` mkSymCo co) -- tv ~ s2 ~ xi2'
- Derived {} -> return ()
+ ; fl' <- case fl of
+ Wanted {} -> setEqBind eqv (cv' `mkTransCo` co) fl -- tv ~ xi2' ~ s2
+ Given {} -> setEqBind eqv' (cv `mkTransCo` mkSymCo co) fl -- tv ~ s2 ~ xi2'
+ Derived {} -> return fl
; if isNewEvVar evc then
if isNothing occ_check_result then
canEqFailure d fl eqv'
else continueWith CTyEqCan { cc_id = eqv'
- , cc_flavor = fl
+ , cc_flavor = fl'
, cc_tyvar = tv
, cc_rhs = xi2'
, cc_depth = d }
diff --git a/compiler/typecheck/TcForeign.lhs b/compiler/typecheck/TcForeign.lhs
index 5a4bf776fa..6bc5a4fcf3 100644
--- a/compiler/typecheck/TcForeign.lhs
+++ b/compiler/typecheck/TcForeign.lhs
@@ -453,6 +453,7 @@ Calling conventions
\begin{code}
checkCConv :: CCallConv -> TcM ()
checkCConv CCallConv = return ()
+checkCConv CApiConv = return ()
checkCConv StdCallConv = do dflags <- getDOpts
let platform = targetPlatform dflags
unless (platformArch platform == ArchX86) $
diff --git a/compiler/typecheck/TcHsSyn.lhs b/compiler/typecheck/TcHsSyn.lhs
index 4f8cdb2a77..72f64dddc9 100644
--- a/compiler/typecheck/TcHsSyn.lhs
+++ b/compiler/typecheck/TcHsSyn.lhs
@@ -280,7 +280,10 @@ zonkEvBndr :: ZonkEnv -> EvVar -> TcM EvVar
-- Works for dictionaries and coercions
-- Does not extend the ZonkEnv
zonkEvBndr env var
- = do { ty <- zonkTcTypeToType env (varType var)
+ = do { let var_ty = varType var
+ ; ty <-
+ {-# SCC "zonkEvBndr_zonkTcTypeToType" #-}
+ zonkTcTypeToType env var_ty
; return (setVarType var ty) }
zonkEvVarOcc :: ZonkEnv -> EvVar -> EvVar
@@ -1103,7 +1106,8 @@ zonkEvBindsVar env (EvBindsVar ref _) = do { bs <- readMutVar ref
zonkEvBinds :: ZonkEnv -> Bag EvBind -> TcM (ZonkEnv, Bag EvBind)
zonkEvBinds env binds
- = fixM (\ ~( _, new_binds) -> do
+ = {-# SCC "zonkEvBinds" #-}
+ fixM (\ ~( _, new_binds) -> do
{ let env1 = extendIdZonkEnv env (collect_ev_bndrs new_binds)
; binds' <- mapBagM (zonkEvBind env1) binds
; return (env1, binds') })
@@ -1114,9 +1118,29 @@ zonkEvBinds env binds
zonkEvBind :: ZonkEnv -> EvBind -> TcM EvBind
zonkEvBind env (EvBind var term)
- = do { var' <- zonkEvBndr env var
- ; term' <- zonkEvTerm env term
- ; return (EvBind var' term') }
+ -- This function has some special cases for avoiding re-zonking the
+ -- same types many types. See Note [Optimized Evidence Binding Zonking]
+ = case term of
+ -- Fast path for reflexivity coercions:
+ EvCoercionBox co
+ | Just ty <- isReflCo_maybe co
+ ->
+ do { zty <- zonkTcTypeToType env ty
+ ; let var' = setVarType var (mkEqPred (zty,zty))
+ ; return (EvBind var' (EvCoercionBox (mkReflCo zty))) }
+
+ -- Fast path for variable-variable bindings
+ -- NB: could be optimized further! (e.g. SymCo cv)
+ | Just cv <- getCoVar_maybe co
+ -> do { let cv' = zonkIdOcc env cv -- Just lazily look up
+ term' = EvCoercionBox (CoVarCo cv')
+ var' = setVarType var (varType cv')
+ ; return (EvBind var' term') }
+ -- Ugly safe and slow path
+ _ -> do { var' <- {-# SCC "zonkEvBndr" #-} zonkEvBndr env var
+ ; term' <- zonkEvTerm env term
+ ; return (EvBind var' term')
+ }
\end{code}
%************************************************************************
@@ -1171,6 +1195,33 @@ The type of Phantom is (forall (k : BOX). forall (a : k). Int). Both `a` and
we have a type or a kind variable; for kind variables we just return AnyK (and
not the ill-kinded Any BOX).
+Note [Optimized Evidence Binding Zonking]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When optimising evidence binds we may come accross situations where
+a coercion is just reflexivity:
+ cv = ReflCo ty
+In such a case it is a waste of time to zonk both ty and the type
+of the coercion, especially if the types involved are huge. For this
+reason this case is optimized to only zonk 'ty' and set the type of
+the variable to be that zonked type.
+
+Another case that hurts a lot are simple coercion bindings of the form:
+ cv1 = cv2
+ cv3 = cv1
+ cv4 = cv2
+etc. In all such cases it is very easy to just get the zonked type of
+cv2 and use it to set the type of the LHS coercion variable without zonking
+twice. Though this case is funny, it can happen due the way that evidence
+from spontaneously solved goals is now used.
+See Note [Optimizing Spontaneously Solved Goals] about this.
+
+NB: That these optimizations are independently useful, regardless of the
+constraint solver strategy.
+
+DV, TODO: followup on this note mentioning new examples I will add to perf/
+
+
\begin{code}
mkZonkTcTyVar :: (TcTyVar -> TcM Type) -- What to do for an *mutable Flexi* var
-> (TcTyVar -> Type) -- What to do for an immutable var
@@ -1186,9 +1237,14 @@ mkZonkTcTyVar unbound_mvar_fn unbound_ivar_fn
FlatSkol ty -> zonkType zonk_tv ty
MetaTv _ ref -> do { cts <- readMutVar ref
; case cts of
- Flexi -> do { kind <- zonkType zonk_tv (tyVarKind tv)
+ Flexi -> do { kind <- {-# SCC "zonkKind1" #-}
+ zonkType zonk_tv (tyVarKind tv)
; unbound_mvar_fn (setTyVarKind tv kind) }
- Indirect ty -> zonkType zonk_tv ty }
+ Indirect ty -> do { zty <- zonkType zonk_tv ty
+ -- Small optimisation: shortern-out indirect steps
+ -- so that the old type may be more easily collected.
+ ; writeMutVar ref (Indirect zty)
+ ; return zty } }
zonkTcTypeToType :: ZonkEnv -> TcType -> TcM Type
zonkTcTypeToType (ZonkEnv zonk_unbound_tyvar tv_env _id_env)
diff --git a/compiler/typecheck/TcInteract.lhs b/compiler/typecheck/TcInteract.lhs
index cf6e8c88df..ab7d815cd7 100644
--- a/compiler/typecheck/TcInteract.lhs
+++ b/compiler/typecheck/TcInteract.lhs
@@ -47,7 +47,11 @@ import Bag
import Control.Monad ( foldM )
import TrieMap
+import VarEnv
+import qualified Data.Traversable as Traversable
+
import Control.Monad( when )
+import Pair ( pSnd )
import UniqFM
import FastString ( sLit )
import DynFlags
@@ -104,7 +108,7 @@ solveInteractCts cts
| Just (ev',fl') <- lookupTM pty acc_cache
, fl' `canSolve` fl
, isWanted fl
- = do { setEvBind ev (EvId ev')
+ = do { _ <- setEvBind ev (EvId ev') fl
; return (acc_cts,acc_cache) }
| otherwise -- If it's a given keep it in the work list, even if it exists in the cache!
= return (ct:acc_cts, alterTM pty (\_ -> Just (ev,fl)) acc_cache)
@@ -133,10 +137,12 @@ solveInteractWanted wevs
solveInteract :: TcS ()
-- Returns the final InertSet in TcS, WorkList will be eventually empty.
solveInteract
- = do { dyn_flags <- getDynFlags
+ = {-# SCC "solveInteract" #-}
+ do { dyn_flags <- getDynFlags
; let max_depth = ctxtStkDepth dyn_flags
solve_loop
- = do { sel <- selectNextWorkItem max_depth
+ = {-# SCC "solve_loop" #-}
+ do { sel <- selectNextWorkItem max_depth
; case sel of
NoWorkRemaining -- Done, successfuly (modulo frozen)
-> return ()
@@ -164,22 +170,14 @@ selectNextWorkItem max_depth
= updWorkListTcS_return pick_next
where
pick_next :: WorkList -> (SelectWorkItem, WorkList)
- -- A simple priorititization of equalities (for now)
- -- --------------------------------------------------------
- pick_next wl@(WorkList { wl_eqs = eqs, wl_rest = rest })
- = case (eqs,rest) of
- ([],[]) -- No more work
- -> (NoWorkRemaining,wl)
- ((ct:cts),_)
- | cc_depth ct > max_depth -- Depth exceeded
- -> (MaxDepthExceeded ct,wl)
- | otherwise -- Equality work
- -> (NextWorkItem ct, wl { wl_eqs = cts })
- ([],(ct:cts))
- | cc_depth ct > max_depth -- Depth exceeded
- -> (MaxDepthExceeded ct,wl)
- | otherwise -- Non-equality work
- -> (NextWorkItem ct, wl {wl_rest = cts})
+ pick_next wl = case selectWorkItem wl of
+ (Nothing,_)
+ -> (NoWorkRemaining,wl) -- No more work
+ (Just ct, new_wl)
+ | cc_depth ct > max_depth -- Depth exceeded
+ -> (MaxDepthExceeded ct,new_wl)
+ (Just ct, new_wl)
+ -> (NextWorkItem ct, new_wl) -- New workitem and worklist
runSolverPipeline :: [(String,SimplifierStage)] -- The pipeline
-> WorkItem -- The work item
@@ -241,12 +239,7 @@ React with (F Int ~ b) ==> IR Stop True [] -- after substituting we re-canoni
\begin{code}
thePipeline :: [(String,SimplifierStage)]
thePipeline = [ ("canonicalization", canonicalizationStage)
- -- If ContinueWith, will be canonical and fully rewritten wrt inert eqs
- , ("interact the inert eqs", interactWithInertEqsStage)
- -- If ContinueWith, will be wanted/derived eq or non-eq
- -- but can't rewrite not can be rewritten by the inerts
, ("spontaneous solve", spontaneousSolveStage)
- -- If ContinueWith its not spontaneously solved equality
, ("interact with inerts", interactWithInertsStage)
, ("top-level reactions", topReactionsStage) ]
\end{code}
@@ -297,66 +290,109 @@ spontaneousSolveStage :: SimplifierStage
spontaneousSolveStage workItem
= do { mSolve <- trySpontaneousSolve workItem
; spont_solve mSolve }
- where spont_solve SPCantSolve = continueWith workItem
- spont_solve (SPSolved workItem')
+ where spont_solve SPCantSolve
+ | isCTyEqCan workItem -- Unsolved equality
+ = do { kickOutRewritableInerts workItem -- NB: will add workItem in inerts
+ ; return Stop }
+ | otherwise
+ = continueWith workItem
+ spont_solve (SPSolved workItem') -- Post: workItem' must be equality
= do { bumpStepCountTcS
; traceFireTcS (cc_depth workItem) $
ptext (sLit "Spontaneous")
<+> parens (ppr (cc_flavor workItem)) <+> ppr workItem
- -- If original was /not/ given we may have to kick out now-rewritable inerts
- ; when (not (isGivenOrSolvedCt workItem)) $
- kickOutRewritableInerts workItem'
- -- Add solved guy in inerts anyway
- ; updInertSetTcS workItem'
- -- .. and Stop
+
+ -- NB: will add the item in the inerts
+ ; kickOutRewritableInerts workItem'
+ -- .. and Stop
; return Stop }
kickOutRewritableInerts :: Ct -> TcS ()
-- Pre: ct is a CTyEqCan
--- Post: the TcS monad is left with the thinner non-rewritable inerts; the
--- rewritable end up in the worklist
-kickOutRewritableInerts ct
- = do { wl <- modifyInertTcS (kick_out_rewritable ct)
-
- -- Rewrite the rewritable solved on the spot and stick them back in the inerts
-
-{- DV: I am commenting out the solved story altogether because I did not see any performance
- improvement compared to just kicking out the solved ones any way. In fact there were
- situations where performance got worse.
-
- ; let subst = unitVarEnv (cc_tyvar ct) (ct, mkEqVarLCo (cc_id ct))
- inscope = mkInScopeSet $ tyVarsOfCt ct
- ; solved_rewritten <- mapBagM (rewrite_solved (subst,inscope)) solved_out
- ; _unused <- modifyInertTcS (add_new_solveds solved_rewritten)
-
--}
+-- Post: The TcS monad is left with the thinner non-rewritable inerts; but which
+-- contains the new constraint.
+-- The rewritable end up in the worklist
+kickOutRewritableInerts ct
+ = {-# SCC "kickOutRewritableInerts" #-}
+ do { (wl,ieqs) <- {-# SCC "kick_out_rewritable" #-}
+ modifyInertTcS (kick_out_rewritable ct)
+
+ -- Step 1: Rewrite as many of the inert_eqs on the spot!
+ -- NB: if it is a solved constraint just use the cached evidence
+ ; let ct_coercion
+ | Just (GivenSolved (Just (EvCoercionBox co))) <- isGiven_maybe (cc_flavor ct)
+ = co
+ | otherwise
+ = mkEqVarLCo (cc_id ct)
+
+ ; new_ieqs <- {-# SCC "rewriteInertEqsFromInertEq" #-}
+ rewriteInertEqsFromInertEq (cc_tyvar ct,ct_coercion, cc_flavor ct) ieqs
+ ; modifyInertTcS (\is -> ((), is { inert_eqs = new_ieqs }))
+
+ -- Step 2: Add the new guy in
+ ; updInertSetTcS ct
+
; traceTcS "Kick out" (ppr ct $$ ppr wl)
; updWorkListTcS (unionWorkList wl) }
-{-
- where rewrite_solved inert_eqs solved_ct
- = do { (new_ev,_) <- rewriteFromInertEqs inert_eqs fl ev
- ; mk_canonical new_ev }
- where fl = cc_flavor solved_ct
- ev = cc_id solved_ct
- d = cc_depth solved_ct
- mk_canonical new_ev
- -- A bit of an overkill to call the canonicalizer, but ok ...
- = do { let new_pty = evVarPred new_ev
- ; r <- canEvVar new_ev (classifyPredType new_pty) d fl
- ; case r of
- Stop -> pprPanic "kickOutRewritableInerts" $
- vcat [ text "Should never Stop, solved constraint IS canonical!"
- , text "Orig (solved) =" <+> ppr solved_ct
- , text "Rewritten (solved)=" <+> ppr new_pty ]
- ContinueWith ct -> return ct }
- add_new_solveds cts is = ((), is { inert_solved = new_solved })
- where orig_solveds = inert_solved is
- do_one slvmap ct = let ct_key = mkPredKeyForTypeMap ct
- in alterTM ct_key (\_ -> Just ct) slvmap
- new_solved = foldlBag do_one orig_solveds cts
--}
-
-kick_out_rewritable :: Ct -> InertSet -> (WorkList,InertSet)
+
+rewriteInertEqsFromInertEq :: (TcTyVar,Coercion, CtFlavor) -- A new substitution
+ -> TyVarEnv (Ct,Coercion) -- All inert equalities
+ -> TcS (TyVarEnv (Ct,Coercion)) -- The new inert equalities
+rewriteInertEqsFromInertEq (subst_tv,subst_co, subst_fl) ieqs
+-- The goal: traverse the inert equalities and rewrite some of them, dropping some others
+-- back to the worklist. This is delicate, see Note [Delicate equality kick-out]
+ = do { mieqs <- Traversable.mapM do_one ieqs
+ ; traceTcS "Original inert equalities:" (ppr ieqs)
+ ; let flatten_justs elem venv
+ | Just (act,aco) <- elem = extendVarEnv venv (cc_tyvar act) (act,aco)
+ | otherwise = venv
+ final_ieqs = foldVarEnv flatten_justs emptyVarEnv mieqs
+ ; traceTcS "Remaining inert equalities:" (ppr final_ieqs)
+ ; return final_ieqs }
+
+ where do_one (ct,inert_co)
+ | subst_fl `canRewrite` fl && (subst_tv `elemVarSet` tyVarsOfCt ct)
+ -- Annoyingly inefficient, but we can't simply check
+ -- that isReflCo co because of cached solved ReflCo evidence.
+ = if fl `canRewrite` subst_fl then
+ -- If also the inert can rewrite the subst it's totally safe
+ -- to rewrite on the spot
+ do { (ct',inert_co') <- rewrite_on_the_spot (ct,inert_co)
+ ; return $ Just (ct',inert_co') }
+ else -- We have to throw inert back to worklist for occurs checks
+ do { updWorkListTcS (extendWorkListEq ct)
+ ; return Nothing }
+ | otherwise -- Just keep it there
+ = return $ Just (ct,inert_co)
+ where
+ rewrite_on_the_spot (ct,_inert_co)
+ = do { let rhs' = pSnd (liftedCoercionKind co)
+ ; delCachedEvVar ev fl
+ ; evc <- newEqVar fl (mkTyVarTy tv) rhs'
+ ; let ev' = evc_the_evvar evc
+ ; let evco' = mkEqVarLCo ev'
+ ; fl' <- if isNewEvVar evc then
+ do { case fl of
+ Wanted {}
+ -> setEqBind ev (evco' `mkTransCo` mkSymCo co) fl
+ Given {}
+ -> setEqBind ev' (mkEqVarLCo ev `mkTransCo` co) fl
+ Derived {}
+ -> return fl }
+ else
+ if isWanted fl then
+ setEqBind ev (evco' `mkTransCo` mkSymCo co) fl
+ else return fl
+ ; let ct' = ct { cc_id = ev', cc_flavor = fl', cc_rhs = rhs' }
+ ; return (ct',evco') }
+ ev = cc_id ct
+ fl = cc_flavor ct
+ tv = cc_tyvar ct
+ rhs = cc_rhs ct
+ co = liftCoSubstWith [subst_tv] [subst_co] rhs
+
+kick_out_rewritable :: Ct -> InertSet -> ((WorkList,TyVarEnv (Ct,Coercion)), InertSet)
+-- Returns ALL equalities, to be dealt with later
kick_out_rewritable ct (IS { inert_eqs = eqmap
, inert_eq_tvs = inscope
, inert_dicts = dictmap
@@ -365,14 +401,14 @@ kick_out_rewritable ct (IS { inert_eqs = eqmap
, inert_irreds = irreds
, inert_frozen = frozen
} )
- = (kicked_out, remaining)
+ = ((kicked_out, eqmap), remaining)
where
-
- kicked_out = WorkList { wl_eqs = eqs_out ++ bagToList feqs_out
- , wl_rest = bagToList (fro_out `andCts` dicts_out
- `andCts` ips_out `andCts` irs_out) }
+ kicked_out = WorkList { wl_eqs = []
+ , wl_funeqs = bagToList feqs_out
+ , wl_rest = bagToList (fro_out `andCts` dicts_out
+ `andCts` ips_out `andCts` irs_out) }
- remaining = IS { inert_eqs = eqs_in
+ remaining = IS { inert_eqs = emptyVarEnv
, inert_eq_tvs = inscope -- keep the same, safe and cheap
, inert_dicts = dicts_in
, inert_ips = ips_in
@@ -383,20 +419,46 @@ kick_out_rewritable ct (IS { inert_eqs = eqmap
fl = cc_flavor ct
tv = cc_tyvar ct
+
+ (ips_out, ips_in) = partitionCCanMap rewritable ipmap
- (eqs_out, eqs_in) = partitionEqMap rewritable eqmap
- (ips_out, ips_in) = partitionCCanMap rewritable ipmap
-
- (feqs_out, feqs_in) = partitionCtTypeMap rewritable funeqmap
- (dicts_out, dicts_in) = partitionCCanMap rewritable dictmap
+ (feqs_out, feqs_in) = partitionCtTypeMap rewritable funeqmap
+ (dicts_out, dicts_in) = partitionCCanMap rewritable dictmap
(irs_out, irs_in) = partitionBag rewritable irreds
(fro_out, fro_in) = partitionBag rewritable frozen
- rewritable ct = (fl `canRewrite` cc_flavor ct) &&
+
+ rewritable ct = (fl `canRewrite` cc_flavor ct) &&
(tv `elemVarSet` tyVarsOfCt ct)
+\end{code}
+
+Note [Delicate equality kick-out]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Delicate:
+When kicking out rewritable constraints, it would be safe to simply
+kick out all rewritable equalities, but instead we only kick out those
+that, when rewritten, may result in occur-check errors. We rewrite the
+rest on the spot. Example:
+
+ WorkItem = [S] a ~ b
+ Inerts = { [W] b ~ [a] }
+Now at this point the work item cannot be further rewritten by the
+inert (due to the weaker inert flavor), so we are examining if we can
+instead rewrite the inert from the workitem. But if we rewrite it on
+the spot we have to recanonicalize because of the danger of occurs
+errors. On the other hand if the inert flavor was just as powerful or
+more powerful than the workitem flavor, the work-item could not have
+reached this stage (because it would have already been rewritten by
+the inert).
+The coclusion is: we kick out the 'dangerous' equalities that may
+require recanonicalization (occurs checks) and the rest we rewrite
+unconditionally without further checks, on-the-spot with function
+rewriteInertEqsFromInertEq.
-
+
+\begin{code}
data SPSolveResult = SPCantSolve
| SPSolved WorkItem
@@ -465,21 +527,7 @@ trySpontaneousEqTwoWay d eqv gw tv1 tv2
k1 = tyVarKind tv1
k2 = tyVarKind tv2
nicer_to_update_tv2 = isSigTyVar tv1 || isSystemName (Var.varName tv2)
-{-
--- Previous code below (before kind polymorphism and unification):
- -- | k1 `isSubKind` k2
- -- , nicer_to_update_tv2 = solveWithIdentity eqv gw tv2 (mkTyVarTy tv1)
- -- | k2 `isSubKind` k1
- -- = solveWithIdentity eqv gw tv1 (mkTyVarTy tv2)
- -- | otherwise -- None is a subkind of the other, but they are both touchable!
- -- = return SPCantSolve
- -- -- do { addErrorTcS KindError gw (mkTyVarTy tv1) (mkTyVarTy tv2)
- -- -- ; return SPError }
- -- where
- -- k1 = tyVarKind tv1
- -- k2 = tyVarKind tv2
- -- nicer_to_update_tv2 = isSigTyVar tv1 || isSystemName (Var.varName tv2)
--}
+
\end{code}
Note [Kind errors]
@@ -565,7 +613,7 @@ solveWithIdentity :: SubGoalDepth
-- workItem = the new Given constraint
solveWithIdentity d eqv wd tv xi
= do { traceTcS "Sneaky unification:" $
- vcat [text "Coercion variable: " <+> ppr wd,
+ vcat [text "Coercion variable: " <+> ppr eqv <+> ppr wd,
text "Coercion: " <+> pprEq (mkTyVarTy tv) xi,
text "Left Kind is : " <+> ppr (typeKind (mkTyVarTy tv)),
text "Right Kind is : " <+> ppr (typeKind xi)
@@ -574,36 +622,16 @@ solveWithIdentity d eqv wd tv xi
; setWantedTyBind tv xi
; let refl_xi = mkReflCo xi
- ; let solved_fl = mkSolvedFlavor wd UnkSkol
- ; eqv_given <- newGivenEqVar solved_fl (mkTyVarTy tv) xi refl_xi
+ ; let solved_fl = mkSolvedFlavor wd UnkSkol (EvCoercionBox refl_xi)
+ ; (_,eqv_given) <- newGivenEqVar solved_fl (mkTyVarTy tv) xi refl_xi
- ; when (isWanted wd) (setEqBind eqv refl_xi)
+ ; when (isWanted wd) $ do { _ <- setEqBind eqv refl_xi wd; return () }
-- We don't want to do this for Derived, that's why we use 'when (isWanted wd)'
; return $ SPSolved (CTyEqCan { cc_id = eqv_given
, cc_flavor = solved_fl
, cc_tyvar = tv, cc_rhs = xi, cc_depth = d }) }
\end{code}
-*********************************************************************************
-* *
-* Interact with inert equalities *
-* *
-*********************************************************************************
-
-\begin{code}
-
-interactWithInertEqsStage :: WorkItem -> TcS StopOrContinue
-interactWithInertEqsStage ct
- | isCTyEqCan ct
- = do { kickOutRewritableInerts ct
- ; if isGivenOrSolved (cc_flavor ct) then updInertSetTcS ct >> return Stop
- else continueWith ct } -- If wanted or derived we may spontaneously solve him
- | isCNonCanonical ct
- = pprPanic "Interact with inerts eqs stage met non-canonical constraint!" (ppr ct)
- | otherwise
- = continueWith ct
-\end{code}
-
*********************************************************************************
* *
@@ -779,9 +807,8 @@ doInteractWithInert (CIPCan { cc_id = id1, cc_flavor = ifl, cc_ip_nm = nm1, cc_i
Given {} -> pprPanic "Unexpected given IP" (ppr workItem)
Derived {} -> pprPanic "Unexpected derived IP" (ppr workItem)
Wanted {} ->
- do { setEvBind (cc_id workItem) $
- mkEvCast id1 (mkSymCo (mkTyConAppCo (ipTyCon nm1) [mkEqVarLCo (evc_the_evvar eqv)]))
- -- DV: Changing: used to be (mkSymCo (mkEqVarLCo eqv))
+ do { _ <- setEvBind (cc_id workItem)
+ (mkEvCast id1 (mkSymCo (mkTyConAppCo (ipTyCon nm1) [mkEqVarLCo (evc_the_evvar eqv)]))) wfl
; irWorkItemConsumed "IP/IP (solved by rewriting)" } }
doInteractWithInert (CFunEqCan { cc_id = eqv1, cc_flavor = fl1, cc_fun = tc1
@@ -789,13 +816,13 @@ doInteractWithInert (CFunEqCan { cc_id = eqv1, cc_flavor = fl1, cc_fun = tc1
(CFunEqCan { cc_id = eqv2, cc_flavor = fl2, cc_fun = tc2
, cc_tyargs = args2, cc_rhs = xi2, cc_depth = d2 })
| lhss_match
- , Just GivenSolved <- isGiven_maybe fl1 -- Inert is solved and we can simply ignore it
+ , Just (GivenSolved {}) <- isGiven_maybe fl1 -- Inert is solved and we can simply ignore it
-- when workitem is given/solved
, isGivenOrSolved fl2
= irInertConsumed "FunEq/FunEq"
| lhss_match
- , Just GivenSolved <- isGiven_maybe fl2 -- Workitem is solved and we can ignore it when
- -- the inert is given/solved
+ , Just (GivenSolved {}) <- isGiven_maybe fl2 -- Workitem is solved and we can ignore it when
+ -- the inert is given/solved
, isGivenOrSolved fl1
= irWorkItemConsumed "FunEq/FunEq"
| fl1 `canSolve` fl2 && lhss_match
@@ -820,40 +847,40 @@ rewriteEqLHS :: WhichComesFromInert -> (EqVar,Xi) -> (EqVar,SubGoalDepth,CtFlavo
-- We have an option of creating new work (xi1 ~ xi2) OR (xi2 ~ xi1),
-- See Note [Efficient Orientation] for that
rewriteEqLHS LeftComesFromInert (eqv1,xi1) (eqv2,d,gw,xi2)
- = do { delCachedEvVar eqv2 -- Similarly to canonicalization!
+ = do { delCachedEvVar eqv2 gw -- Similarly to canonicalization!
; evc <- newEqVar gw xi2 xi1
; let eqv2' = evc_the_evvar evc
- ; case gw of
+ ; gw' <- case gw of
Wanted {}
- -> setEqBind eqv2 $
- mkEqVarLCo eqv1 `mkTransCo` mkSymCo (mkEqVarLCo eqv2')
- Given {}
- -> setEqBind eqv2' $
- mkSymCo (mkEqVarLCo eqv2) `mkTransCo` mkEqVarLCo eqv1
+ -> setEqBind eqv2
+ (mkEqVarLCo eqv1 `mkTransCo` mkSymCo (mkEqVarLCo eqv2')) gw
+ Given {}
+ -> setEqBind eqv2'
+ (mkSymCo (mkEqVarLCo eqv2) `mkTransCo` mkEqVarLCo eqv1) gw
Derived {}
- -> return ()
+ -> return gw
; when (isNewEvVar evc) $
updWorkListTcS (extendWorkListEq (CNonCanonical { cc_id = eqv2'
- , cc_flavor = gw
+ , cc_flavor = gw'
, cc_depth = d } ) ) }
rewriteEqLHS RightComesFromInert (eqv1,xi1) (eqv2,d,gw,xi2)
- = do { delCachedEvVar eqv2 -- Similarly to canonicalization!
+ = do { delCachedEvVar eqv2 gw -- Similarly to canonicalization!
; evc <- newEqVar gw xi1 xi2
; let eqv2' = evc_the_evvar evc
- ; case gw of
+ ; gw' <- case gw of
Wanted {}
- -> setEqBind eqv2 $
- mkEqVarLCo eqv1 `mkTransCo` mkEqVarLCo eqv2'
+ -> setEqBind eqv2
+ (mkEqVarLCo eqv1 `mkTransCo` mkEqVarLCo eqv2') gw
Given {}
- -> setEqBind eqv2' $
- mkSymCo (mkEqVarLCo eqv1) `mkTransCo` mkEqVarLCo eqv2
+ -> setEqBind eqv2'
+ (mkSymCo (mkEqVarLCo eqv1) `mkTransCo` mkEqVarLCo eqv2) gw
Derived {}
- -> return ()
+ -> return gw
; when (isNewEvVar evc) $
updWorkListTcS (extendWorkListEq (CNonCanonical { cc_id = eqv2'
- , cc_flavor = gw
+ , cc_flavor = gw'
, cc_depth = d } ) ) }
solveOneFromTheOther :: String -- Info
@@ -872,14 +899,14 @@ solveOneFromTheOther info (ev_term,ifl) workItem
-- so it's safe to continue on from this point
= irInertConsumed ("Solved[DI] " ++ info)
- | Just GivenSolved <- isGiven_maybe ifl, isGivenOrSolved wfl
+ | Just (GivenSolved {}) <- isGiven_maybe ifl, isGivenOrSolved wfl
-- Same if the inert is a GivenSolved -- just get rid of it
= irInertConsumed ("Solved[SI] " ++ info)
| otherwise
= ASSERT( ifl `canSolve` wfl )
-- Because of Note [The Solver Invariant], plus Derived dealt with
- do { when (isWanted wfl) $ setEvBind wid ev_term
+ do { when (isWanted wfl) $ do { _ <- setEvBind wid ev_term wfl; return () }
-- Overwrite the binding, if one exists
-- If both are Given, we already have evidence; no need to duplicate
; irWorkItemConsumed ("Solved " ++ info) }
@@ -1331,30 +1358,32 @@ doTopReact inerts workItem@(CDictCan { cc_flavor = fl@(Wanted loc)
doSolveFromInstance wtvs ev_term workItem
| null wtvs
= do { traceTcS "doTopReact/found nullary instance for" (ppr (cc_id workItem))
- ; setEvBind (cc_id workItem) ev_term
+ ; _ <- setEvBind (cc_id workItem) ev_term fl
; return $
SomeTopInt { tir_rule = "Dict/Top (solved, no new work)"
, tir_new_item = Stop } } -- Don't put him in the inerts
| otherwise
= do { traceTcS "doTopReact/found non-nullary instance for" $
ppr (cc_id workItem)
- ; setEvBind (cc_id workItem) ev_term
+ ; _ <- setEvBind (cc_id workItem) ev_term fl
-- Solved and new wanted work produced, you may cache the
-- (tentatively solved) dictionary as Solved given.
- ; let solved = workItem { cc_flavor = solved_fl }
- solved_fl = mkSolvedFlavor fl UnkSkol
+-- ; let _solved = workItem { cc_flavor = solved_fl }
+-- solved_fl = mkSolvedFlavor fl UnkSkol
; let ct_from_wev (EvVarX v fl)
= CNonCanonical { cc_id = v, cc_flavor = Wanted fl
, cc_depth = cc_depth workItem + 1 }
wtvs_cts = map ct_from_wev wtvs
; updWorkListTcS (appendWorkListCt wtvs_cts)
- ; return $
+ ; return $
SomeTopInt { tir_rule = "Dict/Top (solved, more work)"
- , tir_new_item = ContinueWith solved } } -- Cache in inerts the Solved item
+ , tir_new_item = Stop }
+ }
+-- , tir_new_item = ContinueWith solved } } -- Cache in inerts the Solved item
-- Type functions
doTopReact _inerts (CFunEqCan { cc_flavor = fl })
- | Just GivenSolved <- isGiven_maybe fl
+ | Just (GivenSolved {}) <- isGiven_maybe fl
= return NoTopInt -- If Solved, no more interactions should happen
-- Otherwise, it's a Given, Derived, or Wanted
@@ -1375,25 +1404,29 @@ doTopReact _inerts workItem@(CFunEqCan { cc_id = eqv, cc_flavor = fl
; case fl of
Wanted {} -> do { evc <- newEqVar fl rhs_ty xi -- Wanted version
; let eqv' = evc_the_evvar evc
- ; setEqBind eqv (coe `mkTransCo` mkEqVarLCo eqv')
+ ; let coercion = coe `mkTransCo` mkEqVarLCo eqv'
+ ; _ <- setEqBind eqv coercion fl
; when (isNewEvVar evc) $
(let ct = CNonCanonical { cc_id = eqv'
, cc_flavor = fl
, cc_depth = cc_depth workItem + 1}
in updWorkListTcS (extendWorkListEq ct))
- ; let solved = workItem { cc_flavor = solved_fl }
- solved_fl = mkSolvedFlavor fl UnkSkol
+ ; let _solved = workItem { cc_flavor = solved_fl }
+ solved_fl = mkSolvedFlavor fl UnkSkol (EvCoercionBox coercion)
+
+ ; updateFlatCache eqv solved_fl tc args xi WhenSolved
; return $
SomeTopInt { tir_rule = "Fun/Top (solved, more work)"
- , tir_new_item = ContinueWith solved } }
- -- Cache in inerts the Solved item
+ , tir_new_item = Stop } }
+ -- , tir_new_item = ContinueWith solved } }
+ -- Cache in inerts the Solved item
- Given {} -> do { eqv' <- newGivenEqVar fl xi rhs_ty $
- mkSymCo (mkEqVarLCo eqv) `mkTransCo` coe
+ Given {} -> do { (fl',eqv') <- newGivenEqVar fl xi rhs_ty $
+ mkSymCo (mkEqVarLCo eqv) `mkTransCo` coe
; let ct = CNonCanonical { cc_id = eqv'
- , cc_flavor = fl
+ , cc_flavor = fl'
, cc_depth = cc_depth workItem + 1}
; updWorkListTcS (extendWorkListEq ct)
diff --git a/compiler/typecheck/TcRnDriver.lhs b/compiler/typecheck/TcRnDriver.lhs
index 174939688c..b383563311 100644
--- a/compiler/typecheck/TcRnDriver.lhs
+++ b/compiler/typecheck/TcRnDriver.lhs
@@ -1435,6 +1435,7 @@ tcRnExpr hsc_env ictxt rdr_expr
let { fresh_it = itName uniq (getLoc rdr_expr) } ;
((_tc_expr, res_ty), lie) <- captureConstraints (tcInferRho rn_expr) ;
((qtvs, dicts, _, _), lie_top) <- captureConstraints $
+ {-# SCC "simplifyInfer" #-}
simplifyInfer True {- Free vars are closed -}
False {- No MR for now -}
[(fresh_it, res_ty)]
diff --git a/compiler/typecheck/TcRnMonad.lhs b/compiler/typecheck/TcRnMonad.lhs
index fbe3a2fc7f..845eaceb7b 100644
--- a/compiler/typecheck/TcRnMonad.lhs
+++ b/compiler/typecheck/TcRnMonad.lhs
@@ -1011,7 +1011,7 @@ emitWantedCts = mapBagM_ emit_wanted_ct
| v <- cc_id ct
, Wanted loc <- cc_flavor ct
= emitFlat (EvVarX v loc)
- | otherwise = panic "emitWantecCts: can't emit non-wanted!"
+ | otherwise = panic "emitWantedCts: can't emit non-wanted!"
emitImplication :: Implication -> TcM ()
emitImplication ct
diff --git a/compiler/typecheck/TcRnTypes.lhs b/compiler/typecheck/TcRnTypes.lhs
index da2c8981ed..12f3184aa4 100644
--- a/compiler/typecheck/TcRnTypes.lhs
+++ b/compiler/typecheck/TcRnTypes.lhs
@@ -71,7 +71,7 @@ module TcRnTypes(
SkolemInfo(..),
CtFlavor(..), pprFlavorArising, isWanted,
- isGivenOrSolved, isGiven_maybe,
+ isGivenOrSolved, isGiven_maybe, isSolved,
isDerived,
-- Pretty printing
@@ -1210,14 +1210,17 @@ data CtFlavor
data GivenKind
= GivenOrig -- Originates in some given, such as signature or pattern match
- | GivenSolved -- Is given as result of being solved, maybe provisionally on
- -- some other wanted constraints.
+ | GivenSolved (Maybe EvTerm)
+ -- Is given as result of being solved, maybe provisionally on
+ -- some other wanted constraints. We cache the evidence term
+ -- sometimes here as well /as well as/ in the EvBinds,
+ -- see Note [Optimizing Spontaneously Solved Coercions]
instance Outputable CtFlavor where
- ppr (Given _ GivenOrig) = ptext (sLit "[G]")
- ppr (Given _ GivenSolved) = ptext (sLit "[S]") -- Print [S] for Given/Solved's
- ppr (Wanted {}) = ptext (sLit "[W]")
- ppr (Derived {}) = ptext (sLit "[D]")
+ ppr (Given _ GivenOrig) = ptext (sLit "[G]")
+ ppr (Given _ (GivenSolved {})) = ptext (sLit "[S]") -- Print [S] for Given/Solved's
+ ppr (Wanted {}) = ptext (sLit "[W]")
+ ppr (Derived {}) = ptext (sLit "[D]")
pprFlavorArising :: CtFlavor -> SDoc
pprFlavorArising (Derived wl) = pprArisingAt wl
@@ -1232,6 +1235,10 @@ isGivenOrSolved :: CtFlavor -> Bool
isGivenOrSolved (Given {}) = True
isGivenOrSolved _ = False
+isSolved :: CtFlavor -> Bool
+isSolved (Given _ (GivenSolved {})) = True
+isSolved _ = False
+
isGiven_maybe :: CtFlavor -> Maybe GivenKind
isGiven_maybe (Given _ gk) = Just gk
isGiven_maybe _ = Nothing
diff --git a/compiler/typecheck/TcSMonad.lhs b/compiler/typecheck/TcSMonad.lhs
index 7d3ee73f6b..aee0877c75 100644
--- a/compiler/typecheck/TcSMonad.lhs
+++ b/compiler/typecheck/TcSMonad.lhs
@@ -14,7 +14,7 @@ module TcSMonad (
WorkList(..), isEmptyWorkList, emptyWorkList,
workListFromEq, workListFromNonEq, workListFromCt,
extendWorkListEq, extendWorkListNonEq, extendWorkListCt,
- appendWorkListCt, appendWorkListEqs, unionWorkList,
+ appendWorkListCt, appendWorkListEqs, unionWorkList, selectWorkItem,
getTcSWorkList, updWorkListTcS, updWorkListTcS_return, keepWanted,
@@ -47,8 +47,6 @@ module TcSMonad (
-- Setting evidence variables
setEqBind,
- setIPBind,
- setDictBind,
setEvBind,
setWantedTyBind,
@@ -62,7 +60,7 @@ module TcSMonad (
-- Inerts
InertSet(..),
- getInertEqs, rewriteFromInertEqs, liftInertEqsTy,
+ getInertEqs, liftInertEqsTy,
emptyInert, getTcSInerts, updInertSet, extractUnsolved,
extractUnsolvedTcS, modifyInertTcS,
updInertSetTcS, partitionCCanMap, partitionEqMap,
@@ -125,7 +123,7 @@ import Bag
import MonadUtils
import VarSet
-import Pair ( pSnd )
+-- import Pair ( pSnd )
import FastString
import Util
@@ -207,17 +205,22 @@ better rewrite it as much as possible before reporting it as an error to the use
\begin{code}
-- See Note [WorkList]
-data WorkList = WorkList { wl_eqs :: [Ct], wl_rest :: [Ct] }
+data WorkList = WorkList { wl_eqs :: [Ct], wl_funeqs :: [Ct], wl_rest :: [Ct] }
unionWorkList :: WorkList -> WorkList -> WorkList
unionWorkList new_wl orig_wl =
- WorkList { wl_eqs = wl_eqs new_wl ++ wl_eqs orig_wl
- , wl_rest = wl_rest new_wl ++ wl_rest orig_wl }
+ WorkList { wl_eqs = wl_eqs new_wl ++ wl_eqs orig_wl
+ , wl_funeqs = wl_funeqs new_wl ++ wl_funeqs orig_wl
+ , wl_rest = wl_rest new_wl ++ wl_rest orig_wl }
extendWorkListEq :: Ct -> WorkList -> WorkList
-- Extension by equality
-extendWorkListEq ct wl = wl { wl_eqs = ct : wl_eqs wl }
+extendWorkListEq ct wl
+ | Just {} <- isCFunEqCan_Maybe ct
+ = wl { wl_funeqs = ct : wl_funeqs wl }
+ | otherwise
+ = wl { wl_eqs = ct : wl_eqs wl }
extendWorkListNonEq :: Ct -> WorkList -> WorkList
-- Extension by non equality
@@ -238,25 +241,36 @@ appendWorkListEqs :: [Ct] -> WorkList -> WorkList
appendWorkListEqs cts wl = foldr extendWorkListEq wl cts
isEmptyWorkList :: WorkList -> Bool
-isEmptyWorkList wl = null (wl_eqs wl) && null (wl_rest wl)
+isEmptyWorkList wl
+ = null (wl_eqs wl) && null (wl_rest wl) && null (wl_funeqs wl)
emptyWorkList :: WorkList
-emptyWorkList = WorkList { wl_eqs = [], wl_rest = [] }
+emptyWorkList = WorkList { wl_eqs = [], wl_rest = [], wl_funeqs = []}
workListFromEq :: Ct -> WorkList
-workListFromEq ct = WorkList { wl_eqs = [ct], wl_rest = [] }
+workListFromEq ct = extendWorkListEq ct emptyWorkList
workListFromNonEq :: Ct -> WorkList
-workListFromNonEq ct = WorkList { wl_eqs = [], wl_rest = [ct] }
+workListFromNonEq ct = extendWorkListNonEq ct emptyWorkList
workListFromCt :: Ct -> WorkList
-- Agnostic
workListFromCt ct | isLCoVar (cc_id ct) = workListFromEq ct
| otherwise = workListFromNonEq ct
+
+selectWorkItem :: WorkList -> (Maybe Ct, WorkList)
+selectWorkItem wl@(WorkList { wl_eqs = eqs, wl_funeqs = feqs, wl_rest = rest })
+ = case (eqs,feqs,rest) of
+ (ct:cts,_,_) -> (Just ct, wl { wl_eqs = cts })
+ (_,(ct:cts),_) -> (Just ct, wl { wl_funeqs = cts })
+ (_,_,(ct:cts)) -> (Just ct, wl { wl_rest = cts })
+ (_,_,_) -> (Nothing,wl)
+
-- Pretty printing
instance Outputable WorkList where
ppr wl = vcat [ text "WorkList (eqs) = " <+> ppr (wl_eqs wl)
+ , text "WorkList (funeqs)= " <+> ppr (wl_funeqs wl)
, text "WorkList (rest) = " <+> ppr (wl_rest wl)
]
@@ -475,22 +489,25 @@ updInertSet :: InertSet -> AtomicInert -> InertSet
-- Add a new inert element to the inert set.
updInertSet is item
| isCTyEqCan item
- = let upd_err a b = pprPanic "updInertSet" $
- vcat [text "Multiple inert equalities:", ppr a, ppr b]
+ = let upd_err a b = pprPanic "updInertSet" $
+ vcat [ text "Multiple inert equalities:"
+ , text "Old (already inert):" <+> ppr a
+ , text "Trying to insert :" <+> ppr b
+ ]
+
+ -- If evidence is cached, pick it up from the flavor!
+ coercion
+ | Just (GivenSolved (Just (EvCoercionBox co))) <- isGiven_maybe (cc_flavor item)
+ = co
+ | otherwise
+ = mkEqVarLCo (cc_id item)
+
eqs' = extendVarEnv_C upd_err (inert_eqs is)
(cc_tyvar item)
- (item, mkEqVarLCo (cc_id item))
+ (item, coercion)
inscope' = extendInScopeSetSet (inert_eq_tvs is) (tyVarsOfCt item)
in is { inert_eqs = eqs', inert_eq_tvs = inscope' }
-{-
- -- /Solved/ non-equalities go to the solved map
- | Just GivenSolved <- isGiven_maybe (cc_flavor item)
- = let pty = mkPredKeyForTypeMap item
- solved_orig = inert_solved is
- in is { inert_solved = alterTM pty (\_ -> Just item) solved_orig }
--}
-
| Just x <- isCIPCan_Maybe item -- IP
= is { inert_ips = updCCanMap (x,item) (inert_ips is) }
| isCIrredEvCan item -- Presently-irreducible evidence
@@ -660,11 +677,11 @@ combineCtLoc (Derived loc ) _ = loc
combineCtLoc _ (Derived loc ) = loc
combineCtLoc _ _ = panic "combineCtLoc: both given"
-mkSolvedFlavor :: CtFlavor -> SkolemInfo -> CtFlavor
+mkSolvedFlavor :: CtFlavor -> SkolemInfo -> EvTerm -> CtFlavor
-- To be called when we actually solve a wanted/derived (perhaps leaving residual goals)
-mkSolvedFlavor (Wanted loc) sk = Given (setCtLocOrigin loc sk) GivenSolved
-mkSolvedFlavor (Derived loc) sk = Given (setCtLocOrigin loc sk) GivenSolved
-mkSolvedFlavor fl@(Given {}) _sk = pprPanic "Solving a given constraint!" $ ppr fl
+mkSolvedFlavor (Wanted loc) sk evterm = Given (setCtLocOrigin loc sk) (GivenSolved (Just evterm))
+mkSolvedFlavor (Derived loc) sk evterm = Given (setCtLocOrigin loc sk) (GivenSolved (Just evterm))
+mkSolvedFlavor fl@(Given {}) _sk _evterm = pprPanic "Solving a given constraint!" $ ppr fl
mkGivenFlavor :: CtFlavor -> SkolemInfo -> CtFlavor
mkGivenFlavor (Wanted loc) sk = Given (setCtLocOrigin loc sk) GivenOrig
@@ -1050,8 +1067,8 @@ getTcEvBindsMap
; wrapTcS $ TcM.readTcRef ev_ref }
-setEqBind :: EqVar -> LCoercion -> TcS ()
-setEqBind eqv co = setEvBind eqv (EvCoercionBox co)
+setEqBind :: EqVar -> LCoercion -> CtFlavor -> TcS CtFlavor
+setEqBind eqv co fl = setEvBind eqv (EvCoercionBox co) fl
setWantedTyBind :: TcTyVar -> TcType -> TcS ()
-- Add a type binding
@@ -1067,15 +1084,11 @@ setWantedTyBind tv ty
, text "Old value =" <+> ppr (lookupVarEnv_NF ty_binds tv)]
; TcM.writeTcRef ref (extendVarEnv ty_binds tv (tv,ty)) } }
-setIPBind :: EvVar -> EvTerm -> TcS ()
-setIPBind = setEvBind
-setDictBind :: EvVar -> EvTerm -> TcS ()
-setDictBind = setEvBind
-
-setEvBind :: EvVar -> EvTerm -> TcS ()
--- Internal
-setEvBind ev t
+setEvBind :: EvVar -> EvTerm -> CtFlavor -> TcS CtFlavor
+-- If the flavor is Solved, we cache the new evidence term inside the returned flavor
+-- see Note [Optimizing Spontaneously Solved Coercions]
+setEvBind ev t fl
= do { tc_evbinds <- getTcEvBinds
; wrapTcS $ TcM.addTcEvBind tc_evbinds ev t
@@ -1084,6 +1097,11 @@ setEvBind ev t
; let cycle = any (reaches binds) (evterm_evs t)
; when cycle (fail_if_co_loop binds)
#endif
+ ; return $
+ case fl of
+ Given gl (GivenSolved _)
+ -> Given gl (GivenSolved (Just t))
+ _ -> fl
}
#ifdef DEBUG
@@ -1110,6 +1128,51 @@ setEvBind ev t
evterm_evs (EvTupleMk evs) = evs
#endif
+\end{code}
+Note [Optimizing Spontaneously Solved Coercions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Spontaneously solved coercions such as alpha := tau used to be bound as everything else
+in the evidence binds. Subsequently they were used for rewriting other wanted or solved
+goals. For instance:
+
+WorkItem = [S] g1 : a ~ tau
+Inerts = [S] g2 : b ~ [a]
+ [S] g3 : c ~ [(a,a)]
+
+Would result, eventually, after the workitem rewrites the inerts, in the
+following evidence bindings:
+
+ g1 = ReflCo tau
+ g2 = ReflCo [a]
+ g3 = ReflCo [(a,a)]
+ g2' = g2 ; [g1]
+ g3' = g3 ; [(g1,g1)]
+
+This ia annoying because it puts way too much stress to the zonker and
+desugarer, since we /know/ at the generation time (spontaneously
+solving) that the evidence for a particular evidence variable is the
+identity.
+
+For this reason, our solution is to cache inside the GivenSolved
+flavor of a constraint the term which is actually solving this
+constraint. Whenever we perform a setEvBind, a new flavor is returned
+so that if it was a GivenSolved to start with, it remains a
+GivenSolved with a new evidence term inside. Then, when we use solved
+goals to rewrite other constraints we simply use whatever is in the
+GivenSolved flavor and not the constraint cc_id.
+
+In our particular case we'd get the following evidence bindings, eventually:
+
+ g1 = ReflCo tau
+ g2 = ReflCo [a]
+ g3 = ReflCo [(a,a)]
+ g2'= ReflCo [a]
+ g3'= ReflCo [(a,a)]
+
+Since we use smart constructors to get rid of g;ReflCo t ~~> g etc.
+
+\begin{code}
warnTcS :: CtLoc orig -> Bool -> SDoc -> TcS ()
@@ -1267,11 +1330,23 @@ newEvVar :: CtFlavor -> TcPredType -> TcS EvVarCreated
-- the call sites for this invariant to be quickly restored.
newEvVar fl pty
| isGivenOrSolved fl -- Create new variable and update the cache
- = do { new <- forceNewEvVar fl pty
+ = do {
+{- We lose a lot of time if we enable this check:
+ eref <- getTcSEvVarCache
+ ; ecache <- wrapTcS (TcM.readTcRef eref)
+ ; case lookupTM pty (evc_cache ecache) of
+ Just (_,cached_fl)
+ | cached_fl `canSolve` fl
+ -> pprTrace "Interesting: given newEvVar, missed caching opportunity!" empty $
+ return ()
+ _ -> return ()
+-}
+ new <- forceNewEvVar fl pty
; return (EvVarCreated True new) }
| otherwise -- Otherwise lookup first
- = do { eref <- getTcSEvVarCache
+ = {-# SCC "newEvVarWanted" #-}
+ do { eref <- getTcSEvVarCache
; ecache <- wrapTcS (TcM.readTcRef eref)
; case lookupTM pty (evc_cache ecache) of
Just (cached_evvar, cached_flavor)
@@ -1322,9 +1397,10 @@ updateCache ecache (ev,fl,pty)
ecache' = alterTM pty (\_ -> Just (ev,fl)) $
evc_cache ecache
-delCachedEvVar :: EvVar -> TcS ()
-delCachedEvVar ev
- = do { eref <- getTcSEvVarCache
+delCachedEvVar :: EvVar -> CtFlavor -> TcS ()
+delCachedEvVar ev _fl
+ = {-# SCC "delCachedEvVarOther" #-}
+ do { eref <- getTcSEvVarCache
; ecache <- wrapTcS (TcM.readTcRef eref)
; wrapTcS $ TcM.writeTcRef eref (delFromCache ecache ev) }
@@ -1361,13 +1437,13 @@ pprEvVarCache tm = ppr (foldTM mk_pair tm [])
where mk_pair (co,_) cos = (co, liftedCoercionKind co) : cos
-newGivenEqVar :: CtFlavor -> TcType -> TcType -> Coercion -> TcS EvVar
+newGivenEqVar :: CtFlavor -> TcType -> TcType -> Coercion -> TcS (CtFlavor,EvVar)
-- Pre: fl is Given
newGivenEqVar fl ty1 ty2 co
= do { ecv <- newEqVar fl ty1 ty2
; let v = evc_the_evvar ecv -- Will be a new EvVar by post of newEvVar
- ; setEvBind v (EvCoercionBox co)
- ; return v }
+ ; fl' <- setEvBind v (EvCoercionBox co) fl
+ ; return (fl',v) }
newEqVar :: CtFlavor -> TcType -> TcType -> TcS EvVarCreated
newEqVar fl ty1 ty2
@@ -1431,26 +1507,6 @@ getInertEqs :: TcS (TyVarEnv (Ct,Coercion), InScopeSet)
getInertEqs = do { inert <- getTcSInerts
; return (inert_eqs inert, inert_eq_tvs inert) }
-rewriteFromInertEqs :: (TyVarEnv (Ct,Coercion), InScopeSet)
- -- Precondition: Ct are CTyEqCans only!
- -> CtFlavor
- -> EvVar
- -> TcS (EvVar,Bool)
--- Boolean flag returned: True <-> no rewriting happened
-rewriteFromInertEqs (subst,inscope) fl v
- = do { let co = liftInertEqsTy (subst,inscope) fl (evVarPred v)
- ; if isReflCo co then return (v,True)
- else do { traceTcS "rewriteFromInertEqs" $
- text "Original item =" <+> ppr v <+> dcolon <+> ppr (evVarPred v)
- ; v' <- forceNewEvVar fl (pSnd (liftedCoercionKind co))
- ; case fl of
- Wanted {} -> setEvBind v (EvCast v' (mkSymCo co))
- Given {} -> setEvBind v' (EvCast v co)
- Derived {} -> return ()
- ; traceTcS "rewriteFromInertEqs" $
- text "Rewritten item =" <+> ppr v' <+> dcolon <+> ppr (evVarPred v')
- ; return (v',False) } }
-
-- See Note [LiftInertEqs]
liftInertEqsTy :: (TyVarEnv (Ct,Coercion),InScopeSet)
@@ -1506,7 +1562,7 @@ ty_cts_subst subst inscope fl ty
unused_evvar = panic "ty_cts_subst: This var is just an alpha-renaming!"
\end{code}
-Note [LiftInertEqsPred]
+Note [LiftInertEqsTy]
~~~~~~~~~~~~~~~~~~~~~~~
The function liftInertEqPred behaves almost like liftCoSubst (in
Coercion), but accepts a map TyVarEnv (Ct,Coercion) instead of a
diff --git a/compiler/typecheck/TcSimplify.lhs b/compiler/typecheck/TcSimplify.lhs
index 68082d4156..76e02e6629 100644
--- a/compiler/typecheck/TcSimplify.lhs
+++ b/compiler/typecheck/TcSimplify.lhs
@@ -1046,7 +1046,11 @@ solveCTyFunEqs cts
; return (niFixTvSubst ni_subst, unsolved_can_cts) }
where
solve_one (cv,tv,ty) = do { setWantedTyBind tv ty
- ; setEqBind cv (mkReflCo ty) }
+ ; _ <- setEqBind cv (mkReflCo ty) $
+ (Wanted $ panic "Met an already solved function equality!")
+ ; return () -- Don't care about flavors etc this is
+ -- the last thing happening
+ }
------------
type FunEqBinds = (TvSubstEnv, [(CoVar, TcTyVar, TcType)])
diff --git a/compiler/types/Coercion.lhs b/compiler/types/Coercion.lhs
index aaed359a10..17179fd2f1 100644
--- a/compiler/types/Coercion.lhs
+++ b/compiler/types/Coercion.lhs
@@ -22,6 +22,7 @@ module Coercion (
-- ** Functions over coercions
coVarKind,
coercionType, coercionKind, coercionKinds, isReflCo, liftedCoercionKind,
+ isReflCo_maybe,
mkCoercionType,
-- ** Constructing coercions
diff --git a/compiler/utils/UniqFM.lhs b/compiler/utils/UniqFM.lhs
index c3d204215e..4ee6e190cc 100644
--- a/compiler/utils/UniqFM.lhs
+++ b/compiler/utils/UniqFM.lhs
@@ -20,7 +20,7 @@ and ``addToUFM\_C'' and ``Data.IntMap.insertWith'' differ in the order
of arguments of combining function.
\begin{code}
-{-# OPTIONS -fno-warn-tabs #-}
+{-# OPTIONS -fno-warn-tabs -XGeneralizedNewtypeDeriving #-}
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
@@ -74,6 +74,7 @@ import Compiler.Hoopl hiding (Unique)
import Data.Function (on)
import qualified Data.IntMap as M
import qualified Data.Foldable as Foldable
+import qualified Data.Traversable as Traversable
import Data.Typeable
import Data.Data
\end{code}
@@ -179,11 +180,19 @@ ufmToList :: UniqFM elt -> [(Unique, elt)]
\begin{code}
newtype UniqFM ele = UFM { unUFM :: M.IntMap ele }
- deriving (Typeable,Data)
+ deriving (Typeable,Data, Traversable.Traversable, Functor)
instance Eq ele => Eq (UniqFM ele) where
(==) = (==) `on` unUFM
+{-
+instance Functor UniqFM where
+ fmap f = fmap f . unUFM
+
+instance Traversable.Traversable UniqFM where
+ traverse f = Traversable.traverse f . unUFM
+-}
+
instance Foldable.Foldable UniqFM where
foldMap f = Foldable.foldMap f . unUFM
diff --git a/compiler/vectorise/Vectorise/Builtins.hs b/compiler/vectorise/Vectorise/Builtins.hs
index 8465c203b0..d194135951 100644
--- a/compiler/vectorise/Vectorise/Builtins.hs
+++ b/compiler/vectorise/Vectorise/Builtins.hs
@@ -8,7 +8,6 @@ module Vectorise.Builtins (
Builtins(..),
-- * Wrapped selectors
- parray_PrimTyCon,
selTy, selsTy,
selReplicate,
selTags,
@@ -26,7 +25,7 @@ module Vectorise.Builtins (
closureCtrFun,
-- * Initialisation
- initBuiltins, initBuiltinVars, initBuiltinTyCons
+ initBuiltins, initBuiltinVars,
) where
import Vectorise.Builtins.Base
diff --git a/compiler/vectorise/Vectorise/Builtins/Base.hs b/compiler/vectorise/Vectorise/Builtins/Base.hs
index 586c950f62..90afedfb87 100644
--- a/compiler/vectorise/Vectorise/Builtins/Base.hs
+++ b/compiler/vectorise/Vectorise/Builtins/Base.hs
@@ -13,7 +13,6 @@ module Vectorise.Builtins.Base (
Builtins(..),
-- * Projections
- parray_PrimTyCon,
selTy, selsTy,
selReplicate,
selTags,
@@ -71,9 +70,7 @@ aLL_DPH_PRIM_TYCONS = map tyConName [intPrimTyCon, {- floatPrimTyCon, -} doubleP
--
data Builtins
= Builtins
- { parrayTyCon :: TyCon -- ^ PArray
- , parray_PrimTyCons :: NameEnv TyCon -- ^ PArray_Int# etc.
- , pdataTyCon :: TyCon -- ^ PData
+ { pdataTyCon :: TyCon -- ^ PData
, pdatasTyCon :: TyCon -- ^ PDatas
, prClass :: Class -- ^ PR
, prTyCon :: TyCon -- ^ PR
@@ -119,9 +116,6 @@ data Builtins
-- We use these wrappers instead of indexing the `Builtin` structure directly
-- because they give nicer panic messages if the indexed thing cannot be found.
-parray_PrimTyCon :: TyCon -> Builtins -> TyCon
-parray_PrimTyCon tc bi = lookupEnvBuiltin "parray_PrimTyCon" (parray_PrimTyCons bi) (tyConName tc)
-
selTy :: Int -> Builtins -> Type
selTy = indexBuiltin "selTy" selTys
diff --git a/compiler/vectorise/Vectorise/Builtins/Initialise.hs b/compiler/vectorise/Vectorise/Builtins/Initialise.hs
index e2fddefacd..1ef8183869 100644
--- a/compiler/vectorise/Vectorise/Builtins/Initialise.hs
+++ b/compiler/vectorise/Vectorise/Builtins/Initialise.hs
@@ -2,7 +2,7 @@
module Vectorise.Builtins.Initialise (
-- * Initialisation
- initBuiltins, initBuiltinVars, initBuiltinTyCons
+ initBuiltins, initBuiltinVars
) where
import Vectorise.Builtins.Base
@@ -30,12 +30,7 @@ import Data.Array
--
initBuiltins :: DsM Builtins
initBuiltins
- = do { -- 'PArray': desugared array type
- ; parrayTyCon <- externalTyCon (fsLit "PArray")
- ; parray_tcs <- mapM externalTyCon (suffixed "PArray" aLL_DPH_PRIM_TYCONS)
- ; let parray_PrimTyCons = mkNameEnv (zip aLL_DPH_PRIM_TYCONS parray_tcs)
-
- -- 'PData': type family mapping array element types to array representation types
+ = do { -- 'PData': type family mapping array element types to array representation types
-- Not all backends use `PDatas`.
; pdataTyCon <- externalTyCon (fsLit "PData")
; pdatasTyCon <- externalTyCon (fsLit "PDatas")
@@ -80,7 +75,8 @@ initBuiltins
; scalar_map <- externalVar (fsLit "scalar_map")
; scalar_zip2 <- externalVar (fsLit "scalar_zipWith")
; scalar_zips <- mapM externalVar (numbered "scalar_zipWith" 3 mAX_DPH_SCALAR_ARGS)
- ; let scalarZips = listArray (1, mAX_DPH_SCALAR_ARGS) (scalar_map : scalar_zip2 : scalar_zips)
+ ; let scalarZips = listArray (1, mAX_DPH_SCALAR_ARGS)
+ (scalar_map : scalar_zip2 : scalar_zips)
-- Types and functions for generic type representations
; voidTyCon <- externalTyCon (fsLit "Void")
@@ -119,9 +115,7 @@ initBuiltins
; liftingContext <- liftM (\u -> mkSysLocal (fsLit "lc") u intPrimTy) newUnique
; return $ Builtins
- { parrayTyCon = parrayTyCon
- , parray_PrimTyCons = parray_PrimTyCons
- , pdataTyCon = pdataTyCon
+ { pdataTyCon = pdataTyCon
, pdatasTyCon = pdatasTyCon
, preprTyCon = preprTyCon
, prClass = prClass
@@ -196,20 +190,6 @@ initBuiltinVars (Builtins { })
where
mk_tup n name = (tupleCon BoxedTuple n, name)
--- |Get a list of names to `TyCon`s in the mock prelude.
---
-initBuiltinTyCons :: Builtins -> DsM [(Name, TyCon)]
--- FIXME: * must be replaced by VECTORISE pragmas!!!
--- * then we can remove 'parrayTyCon' from the Builtins as well
-initBuiltinTyCons bi
- = do
- return $ (tyConName funTyCon, closureTyCon bi)
- : (parrTyConName, parrayTyCon bi)
-
- -- FIXME: temporary
- : (tyConName $ parrayTyCon bi, parrayTyCon bi)
- : []
-
-- Auxilliary look up functions -----------------------------------------------
diff --git a/compiler/vectorise/Vectorise/Env.hs b/compiler/vectorise/Vectorise/Env.hs
index ffaf388b31..166262f744 100644
--- a/compiler/vectorise/Vectorise/Env.hs
+++ b/compiler/vectorise/Vectorise/Env.hs
@@ -10,7 +10,6 @@ module Vectorise.Env (
initGlobalEnv,
extendImportedVarsEnv,
extendFamEnv,
- extendTyConsEnv,
setPAFunsEnv,
setPRFunsEnv,
modVectInfo
@@ -182,12 +181,6 @@ extendFamEnv new genv
= genv { global_fam_inst_env = (g_fam_inst, extendFamInstEnvList l_fam_inst new) }
where (g_fam_inst, l_fam_inst) = global_fam_inst_env genv
--- |Extend the list of type constructors in an environment.
---
-extendTyConsEnv :: [(Name, TyCon)] -> GlobalEnv -> GlobalEnv
-extendTyConsEnv ps genv
- = genv { global_tycons = extendNameEnvList (global_tycons genv) ps }
-
-- |Set the list of PA functions in an environment.
--
setPAFunsEnv :: [(Name, Var)] -> GlobalEnv -> GlobalEnv
diff --git a/compiler/vectorise/Vectorise/Monad.hs b/compiler/vectorise/Vectorise/Monad.hs
index 0706e25f4f..a6bf6d973f 100644
--- a/compiler/vectorise/Vectorise/Monad.hs
+++ b/compiler/vectorise/Vectorise/Monad.hs
@@ -80,7 +80,6 @@ initV hsc_env guts info thing_inside
= do { -- set up tables of builtin entities
; builtins <- initBuiltins
; builtin_vars <- initBuiltinVars builtins
- ; builtin_tycons <- initBuiltinTyCons builtins
-- set up class and type family envrionments
; eps <- liftIO $ hscEPS hsc_env
@@ -91,7 +90,6 @@ initV hsc_env guts info thing_inside
-- construct the initial global environment
; let genv = extendImportedVarsEnv builtin_vars
- . extendTyConsEnv builtin_tycons
. setPAFunsEnv builtin_pas
. setPRFunsEnv builtin_prs
$ initGlobalEnv info (mg_vect_decls guts) instEnvs famInstEnvs
diff --git a/compiler/vectorise/Vectorise/Monad/Global.hs b/compiler/vectorise/Vectorise/Monad/Global.hs
index f393f01e92..bb8cc1affa 100644
--- a/compiler/vectorise/Vectorise/Monad/Global.hs
+++ b/compiler/vectorise/Vectorise/Monad/Global.hs
@@ -39,8 +39,11 @@ import TyCon
import DataCon
import NameEnv
import NameSet
+import Name
import VarEnv
import VarSet
+import Var as Var
+import FastString
import Outputable
@@ -70,8 +73,22 @@ defGlobalVar :: Var -> Var -> VM ()
defGlobalVar v v'
= do { traceVt "add global var mapping:" (ppr v <+> text "-->" <+> ppr v')
- ; updGEnv $ \env -> env { global_vars = extendVarEnv (global_vars env) v v' }
+ -- check for duplicate vectorisation
+ ; currentDef <- readGEnv $ \env -> lookupVarEnv (global_vars env) v
+ ; case currentDef of
+ Just old_v' -> cantVectorise "Variable is already vectorised:" $
+ ppr v <+> moduleOf v old_v'
+ Nothing -> return ()
+
+ ; updGEnv $ \env -> env { global_vars = extendVarEnv (global_vars env) v v' }
}
+ where
+ moduleOf var var' | var == var'
+ = ptext (sLit "vectorises to itself")
+ | Just mod <- nameModule_maybe (Var.varName var')
+ = ptext (sLit "in module") <+> ppr mod
+ | otherwise
+ = ptext (sLit "in the current module")
-- Vectorisation declarations -------------------------------------------------
@@ -120,8 +137,26 @@ lookupTyCon tc
-- |Add a mapping between plain and vectorised `TyCon`s to the global environment.
--
defTyCon :: TyCon -> TyCon -> VM ()
-defTyCon tc tc' = updGEnv $ \env ->
- env { global_tycons = extendNameEnv (global_tycons env) (tyConName tc) tc' }
+defTyCon tc tc'
+ = do { traceVt "add global tycon mapping:" (ppr tc <+> text "-->" <+> ppr tc')
+
+ -- check for duplicate vectorisation
+ ; currentDef <- readGEnv $ \env -> lookupNameEnv (global_tycons env) (tyConName tc)
+ ; case currentDef of
+ Just old_tc' -> cantVectorise "Type constructor or class is already vectorised:" $
+ ppr tc <+> moduleOf tc old_tc'
+ Nothing -> return ()
+
+ ; updGEnv $ \env ->
+ env { global_tycons = extendNameEnv (global_tycons env) (tyConName tc) tc' }
+ }
+ where
+ moduleOf tc tc' | tc == tc'
+ = ptext (sLit "vectorises to itself")
+ | Just mod <- nameModule_maybe (tyConName tc')
+ = ptext (sLit "in module") <+> ppr mod
+ | otherwise
+ = ptext (sLit "in the current module")
-- |Get the set of all vectorised type constructors.
--