{-# LANGUAGE CPP, TypeFamilies #-}
module TcSMonad (
WorkList(..), isEmptyWorkList, emptyWorkList,
extendWorkListNonEq, extendWorkListCt,
extendWorkListCts, extendWorkListEq, extendWorkListFunEq,
appendWorkList, extendWorkListImplic,
selectNextWorkItem,
workListSize, workListWantedCount,
getWorkList, updWorkListTcS,
TcS, runTcS, runTcSDeriveds, runTcSWithEvBinds,
failTcS, warnTcS, addErrTcS,
runTcSEqualities,
nestTcS, nestImplicTcS, setEvBindsTcS, buildImplication,
runTcPluginTcS, addUsedGRE, addUsedGREs,
panicTcS, traceTcS,
traceFireTcS, bumpStepCountTcS, csTraceTcS,
wrapErrTcS, wrapWarnTcS,
MaybeNew(..), freshGoals, isFresh, getEvTerm,
newTcEvBinds,
newWantedEq, emitNewWantedEq,
newWanted, newWantedEvVar, newWantedNC, newWantedEvVarNC, newDerivedNC,
newBoundEvVarId,
unifyTyVar, unflattenFmv, reportUnifications,
setEvBind, setWantedEq, setEqIfWanted,
setWantedEvTerm, setWantedEvBind, setEvBindIfWanted,
newEvVar, newGivenEvVar, newGivenEvVars,
emitNewDeriveds, emitNewDerivedEq,
checkReductionDepth,
getInstEnvs, getFamInstEnvs,
getTopEnv, getGblEnv, getLclEnv,
getTcEvBindsVar, getTcLevel,
getTcEvTyCoVars, getTcEvBindsMap, setTcEvBindsMap,
tcLookupClass, tcLookupId,
InertSet(..), InertCans(..),
updInertTcS, updInertCans, updInertDicts, updInertIrreds,
getNoGivenEqs, setInertCans,
getInertEqs, getInertCans, getInertGivens,
getInertInsols,
getTcSInerts, setTcSInerts,
matchableGivens, prohibitedSuperClassSolve,
getUnsolvedInerts,
removeInertCts, getPendingScDicts,
addInertCan, addInertEq, insertFunEq,
emitWorkNC, emitWork,
isImprovable,
kickOutAfterUnification,
addInertSafehask, insertSafeOverlapFailureTcS, updInertSafehask,
getSafeOverlapFailures,
DictMap, emptyDictMap, lookupInertDict, findDictsByClass, addDict,
addDictsByClass, delDict, foldDicts, filterDicts, findDict,
EqualCtList, findTyEqs, foldTyEqs, isInInertEqs,
lookupFlattenTyVar, lookupInertTyVar,
addSolvedDict, lookupSolvedDict,
foldIrreds,
lookupFlatCache, extendFlatCache, newFlattenSkolem,
updInertFunEqs, findFunEq,
findFunEqsByTyCon,
instDFunType,
newFlexiTcSTy, instFlexi, instFlexiX,
cloneMetaTyVar, demoteUnfilledFmv,
tcInstType, tcInstSkolTyVarsX,
TcLevel, isTouchableMetaTyVarTcS,
isFilledMetaTyVar_maybe, isFilledMetaTyVar,
zonkTyCoVarsAndFV, zonkTcType, zonkTcTypes, zonkTcTyVar, zonkCo,
zonkTyCoVarsAndFVList,
zonkSimples, zonkWC,
newTcRef, readTcRef, updTcRef,
getDefaultInfo, getDynFlags, getGlobalRdrEnvTcS,
matchFam, matchFamTcM,
checkWellStagedDFun,
pprEq
) where
#include "HsVersions.h"
import GhcPrelude
import HscTypes
import qualified Inst as TcM
import InstEnv
import FamInst
import FamInstEnv
import qualified TcRnMonad as TcM
import qualified TcMType as TcM
import qualified TcEnv as TcM
( checkWellStaged, topIdLvl, tcGetDefaultTys, tcLookupClass, tcLookupId )
import PrelNames( heqTyConKey, eqTyConKey )
import Kind
import TcType
import DynFlags
import Type
import Coercion
import Unify
import TcEvidence
import Class
import TyCon
import TcErrors ( solverDepthErrorTcS )
import Name
import RdrName ( GlobalRdrEnv, GlobalRdrElt )
import qualified RnEnv as TcM
import Var
import VarEnv
import VarSet
import Outputable
import Bag
import UniqSupply
import Util
import TcRnTypes
import Unique
import UniqFM
import UniqDFM
import Maybes
import TrieMap
import Control.Monad
import qualified Control.Monad.Fail as MonadFail
import MonadUtils
import Data.IORef
import Data.List ( foldl', partition )
#if defined(DEBUG)
import Digraph
import UniqSet
#endif
data WorkList
= WL { wl_eqs :: [Ct]
, wl_funeqs :: [Ct]
, wl_rest :: [Ct]
, wl_implics :: Bag Implication
}
appendWorkList :: WorkList -> WorkList -> WorkList
appendWorkList
(WL { wl_eqs = eqs1, wl_funeqs = funeqs1, wl_rest = rest1
, wl_implics = implics1 })
(WL { wl_eqs = eqs2, wl_funeqs = funeqs2, wl_rest = rest2
, wl_implics = implics2 })
= WL { wl_eqs = eqs1 ++ eqs2
, wl_funeqs = funeqs1 ++ funeqs2
, wl_rest = rest1 ++ rest2
, wl_implics = implics1 `unionBags` implics2 }
workListSize :: WorkList -> Int
workListSize (WL { wl_eqs = eqs, wl_funeqs = funeqs, wl_rest = rest })
= length eqs + length funeqs + length rest
workListWantedCount :: WorkList -> Int
workListWantedCount (WL { wl_eqs = eqs, wl_rest = rest })
= count isWantedCt eqs + count is_wanted rest
where
is_wanted ct
| CIrredCan { cc_ev = ev, cc_insol = insol } <- ct
= not insol && isWanted ev
| otherwise
= isWantedCt ct
extendWorkListEq :: Ct -> WorkList -> WorkList
extendWorkListEq ct wl = wl { wl_eqs = ct : wl_eqs wl }
extendWorkListFunEq :: Ct -> WorkList -> WorkList
extendWorkListFunEq ct wl = wl { wl_funeqs = ct : wl_funeqs wl }
extendWorkListNonEq :: Ct -> WorkList -> WorkList
extendWorkListNonEq ct wl = wl { wl_rest = ct : wl_rest wl }
extendWorkListDeriveds :: [CtEvidence] -> WorkList -> WorkList
extendWorkListDeriveds evs wl
= extendWorkListCts (map mkNonCanonical evs) wl
extendWorkListImplic :: Bag Implication -> WorkList -> WorkList
extendWorkListImplic implics wl = wl { wl_implics = implics `unionBags` wl_implics wl }
extendWorkListCt :: Ct -> WorkList -> WorkList
extendWorkListCt ct wl
= case classifyPredType (ctPred ct) of
EqPred NomEq ty1 _
| Just tc <- tcTyConAppTyCon_maybe ty1
, isTypeFamilyTyCon tc
-> extendWorkListFunEq ct wl
EqPred {}
-> extendWorkListEq ct wl
ClassPred cls _
| cls `hasKey` heqTyConKey
|| cls `hasKey` eqTyConKey
-> extendWorkListEq ct wl
_ -> extendWorkListNonEq ct wl
extendWorkListCts :: [Ct] -> WorkList -> WorkList
extendWorkListCts cts wl = foldr extendWorkListCt wl cts
isEmptyWorkList :: WorkList -> Bool
isEmptyWorkList (WL { wl_eqs = eqs, wl_funeqs = funeqs
, wl_rest = rest, wl_implics = implics })
= null eqs && null rest && null funeqs && isEmptyBag implics
emptyWorkList :: WorkList
emptyWorkList = WL { wl_eqs = [], wl_rest = []
, wl_funeqs = [], wl_implics = emptyBag }
selectWorkItem :: WorkList -> Maybe (Ct, WorkList)
selectWorkItem wl@(WL { wl_eqs = eqs, wl_funeqs = feqs
, wl_rest = rest })
| ct:cts <- eqs = Just (ct, wl { wl_eqs = cts })
| ct:fes <- feqs = Just (ct, wl { wl_funeqs = fes })
| ct:cts <- rest = Just (ct, wl { wl_rest = cts })
| otherwise = Nothing
getWorkList :: TcS WorkList
getWorkList = do { wl_var <- getTcSWorkListRef
; wrapTcS (TcM.readTcRef wl_var) }
selectNextWorkItem :: TcS (Maybe Ct)
selectNextWorkItem
= do { wl_var <- getTcSWorkListRef
; wl <- wrapTcS (TcM.readTcRef wl_var)
; case selectWorkItem wl of {
Nothing -> return Nothing ;
Just (ct, new_wl) ->
do { checkReductionDepth (ctLoc ct) (ctPred ct)
; wrapTcS (TcM.writeTcRef wl_var new_wl)
; return (Just ct) } } }
instance Outputable WorkList where
ppr (WL { wl_eqs = eqs, wl_funeqs = feqs
, wl_rest = rest, wl_implics = implics })
= text "WL" <+> (braces $
vcat [ ppUnless (null eqs) $
text "Eqs =" <+> vcat (map ppr eqs)
, ppUnless (null feqs) $
text "Funeqs =" <+> vcat (map ppr feqs)
, ppUnless (null rest) $
text "Non-eqs =" <+> vcat (map ppr rest)
, ppUnless (isEmptyBag implics) $
ifPprDebug (text "Implics =" <+> vcat (map ppr (bagToList implics)))
(text "(Implics omitted)")
])
data InertSet
= IS { inert_cans :: InertCans
, inert_fsks :: [(TcTyVar, TcType)]
, inert_flat_cache :: ExactFunEqMap (TcCoercion, TcType, CtFlavour)
, inert_solved_dicts :: DictMap CtEvidence
}
instance Outputable InertSet where
ppr is = vcat [ ppr $ inert_cans is
, ppUnless (null dicts) $
text "Solved dicts" <+> vcat (map ppr dicts) ]
where
dicts = bagToList (dictsToBag (inert_solved_dicts is))
emptyInert :: InertSet
emptyInert
= IS { inert_cans = IC { inert_count = 0
, inert_eqs = emptyDVarEnv
, inert_dicts = emptyDicts
, inert_safehask = emptyDicts
, inert_funeqs = emptyFunEqs
, inert_irreds = emptyCts }
, inert_flat_cache = emptyExactFunEqs
, inert_fsks = []
, inert_solved_dicts = emptyDictMap }
data InertCans
= IC { inert_eqs :: InertEqs
, inert_funeqs :: FunEqMap Ct
, inert_dicts :: DictMap Ct
, inert_safehask :: DictMap Ct
, inert_irreds :: Cts
, inert_count :: Int
}
type InertEqs = DTyVarEnv EqualCtList
type EqualCtList = [Ct]
instance Outputable InertCans where
ppr (IC { inert_eqs = eqs
, inert_funeqs = funeqs, inert_dicts = dicts
, inert_safehask = safehask, inert_irreds = irreds
, inert_count = count })
= braces $ vcat
[ ppUnless (isEmptyDVarEnv eqs) $
text "Equalities:"
<+> pprCts (foldDVarEnv (\eqs rest -> listToBag eqs `andCts` rest) emptyCts eqs)
, ppUnless (isEmptyTcAppMap funeqs) $
text "Type-function equalities =" <+> pprCts (funEqsToBag funeqs)
, ppUnless (isEmptyTcAppMap dicts) $
text "Dictionaries =" <+> pprCts (dictsToBag dicts)
, ppUnless (isEmptyTcAppMap safehask) $
text "Safe Haskell unsafe overlap =" <+> pprCts (dictsToBag safehask)
, ppUnless (isEmptyCts irreds) $
text "Irreds =" <+> pprCts irreds
, text "Unsolved goals =" <+> int count
]
maybeEmitShadow :: InertCans -> Ct -> TcS Ct
maybeEmitShadow ics ct
| let ev = ctEvidence ct
, CtWanted { ctev_pred = pred, ctev_loc = loc
, ctev_nosh = WDeriv } <- ev
, shouldSplitWD (inert_eqs ics) ct
= do { traceTcS "Emit derived shadow" (ppr ct)
; let derived_ev = CtDerived { ctev_pred = pred
, ctev_loc = loc }
shadow_ct = ct { cc_ev = derived_ev }
; emitWork [shadow_ct]
; let ev' = ev { ctev_nosh = WOnly }
ct' = ct { cc_ev = ev' }
; return ct' }
| otherwise
= return ct
shouldSplitWD :: InertEqs -> Ct -> Bool
shouldSplitWD inert_eqs (CFunEqCan { cc_tyargs = tys })
= should_split_match_args inert_eqs tys
shouldSplitWD inert_eqs (CDictCan { cc_tyargs = tys })
= should_split_match_args inert_eqs tys
shouldSplitWD inert_eqs (CTyEqCan { cc_tyvar = tv, cc_rhs = ty
, cc_eq_rel = eq_rel })
= tv `elemDVarEnv` inert_eqs
|| anyRewritableTyVar False eq_rel (canRewriteTv inert_eqs) ty
where
shouldSplitWD _ _ = False
should_split_match_args :: InertEqs -> [TcType] -> Bool
should_split_match_args inert_eqs tys
= any (anyRewritableTyVar True NomEq (canRewriteTv inert_eqs)) tys
canRewriteTv :: InertEqs -> EqRel -> TyVar -> Bool
canRewriteTv inert_eqs eq_rel tv
| Just (ct : _) <- lookupDVarEnv inert_eqs tv
, CTyEqCan { cc_eq_rel = eq_rel1 } <- ct
= eq_rel1 `eqCanRewrite` eq_rel
| otherwise
= False
isImprovable :: CtEvidence -> Bool
isImprovable (CtWanted { ctev_nosh = WOnly }) = False
isImprovable _ = True
addTyEq :: InertEqs -> TcTyVar -> Ct -> InertEqs
addTyEq old_eqs tv ct
= extendDVarEnv_C add_eq old_eqs tv [ct]
where
add_eq old_eqs _
| isWantedCt ct
, (eq1 : eqs) <- old_eqs
= eq1 : ct : eqs
| otherwise
= ct : old_eqs
foldTyEqs :: (Ct -> b -> b) -> InertEqs -> b -> b
foldTyEqs k eqs z
= foldDVarEnv (\cts z -> foldr k z cts) z eqs
findTyEqs :: InertCans -> TyVar -> EqualCtList
findTyEqs icans tv = lookupDVarEnv (inert_eqs icans) tv `orElse` []
delTyEq :: InertEqs -> TcTyVar -> TcType -> InertEqs
delTyEq m tv t = modifyDVarEnv (filter (not . isThisOne)) m tv
where isThisOne (CTyEqCan { cc_rhs = t1 }) = eqType t t1
isThisOne _ = False
lookupInertTyVar :: InertEqs -> TcTyVar -> Maybe TcType
lookupInertTyVar ieqs tv
= case lookupDVarEnv ieqs tv of
Just (CTyEqCan { cc_rhs = rhs, cc_eq_rel = NomEq } : _ ) -> Just rhs
_ -> Nothing
lookupFlattenTyVar :: InertEqs -> TcTyVar -> TcType
lookupFlattenTyVar ieqs ftv
= lookupInertTyVar ieqs ftv `orElse` mkTyVarTy ftv
addInertEq :: Ct -> TcS ()
addInertEq ct
= do { traceTcS "addInertEq {" $
text "Adding new inert equality:" <+> ppr ct
; ics <- getInertCans
; ct@(CTyEqCan { cc_tyvar = tv, cc_ev = ev, cc_eq_rel = eq_rel })
<- maybeEmitShadow ics ct
; (_, ics1) <- kickOutRewritable (ctEvFlavour ev, eq_rel) tv ics
; let ics2 = ics1 { inert_eqs = addTyEq (inert_eqs ics1) tv ct
, inert_count = bumpUnsolvedCount ev (inert_count ics1) }
; setInertCans ics2
; traceTcS "addInertEq }" $ empty }
addInertCan :: Ct -> TcS ()
addInertCan ct
= do { traceTcS "insertInertCan {" $
text "Trying to insert new non-eq inert item:" <+> ppr ct
; ics <- getInertCans
; ct <- maybeEmitShadow ics ct
; setInertCans (add_item ics ct)
; traceTcS "addInertCan }" $ empty }
add_item :: InertCans -> Ct -> InertCans
add_item ics item@(CFunEqCan { cc_fun = tc, cc_tyargs = tys })
= ics { inert_funeqs = insertFunEq (inert_funeqs ics) tc tys item }
add_item ics@(IC { inert_irreds = irreds, inert_count = count })
item@(CIrredCan { cc_ev = ev, cc_insol = insoluble })
= ics { inert_irreds = irreds `Bag.snocBag` item
, inert_count = if insoluble
then count
else bumpUnsolvedCount ev count }
add_item ics item@(CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys })
= ics { inert_dicts = addDict (inert_dicts ics) cls tys item
, inert_count = bumpUnsolvedCount ev (inert_count ics) }
add_item _ item
= pprPanic "upd_inert set: can't happen! Inserting " $
ppr item
bumpUnsolvedCount :: CtEvidence -> Int -> Int
bumpUnsolvedCount ev n | isWanted ev = n+1
| otherwise = n
kickOutRewritable :: CtFlavourRole
-> TcTyVar
-> InertCans
-> TcS (Int, InertCans)
kickOutRewritable new_fr new_tv ics
= do { let (kicked_out, ics') = kick_out_rewritable new_fr new_tv ics
n_kicked = workListSize kicked_out
; unless (n_kicked == 0) $
do { updWorkListTcS (appendWorkList kicked_out)
; csTraceTcS $
hang (text "Kick out, tv =" <+> ppr new_tv)
2 (vcat [ text "n-kicked =" <+> int n_kicked
, text "kicked_out =" <+> ppr kicked_out
, text "Residual inerts =" <+> ppr ics' ]) }
; return (n_kicked, ics') }
kick_out_rewritable :: CtFlavourRole
-> TcTyVar
-> InertCans
-> (WorkList, InertCans)
kick_out_rewritable new_fr new_tv ics@(IC { inert_eqs = tv_eqs
, inert_dicts = dictmap
, inert_safehask = safehask
, inert_funeqs = funeqmap
, inert_irreds = irreds
, inert_count = n })
| not (new_fr `eqMayRewriteFR` new_fr)
= (emptyWorkList, ics)
| otherwise
= (kicked_out, inert_cans_in)
where
inert_cans_in = IC { inert_eqs = tv_eqs_in
, inert_dicts = dicts_in
, inert_safehask = safehask
, inert_funeqs = feqs_in
, inert_irreds = irs_in
, inert_count = n - workListWantedCount kicked_out }
kicked_out :: WorkList
kicked_out = foldrBag extendWorkListCt
(emptyWorkList { wl_eqs = tv_eqs_out
, wl_funeqs = feqs_out })
(dicts_out `andCts` irs_out)
(tv_eqs_out, tv_eqs_in) = foldDVarEnv kick_out_eqs ([], emptyDVarEnv) tv_eqs
(feqs_out, feqs_in) = partitionFunEqs kick_out_ct funeqmap
(dicts_out, dicts_in) = partitionDicts kick_out_ct dictmap
(irs_out, irs_in) = partitionBag kick_out_ct irreds
(_, new_role) = new_fr
fr_can_rewrite_ty :: EqRel -> Type -> Bool
fr_can_rewrite_ty role ty = anyRewritableTyVar False role
fr_can_rewrite_tv ty
fr_can_rewrite_tv :: EqRel -> TyVar -> Bool
fr_can_rewrite_tv role tv = new_role `eqCanRewrite` role
&& tv == new_tv
fr_may_rewrite :: CtFlavourRole -> Bool
fr_may_rewrite fs = new_fr `eqMayRewriteFR` fs
kick_out_ct :: Ct -> Bool
kick_out_ct ct | let fs@(_,role) = ctFlavourRole ct
= fr_may_rewrite fs
&& fr_can_rewrite_ty role (ctPred ct)
kick_out_eqs :: EqualCtList -> ([Ct], DTyVarEnv EqualCtList)
-> ([Ct], DTyVarEnv EqualCtList)
kick_out_eqs eqs (acc_out, acc_in)
= (eqs_out ++ acc_out, case eqs_in of
[] -> acc_in
(eq1:_) -> extendDVarEnv acc_in (cc_tyvar eq1) eqs_in)
where
(eqs_out, eqs_in) = partition kick_out_eq eqs
kick_out_eq (CTyEqCan { cc_tyvar = tv, cc_rhs = rhs_ty
, cc_ev = ev, cc_eq_rel = eq_rel })
| not (fr_may_rewrite fs)
= False
| tv == new_tv = True
| kick_out_for_inertness = True
| kick_out_for_completeness = True
| otherwise = False
where
fs = (ctEvFlavour ev, eq_rel)
kick_out_for_inertness
= (fs `eqMayRewriteFR` fs)
&& not (fs `eqMayRewriteFR` new_fr)
&& fr_can_rewrite_ty eq_rel rhs_ty
kick_out_for_completeness
= case eq_rel of
NomEq -> rhs_ty `eqType` mkTyVarTy new_tv
ReprEq -> isTyVarHead new_tv rhs_ty
kick_out_eq ct = pprPanic "keep_eq" (ppr ct)
kickOutAfterUnification :: TcTyVar -> TcS Int
kickOutAfterUnification new_tv
= do { ics <- getInertCans
; (n_kicked, ics2) <- kickOutRewritable (Given,NomEq)
new_tv ics
; setInertCans ics2
; return n_kicked }
addInertSafehask :: InertCans -> Ct -> InertCans
addInertSafehask ics item@(CDictCan { cc_class = cls, cc_tyargs = tys })
= ics { inert_safehask = addDict (inert_dicts ics) cls tys item }
addInertSafehask _ item
= pprPanic "addInertSafehask: can't happen! Inserting " $ ppr item
insertSafeOverlapFailureTcS :: Ct -> TcS ()
insertSafeOverlapFailureTcS item
= updInertCans (\ics -> addInertSafehask ics item)
getSafeOverlapFailures :: TcS Cts
getSafeOverlapFailures
= do { IC { inert_safehask = safehask } <- getInertCans
; return $ foldDicts consCts safehask emptyCts }
addSolvedDict :: CtEvidence -> Class -> [Type] -> TcS ()
addSolvedDict item cls tys
| isIPPred (ctEvPred item)
= return ()
| otherwise
= do { traceTcS "updSolvedSetTcs:" $ ppr item
; updInertTcS $ \ ics ->
ics { inert_solved_dicts = addDict (inert_solved_dicts ics) cls tys item } }
updInertTcS :: (InertSet -> InertSet) -> TcS ()
updInertTcS upd_fn
= do { is_var <- getTcSInertsRef
; wrapTcS (do { curr_inert <- TcM.readTcRef is_var
; TcM.writeTcRef is_var (upd_fn curr_inert) }) }
getInertCans :: TcS InertCans
getInertCans = do { inerts <- getTcSInerts; return (inert_cans inerts) }
setInertCans :: InertCans -> TcS ()
setInertCans ics = updInertTcS $ \ inerts -> inerts { inert_cans = ics }
updRetInertCans :: (InertCans -> (a, InertCans)) -> TcS a
updRetInertCans upd_fn
= do { is_var <- getTcSInertsRef
; wrapTcS (do { inerts <- TcM.readTcRef is_var
; let (res, cans') = upd_fn (inert_cans inerts)
; TcM.writeTcRef is_var (inerts { inert_cans = cans' })
; return res }) }
updInertCans :: (InertCans -> InertCans) -> TcS ()
updInertCans upd_fn
= updInertTcS $ \ inerts -> inerts { inert_cans = upd_fn (inert_cans inerts) }
updInertDicts :: (DictMap Ct -> DictMap Ct) -> TcS ()
updInertDicts upd_fn
= updInertCans $ \ ics -> ics { inert_dicts = upd_fn (inert_dicts ics) }
updInertSafehask :: (DictMap Ct -> DictMap Ct) -> TcS ()
updInertSafehask upd_fn
= updInertCans $ \ ics -> ics { inert_safehask = upd_fn (inert_safehask ics) }
updInertFunEqs :: (FunEqMap Ct -> FunEqMap Ct) -> TcS ()
updInertFunEqs upd_fn
= updInertCans $ \ ics -> ics { inert_funeqs = upd_fn (inert_funeqs ics) }
updInertIrreds :: (Cts -> Cts) -> TcS ()
updInertIrreds upd_fn
= updInertCans $ \ ics -> ics { inert_irreds = upd_fn (inert_irreds ics) }
getInertEqs :: TcS (DTyVarEnv EqualCtList)
getInertEqs = do { inert <- getInertCans; return (inert_eqs inert) }
getInertInsols :: TcS Cts
getInertInsols = do { inert <- getInertCans
; return (filterBag insolubleEqCt (inert_irreds inert)) }
getInertGivens :: TcS [Ct]
getInertGivens
= do { inerts <- getInertCans
; let all_cts = foldDicts (:) (inert_dicts inerts)
$ foldFunEqs (:) (inert_funeqs inerts)
$ concat (dVarEnvElts (inert_eqs inerts))
; return (filter isGivenCt all_cts) }
getPendingScDicts :: TcS [Ct]
getPendingScDicts = updRetInertCans get_sc_dicts
where
get_sc_dicts ic@(IC { inert_dicts = dicts })
= (sc_pend_dicts, ic')
where
ic' = ic { inert_dicts = foldr add dicts sc_pend_dicts }
sc_pend_dicts :: [Ct]
sc_pend_dicts = foldDicts get_pending dicts []
get_pending :: Ct -> [Ct] -> [Ct]
get_pending dict dicts
| Just dict' <- isPendingScDict dict = dict' : dicts
| otherwise = dicts
add :: Ct -> DictMap Ct -> DictMap Ct
add ct@(CDictCan { cc_class = cls, cc_tyargs = tys }) dicts
= addDict dicts cls tys ct
add ct _ = pprPanic "getPendingScDicts" (ppr ct)
getUnsolvedInerts :: TcS ( Bag Implication
, Cts
, Cts
, Cts )
getUnsolvedInerts
= do { IC { inert_eqs = tv_eqs
, inert_funeqs = fun_eqs
, inert_irreds = irreds
, inert_dicts = idicts
} <- getInertCans
; let unsolved_tv_eqs = foldTyEqs add_if_unsolved tv_eqs emptyCts
unsolved_fun_eqs = foldFunEqs add_if_wanted fun_eqs emptyCts
unsolved_irreds = Bag.filterBag is_unsolved irreds
unsolved_dicts = foldDicts add_if_unsolved idicts emptyCts
unsolved_others = unsolved_irreds `unionBags` unsolved_dicts
; implics <- getWorkListImplics
; traceTcS "getUnsolvedInerts" $
vcat [ text " tv eqs =" <+> ppr unsolved_tv_eqs
, text "fun eqs =" <+> ppr unsolved_fun_eqs
, text "others =" <+> ppr unsolved_others
, text "implics =" <+> ppr implics ]
; return ( implics, unsolved_tv_eqs, unsolved_fun_eqs, unsolved_others) }
where
add_if_unsolved :: Ct -> Cts -> Cts
add_if_unsolved ct cts | is_unsolved ct = ct `consCts` cts
| otherwise = cts
is_unsolved ct = not (isGivenCt ct)
add_if_wanted ct cts | isWantedCt ct = ct `consCts` cts
| otherwise = cts
isInInertEqs :: DTyVarEnv EqualCtList -> TcTyVar -> TcType -> Bool
isInInertEqs eqs tv rhs
= case lookupDVarEnv eqs tv of
Nothing -> False
Just cts -> any (same_pred rhs) cts
where
same_pred rhs ct
| CTyEqCan { cc_rhs = rhs2, cc_eq_rel = eq_rel } <- ct
, NomEq <- eq_rel
, rhs `eqType` rhs2 = True
| otherwise = False
getNoGivenEqs :: TcLevel
-> [TcTyVar]
-> TcS ( Bool
, Cts )
getNoGivenEqs tclvl skol_tvs
= do { inerts@(IC { inert_eqs = ieqs, inert_irreds = irreds })
<- getInertCans
; let has_given_eqs = foldrBag ((||) . ct_given_here) False irreds
|| anyDVarEnv eqs_given_here ieqs
insols = filterBag insolubleEqCt irreds
; traceTcS "getNoGivenEqs" (vcat [ ppr has_given_eqs, ppr inerts
, ppr insols])
; return (not has_given_eqs, insols) }
where
eqs_given_here :: EqualCtList -> Bool
eqs_given_here [ct@(CTyEqCan { cc_tyvar = tv })]
= not (skolem_bound_here tv) && ct_given_here ct
eqs_given_here _ = False
ct_given_here :: Ct -> Bool
ct_given_here ct = isGiven ev
&& tclvl == ctLocLevel (ctEvLoc ev)
where
ev = ctEvidence ct
skol_tv_set = mkVarSet skol_tvs
skolem_bound_here tv
= case tcTyVarDetails tv of
SkolemTv {} -> tv `elemVarSet` skol_tv_set
_ -> False
matchableGivens :: CtLoc -> PredType -> InertSet -> Cts
matchableGivens loc_w pred (IS { inert_cans = inert_cans })
= filterBag matchable_given all_relevant_givens
where
all_relevant_givens :: Cts
all_relevant_givens
| Just (clas, _) <- getClassPredTys_maybe pred
= findDictsByClass (inert_dicts inert_cans) clas
`unionBags` inert_irreds inert_cans
| otherwise
= inert_irreds inert_cans
matchable_given :: Ct -> Bool
matchable_given ct
| CtGiven { ctev_loc = loc_g } <- ctev
, Just _ <- tcUnifyTys bind_meta_tv [ctEvPred ctev] [pred]
, not (prohibitedSuperClassSolve loc_g loc_w)
= True
| otherwise
= False
where
ctev = cc_ev ct
bind_meta_tv :: TcTyVar -> BindFlag
bind_meta_tv tv | isMetaTyVar tv
, not (isFskTyVar tv) = BindMe
| otherwise = Skolem
prohibitedSuperClassSolve :: CtLoc -> CtLoc -> Bool
prohibitedSuperClassSolve from_loc solve_loc
| GivenOrigin (InstSC given_size) <- ctLocOrigin from_loc
, ScOrigin wanted_size <- ctLocOrigin solve_loc
= given_size >= wanted_size
| otherwise
= False
removeInertCts :: [Ct] -> InertCans -> InertCans
removeInertCts cts icans = foldl' removeInertCt icans cts
removeInertCt :: InertCans -> Ct -> InertCans
removeInertCt is ct =
case ct of
CDictCan { cc_class = cl, cc_tyargs = tys } ->
is { inert_dicts = delDict (inert_dicts is) cl tys }
CFunEqCan { cc_fun = tf, cc_tyargs = tys } ->
is { inert_funeqs = delFunEq (inert_funeqs is) tf tys }
CTyEqCan { cc_tyvar = x, cc_rhs = ty } ->
is { inert_eqs = delTyEq (inert_eqs is) x ty }
CIrredCan {} -> panic "removeInertCt: CIrredEvCan"
CNonCanonical {} -> panic "removeInertCt: CNonCanonical"
CHoleCan {} -> panic "removeInertCt: CHoleCan"
lookupFlatCache :: TyCon -> [Type] -> TcS (Maybe (TcCoercion, TcType, CtFlavour))
lookupFlatCache fam_tc tys
= do { IS { inert_flat_cache = flat_cache
, inert_cans = IC { inert_funeqs = inert_funeqs } } <- getTcSInerts
; return (firstJusts [lookup_inerts inert_funeqs,
lookup_flats flat_cache]) }
where
lookup_inerts inert_funeqs
| Just (CFunEqCan { cc_ev = ctev, cc_fsk = fsk, cc_tyargs = xis })
<- findFunEq inert_funeqs fam_tc tys
, tys `eqTypes` xis
= Just (ctEvCoercion ctev, mkTyVarTy fsk, ctEvFlavour ctev)
| otherwise = Nothing
lookup_flats flat_cache = findExactFunEq flat_cache fam_tc tys
lookupInInerts :: CtLoc -> TcPredType -> TcS (Maybe CtEvidence)
lookupInInerts loc pty
| ClassPred cls tys <- classifyPredType pty
= do { inerts <- getTcSInerts
; return (lookupSolvedDict inerts loc cls tys `mplus`
lookupInertDict (inert_cans inerts) loc cls tys) }
| otherwise
= return Nothing
lookupInertDict :: InertCans -> CtLoc -> Class -> [Type] -> Maybe CtEvidence
lookupInertDict (IC { inert_dicts = dicts }) loc cls tys
= case findDict dicts loc cls tys of
Just ct -> Just (ctEvidence ct)
_ -> Nothing
lookupSolvedDict :: InertSet -> CtLoc -> Class -> [Type] -> Maybe CtEvidence
lookupSolvedDict (IS { inert_solved_dicts = solved }) loc cls tys
= case findDict solved loc cls tys of
Just ev -> Just ev
_ -> Nothing
foldIrreds :: (Ct -> b -> b) -> Cts -> b -> b
foldIrreds k irreds z = foldrBag k z irreds
type TcAppMap a = UniqDFM (ListMap LooseTypeMap a)
isEmptyTcAppMap :: TcAppMap a -> Bool
isEmptyTcAppMap m = isNullUDFM m
emptyTcAppMap :: TcAppMap a
emptyTcAppMap = emptyUDFM
findTcApp :: TcAppMap a -> Unique -> [Type] -> Maybe a
findTcApp m u tys = do { tys_map <- lookupUDFM m u
; lookupTM tys tys_map }
delTcApp :: TcAppMap a -> Unique -> [Type] -> TcAppMap a
delTcApp m cls tys = adjustUDFM (deleteTM tys) m cls
insertTcApp :: TcAppMap a -> Unique -> [Type] -> a -> TcAppMap a
insertTcApp m cls tys ct = alterUDFM alter_tm m cls
where
alter_tm mb_tm = Just (insertTM tys ct (mb_tm `orElse` emptyTM))
filterTcAppMap :: (Ct -> Bool) -> TcAppMap Ct -> TcAppMap Ct
filterTcAppMap f m
= mapUDFM do_tm m
where
do_tm tm = foldTM insert_mb tm emptyTM
insert_mb ct tm
| f ct = insertTM tys ct tm
| otherwise = tm
where
tys = case ct of
CFunEqCan { cc_tyargs = tys } -> tys
CDictCan { cc_tyargs = tys } -> tys
_ -> pprPanic "filterTcAppMap" (ppr ct)
tcAppMapToBag :: TcAppMap a -> Bag a
tcAppMapToBag m = foldTcAppMap consBag m emptyBag
foldTcAppMap :: (a -> b -> b) -> TcAppMap a -> b -> b
foldTcAppMap k m z = foldUDFM (foldTM k) z m
type DictMap a = TcAppMap a
emptyDictMap :: DictMap a
emptyDictMap = emptyTcAppMap
findDict :: DictMap a -> CtLoc -> Class -> [Type] -> Maybe a
findDict m loc cls tys
| isCTupleClass cls
, any hasIPPred tys
= Nothing
| Just {} <- isCallStackPred cls tys
, OccurrenceOf {} <- ctLocOrigin loc
= Nothing
| otherwise
= findTcApp m (getUnique cls) tys
findDictsByClass :: DictMap a -> Class -> Bag a
findDictsByClass m cls
| Just tm <- lookupUDFM m cls = foldTM consBag tm emptyBag
| otherwise = emptyBag
delDict :: DictMap a -> Class -> [Type] -> DictMap a
delDict m cls tys = delTcApp m (getUnique cls) tys
addDict :: DictMap a -> Class -> [Type] -> a -> DictMap a
addDict m cls tys item = insertTcApp m (getUnique cls) tys item
addDictsByClass :: DictMap Ct -> Class -> Bag Ct -> DictMap Ct
addDictsByClass m cls items
= addToUDFM m cls (foldrBag add emptyTM items)
where
add ct@(CDictCan { cc_tyargs = tys }) tm = insertTM tys ct tm
add ct _ = pprPanic "addDictsByClass" (ppr ct)
filterDicts :: (Ct -> Bool) -> DictMap Ct -> DictMap Ct
filterDicts f m = filterTcAppMap f m
partitionDicts :: (Ct -> Bool) -> DictMap Ct -> (Bag Ct, DictMap Ct)
partitionDicts f m = foldTcAppMap k m (emptyBag, emptyDicts)
where
k ct (yeses, noes) | f ct = (ct `consBag` yeses, noes)
| otherwise = (yeses, add ct noes)
add ct@(CDictCan { cc_class = cls, cc_tyargs = tys }) m
= addDict m cls tys ct
add ct _ = pprPanic "partitionDicts" (ppr ct)
dictsToBag :: DictMap a -> Bag a
dictsToBag = tcAppMapToBag
foldDicts :: (a -> b -> b) -> DictMap a -> b -> b
foldDicts = foldTcAppMap
emptyDicts :: DictMap a
emptyDicts = emptyTcAppMap
type FunEqMap a = TcAppMap a
emptyFunEqs :: TcAppMap a
emptyFunEqs = emptyTcAppMap
findFunEq :: FunEqMap a -> TyCon -> [Type] -> Maybe a
findFunEq m tc tys = findTcApp m (getUnique tc) tys
funEqsToBag :: FunEqMap a -> Bag a
funEqsToBag m = foldTcAppMap consBag m emptyBag
findFunEqsByTyCon :: FunEqMap a -> TyCon -> [a]
findFunEqsByTyCon m tc
| Just tm <- lookupUDFM m tc = foldTM (:) tm []
| otherwise = []
foldFunEqs :: (a -> b -> b) -> FunEqMap a -> b -> b
foldFunEqs = foldTcAppMap
insertFunEq :: FunEqMap a -> TyCon -> [Type] -> a -> FunEqMap a
insertFunEq m tc tys val = insertTcApp m (getUnique tc) tys val
partitionFunEqs :: (Ct -> Bool) -> FunEqMap Ct -> ([Ct], FunEqMap Ct)
partitionFunEqs f m = (yeses, foldr del m yeses)
where
yeses = foldTcAppMap k m []
k ct yeses | f ct = ct : yeses
| otherwise = yeses
del (CFunEqCan { cc_fun = tc, cc_tyargs = tys }) m
= delFunEq m tc tys
del ct _ = pprPanic "partitionFunEqs" (ppr ct)
delFunEq :: FunEqMap a -> TyCon -> [Type] -> FunEqMap a
delFunEq m tc tys = delTcApp m (getUnique tc) tys
type ExactFunEqMap a = UniqFM (ListMap TypeMap a)
emptyExactFunEqs :: ExactFunEqMap a
emptyExactFunEqs = emptyUFM
findExactFunEq :: ExactFunEqMap a -> TyCon -> [Type] -> Maybe a
findExactFunEq m tc tys = do { tys_map <- lookupUFM m (getUnique tc)
; lookupTM tys tys_map }
insertExactFunEq :: ExactFunEqMap a -> TyCon -> [Type] -> a -> ExactFunEqMap a
insertExactFunEq m tc tys val = alterUFM alter_tm m (getUnique tc)
where alter_tm mb_tm = Just (insertTM tys val (mb_tm `orElse` emptyTM))
data TcSEnv
= TcSEnv {
tcs_ev_binds :: EvBindsVar,
tcs_unified :: IORef Int,
tcs_count :: IORef Int,
tcs_inerts :: IORef InertSet,
tcs_worklist :: IORef WorkList
}
newtype TcS a = TcS { unTcS :: TcSEnv -> TcM a }
instance Functor TcS where
fmap f m = TcS $ fmap f . unTcS m
instance Applicative TcS where
pure x = TcS (\_ -> return x)
(<*>) = ap
instance Monad TcS where
fail = MonadFail.fail
m >>= k = TcS (\ebs -> unTcS m ebs >>= \r -> unTcS (k r) ebs)
instance MonadFail.MonadFail TcS where
fail err = TcS (\_ -> fail err)
instance MonadUnique TcS where
getUniqueSupplyM = wrapTcS getUniqueSupplyM
wrapTcS :: TcM a -> TcS a
wrapTcS = TcS . const
wrapErrTcS :: TcM a -> TcS a
wrapErrTcS = wrapTcS
wrapWarnTcS :: TcM a -> TcS a
wrapWarnTcS = wrapTcS
failTcS, panicTcS :: SDoc -> TcS a
warnTcS :: WarningFlag -> SDoc -> TcS ()
addErrTcS :: SDoc -> TcS ()
failTcS = wrapTcS . TcM.failWith
warnTcS flag = wrapTcS . TcM.addWarn (Reason flag)
addErrTcS = wrapTcS . TcM.addErr
panicTcS doc = pprPanic "TcCanonical" doc
traceTcS :: String -> SDoc -> TcS ()
traceTcS herald doc = wrapTcS (TcM.traceTc herald doc)
runTcPluginTcS :: TcPluginM a -> TcS a
runTcPluginTcS m = wrapTcS . runTcPluginM m =<< getTcEvBindsVar
instance HasDynFlags TcS where
getDynFlags = wrapTcS getDynFlags
getGlobalRdrEnvTcS :: TcS GlobalRdrEnv
getGlobalRdrEnvTcS = wrapTcS TcM.getGlobalRdrEnv
bumpStepCountTcS :: TcS ()
bumpStepCountTcS = TcS $ \env -> do { let ref = tcs_count env
; n <- TcM.readTcRef ref
; TcM.writeTcRef ref (n+1) }
csTraceTcS :: SDoc -> TcS ()
csTraceTcS doc
= wrapTcS $ csTraceTcM (return doc)
traceFireTcS :: CtEvidence -> SDoc -> TcS ()
traceFireTcS ev doc
= TcS $ \env -> csTraceTcM $
do { n <- TcM.readTcRef (tcs_count env)
; tclvl <- TcM.getTcLevel
; return (hang (text "Step" <+> int n
<> brackets (text "l:" <> ppr tclvl <> comma <>
text "d:" <> ppr (ctLocDepth (ctEvLoc ev)))
<+> doc <> colon)
4 (ppr ev)) }
csTraceTcM :: TcM SDoc -> TcM ()
csTraceTcM mk_doc
= do { dflags <- getDynFlags
; when ( dopt Opt_D_dump_cs_trace dflags
|| dopt Opt_D_dump_tc_trace dflags )
( do { msg <- mk_doc
; TcM.traceTcRn Opt_D_dump_cs_trace msg }) }
runTcS :: TcS a
-> TcM (a, EvBindMap)
runTcS tcs
= do { ev_binds_var <- TcM.newTcEvBinds
; res <- runTcSWithEvBinds ev_binds_var tcs
; ev_binds <- TcM.getTcEvBindsMap ev_binds_var
; return (res, ev_binds) }
runTcSDeriveds :: TcS a -> TcM a
runTcSDeriveds tcs
= do { ev_binds_var <- TcM.newTcEvBinds
; runTcSWithEvBinds ev_binds_var tcs }
runTcSEqualities :: TcS a -> TcM a
runTcSEqualities thing_inside
= do { ev_binds_var <- TcM.newTcEvBinds
; runTcSWithEvBinds ev_binds_var thing_inside }
runTcSWithEvBinds :: EvBindsVar
-> TcS a
-> TcM a
runTcSWithEvBinds ev_binds_var tcs
= do { unified_var <- TcM.newTcRef 0
; step_count <- TcM.newTcRef 0
; inert_var <- TcM.newTcRef emptyInert
; wl_var <- TcM.newTcRef emptyWorkList
; let env = TcSEnv { tcs_ev_binds = ev_binds_var
, tcs_unified = unified_var
, tcs_count = step_count
, tcs_inerts = inert_var
, tcs_worklist = wl_var }
; res <- unTcS tcs env
; count <- TcM.readTcRef step_count
; when (count > 0) $
csTraceTcM $ return (text "Constraint solver steps =" <+> int count)
; unflattenGivens inert_var
#if defined(DEBUG)
; ev_binds <- TcM.getTcEvBindsMap ev_binds_var
; checkForCyclicBinds ev_binds
#endif
; return res }
----------------------------
#if defined(DEBUG)
checkForCyclicBinds :: EvBindMap -> TcM ()
checkForCyclicBinds ev_binds_map
| null cycles
= return ()
| null coercion_cycles
= TcM.traceTc "Cycle in evidence binds" $ ppr cycles
| otherwise
= pprPanic "Cycle in coercion bindings" $ ppr coercion_cycles
where
ev_binds = evBindMapBinds ev_binds_map
cycles :: [[EvBind]]
cycles = [c | CyclicSCC c <- stronglyConnCompFromEdgedVerticesUniq edges]
coercion_cycles = [c | c <- cycles, any is_co_bind c]
is_co_bind (EvBind { eb_lhs = b }) = isEqPred (varType b)
edges :: [ Node EvVar EvBind ]
edges = [ DigraphNode bind bndr (nonDetEltsUniqSet (evVarsOfTerm rhs))
| bind@(EvBind { eb_lhs = bndr, eb_rhs = rhs}) <- bagToList ev_binds ]
#endif
setEvBindsTcS :: EvBindsVar -> TcS a -> TcS a
setEvBindsTcS ref (TcS thing_inside)
= TcS $ \ env -> thing_inside (env { tcs_ev_binds = ref })
nestImplicTcS :: EvBindsVar
-> TcLevel -> TcS a
-> TcS a
nestImplicTcS ref inner_tclvl (TcS thing_inside)
= TcS $ \ TcSEnv { tcs_unified = unified_var
, tcs_inerts = old_inert_var
, tcs_count = count
} ->
do { inerts <- TcM.readTcRef old_inert_var
; let nest_inert = emptyInert { inert_cans = inert_cans inerts
, inert_solved_dicts = inert_solved_dicts inerts }
; new_inert_var <- TcM.newTcRef nest_inert
; new_wl_var <- TcM.newTcRef emptyWorkList
; let nest_env = TcSEnv { tcs_ev_binds = ref
, tcs_unified = unified_var
, tcs_count = count
, tcs_inerts = new_inert_var
, tcs_worklist = new_wl_var }
; res <- TcM.setTcLevel inner_tclvl $
thing_inside nest_env
; unflattenGivens new_inert_var
#if defined(DEBUG)
; ev_binds <- TcM.getTcEvBindsMap ref
; checkForCyclicBinds ev_binds
#endif
; return res }
{- Note [Do not inherit the flat cache]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We do not want to inherit the flat cache when processing nested
implications. Consider
a ~ F b, forall c. b~Int => blah
If we have F b ~ fsk in the flat-cache, and we push that into the
nested implication, we might miss that F b can be rewritten to F Int,
and hence perhpas solve it. Moreover, the fsk from outside is
flattened out after solving the outer level, but and we don't
do that flattening recursively.
-}
nestTcS :: TcS a -> TcS a
-- Use the current untouchables, augmenting the current
-- evidence bindings, and solved dictionaries
-- But have no effect on the InertCans, or on the inert_flat_cache
-- (we want to inherit the latter from processing the Givens)
nestTcS (TcS thing_inside)
= TcS $ \ env@(TcSEnv { tcs_inerts = inerts_var }) ->
do { inerts <- TcM.readTcRef inerts_var
; new_inert_var <- TcM.newTcRef inerts
; new_wl_var <- TcM.newTcRef emptyWorkList
; let nest_env = env { tcs_inerts = new_inert_var
, tcs_worklist = new_wl_var }
; res <- thing_inside nest_env
; new_inerts <- TcM.readTcRef new_inert_var
-- we want to propogate the safe haskell failures
; let old_ic = inert_cans inerts
new_ic = inert_cans new_inerts
nxt_ic = old_ic { inert_safehask = inert_safehask new_ic }
; TcM.writeTcRef inerts_var -- See Note [Propagate the solved dictionaries]
(inerts { inert_solved_dicts = inert_solved_dicts new_inerts
, inert_cans = nxt_ic })
; return res }
buildImplication :: SkolemInfo
-> [TcTyVar] -- Skolems
-> [EvVar] -- Givens
-> TcS result
-> TcS (Bag Implication, TcEvBinds, result)
-- Just like TcUnify.buildImplication, but in the TcS monnad,
-- using the work-list to gather the constraints
buildImplication skol_info skol_tvs givens (TcS thing_inside)
= TcS $ \ env ->
do { new_wl_var <- TcM.newTcRef emptyWorkList
; tc_lvl <- TcM.getTcLevel
; let new_tclvl = pushTcLevel tc_lvl
; res <- TcM.setTcLevel new_tclvl $
thing_inside (env { tcs_worklist = new_wl_var })
; wl@WL { wl_eqs = eqs } <- TcM.readTcRef new_wl_var
; if null eqs
then return (emptyBag, emptyTcEvBinds, res)
else
do { env <- TcM.getLclEnv
; ev_binds_var <- TcM.newTcEvBinds
; let wc = ASSERT2( null (wl_funeqs wl) && null (wl_rest wl) &&
null (wl_implics wl), ppr wl )
WC { wc_simple = listToCts eqs
, wc_impl = emptyBag }
imp = newImplication { ic_tclvl = new_tclvl
, ic_skols = skol_tvs
, ic_given = givens
, ic_wanted = wc
, ic_binds = ev_binds_var
, ic_env = env
, ic_info = skol_info }
; return (unitBag imp, TcEvBinds ev_binds_var, res) } }
{-
Note [Propagate the solved dictionaries]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's really quite important that nestTcS does not discard the solved
dictionaries from the thing_inside.
Consider
Eq [a]
forall b. empty => Eq [a]
We solve the simple (Eq [a]), under nestTcS, and then turn our attention to
the implications. It's definitely fine to use the solved dictionaries on
the inner implications, and it can make a signficant performance difference
if you do so.
-}
-- Getters and setters of TcEnv fields
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Getter of inerts and worklist
getTcSInertsRef :: TcS (IORef InertSet)
getTcSInertsRef = TcS (return . tcs_inerts)
getTcSWorkListRef :: TcS (IORef WorkList)
getTcSWorkListRef = TcS (return . tcs_worklist)
getTcSInerts :: TcS InertSet
getTcSInerts = getTcSInertsRef >>= wrapTcS . (TcM.readTcRef)
setTcSInerts :: InertSet -> TcS ()
setTcSInerts ics = do { r <- getTcSInertsRef; wrapTcS (TcM.writeTcRef r ics) }
getWorkListImplics :: TcS (Bag Implication)
getWorkListImplics
= do { wl_var <- getTcSWorkListRef
; wl_curr <- wrapTcS (TcM.readTcRef wl_var)
; return (wl_implics wl_curr) }
updWorkListTcS :: (WorkList -> WorkList) -> TcS ()
updWorkListTcS f
= do { wl_var <- getTcSWorkListRef
; wl_curr <- wrapTcS (TcM.readTcRef wl_var)
; let new_work = f wl_curr
; wrapTcS (TcM.writeTcRef wl_var new_work) }
emitWorkNC :: [CtEvidence] -> TcS ()
emitWorkNC evs
| null evs
= return ()
| otherwise
= emitWork (map mkNonCanonical evs)
emitWork :: [Ct] -> TcS ()
emitWork cts
= do { traceTcS "Emitting fresh work" (vcat (map ppr cts))
; updWorkListTcS (extendWorkListCts cts) }
newTcRef :: a -> TcS (TcRef a)
newTcRef x = wrapTcS (TcM.newTcRef x)
readTcRef :: TcRef a -> TcS a
readTcRef ref = wrapTcS (TcM.readTcRef ref)
updTcRef :: TcRef a -> (a->a) -> TcS ()
updTcRef ref upd_fn = wrapTcS (TcM.updTcRef ref upd_fn)
getTcEvBindsVar :: TcS EvBindsVar
getTcEvBindsVar = TcS (return . tcs_ev_binds)
getTcLevel :: TcS TcLevel
getTcLevel = wrapTcS TcM.getTcLevel
getTcEvTyCoVars :: EvBindsVar -> TcS TyCoVarSet
getTcEvTyCoVars ev_binds_var
= wrapTcS $ TcM.getTcEvTyCoVars ev_binds_var
getTcEvBindsMap :: EvBindsVar -> TcS EvBindMap
getTcEvBindsMap ev_binds_var
= wrapTcS $ TcM.getTcEvBindsMap ev_binds_var
setTcEvBindsMap :: EvBindsVar -> EvBindMap -> TcS ()
setTcEvBindsMap ev_binds_var binds
= wrapTcS $ TcM.setTcEvBindsMap ev_binds_var binds
unifyTyVar :: TcTyVar -> TcType -> TcS ()
-- Unify a meta-tyvar with a type
-- We keep track of how many unifications have happened in tcs_unified,
--
-- We should never unify the same variable twice!
unifyTyVar tv ty
= ASSERT2( isMetaTyVar tv, ppr tv )
TcS $ \ env ->
do { TcM.traceTc "unifyTyVar" (ppr tv <+> text ":=" <+> ppr ty)
; TcM.writeMetaTyVar tv ty
; TcM.updTcRef (tcs_unified env) (+1) }
reportUnifications :: TcS a -> TcS (Int, a)
reportUnifications (TcS thing_inside)
= TcS $ \ env ->
do { inner_unified <- TcM.newTcRef 0
; res <- thing_inside (env { tcs_unified = inner_unified })
; n_unifs <- TcM.readTcRef inner_unified
; TcM.updTcRef (tcs_unified env) (+ n_unifs)
; return (n_unifs, res) }
getDefaultInfo :: TcS ([Type], (Bool, Bool))
getDefaultInfo = wrapTcS TcM.tcGetDefaultTys
-- Just get some environments needed for instance looking up and matching
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
getInstEnvs :: TcS InstEnvs
getInstEnvs = wrapTcS $ TcM.tcGetInstEnvs
getFamInstEnvs :: TcS (FamInstEnv, FamInstEnv)
getFamInstEnvs = wrapTcS $ FamInst.tcGetFamInstEnvs
getTopEnv :: TcS HscEnv
getTopEnv = wrapTcS $ TcM.getTopEnv
getGblEnv :: TcS TcGblEnv
getGblEnv = wrapTcS $ TcM.getGblEnv
getLclEnv :: TcS TcLclEnv
getLclEnv = wrapTcS $ TcM.getLclEnv
tcLookupClass :: Name -> TcS Class
tcLookupClass c = wrapTcS $ TcM.tcLookupClass c
tcLookupId :: Name -> TcS Id
tcLookupId n = wrapTcS $ TcM.tcLookupId n
-- Setting names as used (used in the deriving of Coercible evidence)
-- Too hackish to expose it to TcS? In that case somehow extract the used
-- constructors from the result of solveInteract
addUsedGREs :: [GlobalRdrElt] -> TcS ()
addUsedGREs gres = wrapTcS $ TcM.addUsedGREs gres
addUsedGRE :: Bool -> GlobalRdrElt -> TcS ()
addUsedGRE warn_if_deprec gre = wrapTcS $ TcM.addUsedGRE warn_if_deprec gre
-- Various smaller utilities [TODO, maybe will be absorbed in the instance matcher]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
checkWellStagedDFun :: PredType -> DFunId -> CtLoc -> TcS ()
checkWellStagedDFun pred dfun_id loc
= wrapTcS $ TcM.setCtLocM loc $
do { use_stage <- TcM.getStage
; TcM.checkWellStaged pp_thing bind_lvl (thLevel use_stage) }
where
pp_thing = text "instance for" <+> quotes (ppr pred)
bind_lvl = TcM.topIdLvl dfun_id
pprEq :: TcType -> TcType -> SDoc
pprEq ty1 ty2 = pprParendType ty1 <+> char '~' <+> pprParendType ty2
isTouchableMetaTyVarTcS :: TcTyVar -> TcS Bool
isTouchableMetaTyVarTcS tv
= do { tclvl <- getTcLevel
; return $ isTouchableMetaTyVar tclvl tv }
isFilledMetaTyVar_maybe :: TcTyVar -> TcS (Maybe Type)
isFilledMetaTyVar_maybe tv
= case tcTyVarDetails tv of
MetaTv { mtv_ref = ref }
-> do { cts <- wrapTcS (TcM.readTcRef ref)
; case cts of
Indirect ty -> return (Just ty)
Flexi -> return Nothing }
_ -> return Nothing
isFilledMetaTyVar :: TcTyVar -> TcS Bool
isFilledMetaTyVar tv = wrapTcS (TcM.isFilledMetaTyVar tv)
zonkTyCoVarsAndFV :: TcTyCoVarSet -> TcS TcTyCoVarSet
zonkTyCoVarsAndFV tvs = wrapTcS (TcM.zonkTyCoVarsAndFV tvs)
zonkTyCoVarsAndFVList :: [TcTyCoVar] -> TcS [TcTyCoVar]
zonkTyCoVarsAndFVList tvs = wrapTcS (TcM.zonkTyCoVarsAndFVList tvs)
zonkCo :: Coercion -> TcS Coercion
zonkCo = wrapTcS . TcM.zonkCo
zonkTcType :: TcType -> TcS TcType
zonkTcType ty = wrapTcS (TcM.zonkTcType ty)
zonkTcTypes :: [TcType] -> TcS [TcType]
zonkTcTypes tys = wrapTcS (TcM.zonkTcTypes tys)
zonkTcTyVar :: TcTyVar -> TcS TcType
zonkTcTyVar tv = wrapTcS (TcM.zonkTcTyVar tv)
zonkSimples :: Cts -> TcS Cts
zonkSimples cts = wrapTcS (TcM.zonkSimples cts)
zonkWC :: WantedConstraints -> TcS WantedConstraints
zonkWC wc = wrapTcS (TcM.zonkWC wc)
{- *********************************************************************
* *
* Flatten skolems *
* *
********************************************************************* -}
newFlattenSkolem :: CtFlavour -> CtLoc
-> TyCon -> [TcType] -- F xis
-> TcS (CtEvidence, Coercion, TcTyVar) -- [G/WD] x:: F xis ~ fsk
newFlattenSkolem flav loc tc xis
= do { stuff@(ev, co, fsk) <- new_skolem
; let fsk_ty = mkTyVarTy fsk
; extendFlatCache tc xis (co, fsk_ty, ctEvFlavour ev)
; return stuff }
where
fam_ty = mkTyConApp tc xis
new_skolem
| Given <- flav
= do { fsk <- wrapTcS (TcM.newFskTyVar fam_ty)
-- Extend the inert_fsks list, for use by unflattenGivens
; updInertTcS $ \is -> is { inert_fsks = (fsk, fam_ty) : inert_fsks is }
-- Construct the Refl evidence
; let pred = mkPrimEqPred fam_ty (mkTyVarTy fsk)
co = mkNomReflCo fam_ty
; ev <- newGivenEvVar loc (pred, EvCoercion co)
; return (ev, co, fsk) }
| otherwise -- Generate a [WD] for both Wanted and Derived
-- See Note [No Derived CFunEqCans]
= do { fmv <- wrapTcS (TcM.newFmvTyVar fam_ty)
; (ev, hole_co) <- newWantedEq loc Nominal fam_ty (mkTyVarTy fmv)
; return (ev, hole_co, fmv) }
----------------------------
unflattenGivens :: IORef InertSet -> TcM ()
-- Unflatten all the fsks created by flattening types in Given
-- constraints. We must be sure to do this, else we end up with
-- flatten-skolems buried in any residual Wanteds
--
-- NB: this is the /only/ way that a fsk (MetaDetails = FlatSkolTv)
-- is filled in. Nothing else does so.
--
-- It's here (rather than in TcFlatten) because the Right Places
-- to call it are in runTcSWithEvBinds/nestImplicTcS, where it
-- is nicely paired with the creation an empty inert_fsks list.
unflattenGivens inert_var
= do { inerts <- TcM.readTcRef inert_var
; mapM_ flatten_one (inert_fsks inerts) }
where
flatten_one (fsk, ty) = TcM.writeMetaTyVar fsk ty
----------------------------
extendFlatCache :: TyCon -> [Type] -> (TcCoercion, TcType, CtFlavour) -> TcS ()
extendFlatCache tc xi_args stuff@(_, ty, fl)
| isGivenOrWDeriv fl -- Maintain the invariant that inert_flat_cache
-- only has [G] and [WD] CFunEqCans
= do { dflags <- getDynFlags
; when (gopt Opt_FlatCache dflags) $
do { traceTcS "extendFlatCache" (vcat [ ppr tc <+> ppr xi_args
, ppr fl, ppr ty ])
-- 'co' can be bottom, in the case of derived items
; updInertTcS $ \ is@(IS { inert_flat_cache = fc }) ->
is { inert_flat_cache = insertExactFunEq fc tc xi_args stuff } } }
| otherwise
= return ()
----------------------------
unflattenFmv :: TcTyVar -> TcType -> TcS ()
-- Fill a flatten-meta-var, simply by unifying it.
-- This does NOT count as a unification in tcs_unified.
unflattenFmv tv ty
= ASSERT2( isMetaTyVar tv, ppr tv )
TcS $ \ _ ->
do { TcM.traceTc "unflattenFmv" (ppr tv <+> text ":=" <+> ppr ty)
; TcM.writeMetaTyVar tv ty }
----------------------------
demoteUnfilledFmv :: TcTyVar -> TcS ()
-- If a flatten-meta-var is still un-filled,
-- turn it into an ordinary meta-var
demoteUnfilledFmv fmv
= wrapTcS $ do { is_filled <- TcM.isFilledMetaTyVar fmv
; unless is_filled $
do { tv_ty <- TcM.newFlexiTyVarTy (tyVarKind fmv)
; TcM.writeMetaTyVar fmv tv_ty } }
{- *********************************************************************
* *
* Instantiation etc.
* *
********************************************************************* -}
-- Instantiations
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
instDFunType :: DFunId -> [DFunInstType] -> TcS ([TcType], TcThetaType)
instDFunType dfun_id inst_tys
= wrapTcS $ TcM.instDFunType dfun_id inst_tys
newFlexiTcSTy :: Kind -> TcS TcType
newFlexiTcSTy knd = wrapTcS (TcM.newFlexiTyVarTy knd)
cloneMetaTyVar :: TcTyVar -> TcS TcTyVar
cloneMetaTyVar tv = wrapTcS (TcM.cloneMetaTyVar tv)
instFlexi :: [TKVar] -> TcS TCvSubst
instFlexi = instFlexiX emptyTCvSubst
instFlexiX :: TCvSubst -> [TKVar] -> TcS TCvSubst
instFlexiX subst tvs
= wrapTcS (foldlM instFlexiHelper subst tvs)
instFlexiHelper :: TCvSubst -> TKVar -> TcM TCvSubst
instFlexiHelper subst tv
= do { uniq <- TcM.newUnique
; details <- TcM.newMetaDetails TauTv
; let name = setNameUnique (tyVarName tv) uniq
kind = substTyUnchecked subst (tyVarKind tv)
ty' = mkTyVarTy (mkTcTyVar name kind details)
; return (extendTvSubst subst tv ty') }
tcInstType :: ([TyVar] -> TcM (TCvSubst, [TcTyVar]))
-- ^ How to instantiate the type variables
-> Id -- ^ Type to instantiate
-> TcS ([(Name, TcTyVar)], TcThetaType, TcType) -- ^ Result
-- (type vars, preds (incl equalities), rho)
tcInstType inst_tyvars id = wrapTcS (TcM.tcInstType inst_tyvars id)
tcInstSkolTyVarsX :: TCvSubst -> [TyVar] -> TcS (TCvSubst, [TcTyVar])
tcInstSkolTyVarsX subst tvs = wrapTcS $ TcM.tcInstSkolTyVarsX subst tvs
-- Creating and setting evidence variables and CtFlavors
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
data MaybeNew = Fresh CtEvidence | Cached EvTerm
isFresh :: MaybeNew -> Bool
isFresh (Fresh {}) = True
isFresh (Cached {}) = False
freshGoals :: [MaybeNew] -> [CtEvidence]
freshGoals mns = [ ctev | Fresh ctev <- mns ]
getEvTerm :: MaybeNew -> EvTerm
getEvTerm (Fresh ctev) = ctEvTerm ctev
getEvTerm (Cached evt) = evt
setEvBind :: EvBind -> TcS ()
setEvBind ev_bind
= do { evb <- getTcEvBindsVar
; wrapTcS $ TcM.addTcEvBind evb ev_bind }
-- | Mark variables as used filling a coercion hole
useVars :: CoVarSet -> TcS ()
useVars vars
= do { EvBindsVar { ebv_tcvs = ref } <- getTcEvBindsVar
; wrapTcS $
do { tcvs <- TcM.readTcRef ref
; let tcvs' = tcvs `unionVarSet` vars
; TcM.writeTcRef ref tcvs' } }
-- | Equalities only
setWantedEq :: TcEvDest -> Coercion -> TcS ()
setWantedEq (HoleDest hole) co
= do { useVars (coVarsOfCo co)
; wrapTcS $ TcM.fillCoercionHole hole co }
setWantedEq (EvVarDest ev) _ = pprPanic "setWantedEq" (ppr ev)
-- | Equalities only
setEqIfWanted :: CtEvidence -> Coercion -> TcS ()
setEqIfWanted (CtWanted { ctev_dest = dest }) co = setWantedEq dest co
setEqIfWanted _ _ = return ()
-- | Good for equalities and non-equalities
setWantedEvTerm :: TcEvDest -> EvTerm -> TcS ()
setWantedEvTerm (HoleDest hole) tm
= do { let co = evTermCoercion tm
; useVars (coVarsOfCo co)
; wrapTcS $ TcM.fillCoercionHole hole co }
setWantedEvTerm (EvVarDest ev) tm = setWantedEvBind ev tm
setWantedEvBind :: EvVar -> EvTerm -> TcS ()
setWantedEvBind ev_id tm = setEvBind (mkWantedEvBind ev_id tm)
setEvBindIfWanted :: CtEvidence -> EvTerm -> TcS ()
setEvBindIfWanted ev tm
= case ev of
CtWanted { ctev_dest = dest }
-> setWantedEvTerm dest tm
_ -> return ()
newTcEvBinds :: TcS EvBindsVar
newTcEvBinds = wrapTcS TcM.newTcEvBinds
newEvVar :: TcPredType -> TcS EvVar
newEvVar pred = wrapTcS (TcM.newEvVar pred)
newGivenEvVar :: CtLoc -> (TcPredType, EvTerm) -> TcS CtEvidence
-- Make a new variable of the given PredType,
-- immediately bind it to the given term
-- and return its CtEvidence
-- See Note [Bind new Givens immediately] in TcRnTypes
newGivenEvVar loc (pred, rhs)
= do { new_ev <- newBoundEvVarId pred rhs
; return (CtGiven { ctev_pred = pred, ctev_evar = new_ev, ctev_loc = loc }) }
-- | Make a new 'Id' of the given type, bound (in the monad's EvBinds) to the
-- given term
newBoundEvVarId :: TcPredType -> EvTerm -> TcS EvVar
newBoundEvVarId pred rhs
= do { new_ev <- newEvVar pred
; setEvBind (mkGivenEvBind new_ev rhs)
; return new_ev }
newGivenEvVars :: CtLoc -> [(TcPredType, EvTerm)] -> TcS [CtEvidence]
newGivenEvVars loc pts = mapM (newGivenEvVar loc) pts
emitNewWantedEq :: CtLoc -> Role -> TcType -> TcType -> TcS Coercion
-- | Emit a new Wanted equality into the work-list
emitNewWantedEq loc role ty1 ty2
| otherwise
= do { (ev, co) <- newWantedEq loc role ty1 ty2
; updWorkListTcS $
extendWorkListEq (mkNonCanonical ev)
; return co }
-- | Make a new equality CtEvidence
newWantedEq :: CtLoc -> Role -> TcType -> TcType -> TcS (CtEvidence, Coercion)
newWantedEq loc role ty1 ty2
= do { hole <- wrapTcS $ TcM.newCoercionHole pty
; traceTcS "Emitting new coercion hole" (ppr hole <+> dcolon <+> ppr pty)
; return ( CtWanted { ctev_pred = pty, ctev_dest = HoleDest hole
, ctev_nosh = WDeriv
, ctev_loc = loc}
, mkHoleCo hole ) }
where
pty = mkPrimEqPredRole role ty1 ty2
-- no equalities here. Use newWantedEq instead
newWantedEvVarNC :: CtLoc -> TcPredType -> TcS CtEvidence
-- Don't look up in the solved/inerts; we know it's not there
newWantedEvVarNC loc pty
= do { new_ev <- newEvVar pty
; traceTcS "Emitting new wanted" (ppr new_ev <+> dcolon <+> ppr pty $$
pprCtLoc loc)
; return (CtWanted { ctev_pred = pty, ctev_dest = EvVarDest new_ev
, ctev_nosh = WDeriv
, ctev_loc = loc })}
newWantedEvVar :: CtLoc -> TcPredType -> TcS MaybeNew
-- For anything except ClassPred, this is the same as newWantedEvVarNC
newWantedEvVar loc pty
= do { mb_ct <- lookupInInerts loc pty
; case mb_ct of
Just ctev
| not (isDerived ctev)
-> do { traceTcS "newWantedEvVar/cache hit" $ ppr ctev
; return $ Cached (ctEvTerm ctev) }
_ -> do { ctev <- newWantedEvVarNC loc pty
; return (Fresh ctev) } }
-- deals with both equalities and non equalities. Tries to look
-- up non-equalities in the cache
newWanted :: CtLoc -> PredType -> TcS MaybeNew
newWanted loc pty
| Just (role, ty1, ty2) <- getEqPredTys_maybe pty
= Fresh . fst <$> newWantedEq loc role ty1 ty2
| otherwise
= newWantedEvVar loc pty
-- deals with both equalities and non equalities. Doesn't do any cache lookups.
newWantedNC :: CtLoc -> PredType -> TcS CtEvidence
newWantedNC loc pty
| Just (role, ty1, ty2) <- getEqPredTys_maybe pty
= fst <$> newWantedEq loc role ty1 ty2
| otherwise
= newWantedEvVarNC loc pty
emitNewDeriveds :: CtLoc -> [TcPredType] -> TcS ()
emitNewDeriveds loc preds
| null preds
= return ()
| otherwise
= do { evs <- mapM (newDerivedNC loc) preds
; traceTcS "Emitting new deriveds" (ppr evs)
; updWorkListTcS (extendWorkListDeriveds evs) }
emitNewDerivedEq :: CtLoc -> Role -> TcType -> TcType -> TcS ()
-- Create new equality Derived and put it in the work list
-- There's no caching, no lookupInInerts
emitNewDerivedEq loc role ty1 ty2
= do { ev <- newDerivedNC loc (mkPrimEqPredRole role ty1 ty2)
; traceTcS "Emitting new derived equality" (ppr ev $$ pprCtLoc loc)
; updWorkListTcS (extendWorkListEq (mkNonCanonical ev)) }
-- Very important: put in the wl_eqs
-- See Note [Prioritise equalities] (Avoiding fundep iteration)
newDerivedNC :: CtLoc -> TcPredType -> TcS CtEvidence
newDerivedNC loc pred
= do { -- checkReductionDepth loc pred
; return (CtDerived { ctev_pred = pred, ctev_loc = loc }) }
-- --------- Check done in TcInteract.selectNewWorkItem???? ---------
-- | Checks if the depth of the given location is too much. Fails if
-- it's too big, with an appropriate error message.
checkReductionDepth :: CtLoc -> TcType -- ^ type being reduced
-> TcS ()
checkReductionDepth loc ty
= do { dflags <- getDynFlags
; when (subGoalDepthExceeded dflags (ctLocDepth loc)) $
wrapErrTcS $
solverDepthErrorTcS loc ty }
matchFam :: TyCon -> [Type] -> TcS (Maybe (Coercion, TcType))
matchFam tycon args = wrapTcS $ matchFamTcM tycon args
matchFamTcM :: TyCon -> [Type] -> TcM (Maybe (Coercion, TcType))
-- Given (F tys) return (ty, co), where co :: F tys ~ ty
matchFamTcM tycon args
= do { fam_envs <- FamInst.tcGetFamInstEnvs
; let match_fam_result
= reduceTyFamApp_maybe fam_envs Nominal tycon args
; TcM.traceTc "matchFamTcM" $
vcat [ text "Matching:" <+> ppr (mkTyConApp tycon args)
, ppr_res match_fam_result ]
; return match_fam_result }
where
ppr_res Nothing = text "Match failed"
ppr_res (Just (co,ty)) = hang (text "Match succeeded:")
2 (vcat [ text "Rewrites to:" <+> ppr ty
, text "Coercion:" <+> ppr co ])
{-
Note [Residual implications]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The wl_implics in the WorkList are the residual implication
constraints that are generated while solving or canonicalising the
current worklist. Specifically, when canonicalising
(forall a. t1 ~ forall a. t2)
from which we get the implication
(forall a. t1 ~ t2)
See TcSMonad.deferTcSForAllEq
-}