diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/typecheck/TcCanonical.lhs | 224 | ||||
-rw-r--r-- | compiler/typecheck/TcHsSyn.lhs | 44 | ||||
-rw-r--r-- | compiler/typecheck/TcInteract.lhs | 349 | ||||
-rw-r--r-- | compiler/typecheck/TcRnTypes.lhs | 21 | ||||
-rw-r--r-- | compiler/typecheck/TcSMonad.lhs | 72 | ||||
-rw-r--r-- | compiler/typecheck/TcSimplify.lhs | 6 | ||||
-rw-r--r-- | compiler/types/Coercion.lhs | 1 |
7 files changed, 415 insertions, 302 deletions
diff --git a/compiler/typecheck/TcCanonical.lhs b/compiler/typecheck/TcCanonical.lhs index 16dea420ac..c1f679ee70 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 @@ -255,13 +262,13 @@ canIP d fl v nm ty 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 } } @@ -301,13 +308,13 @@ canClass d fl v cls tys -- 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. @@ -458,13 +466,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 } } @@ -588,16 +596,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 - ; return (mkEqVarLCo eqv, rhs_xi_var, [ct]) } | otherwise -> -- Derived or Wanted: make a new /unification/ flatten variable @@ -688,11 +696,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 @@ -701,7 +709,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 @@ -714,7 +722,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. @@ -723,16 +732,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 @@ -759,17 +771,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 @@ -793,9 +806,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 {}) @@ -1023,15 +1037,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 @@ -1075,15 +1089,24 @@ 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) <- + {-# 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 is_cached = lookupFunEq (mkTyConApp fn xis1) fl fam_eqs + ; let flat_ty = mkTyConApp fn xis1 + + ; 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 @@ -1093,23 +1116,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 } } @@ -1148,8 +1172,11 @@ canEqLeafFunEqLeft :: SubGoalDepth -- Depth -> 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 + = {-# SCC "canEqLeafFunEqLeft" #-} + do { traceTcS "canEqLeafFunEqLeft" $ ppr (evVarPred eqv) + ; (xi2,co2) <- + {-# SCC "flatten" #-} + flatten d fl s2 -- co2 :: xi2 ~ s2 ; let no_flattening_happened = isReflCo co2 ; if no_flattening_happened then continueWith $ CFunEqCan { cc_id = eqv @@ -1158,19 +1185,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 @@ -1186,17 +1215,17 @@ canEqLeafTyVarLeftRec d fl eqv tv s2 -- eqv :: tv ~ s2 ; (xi1,co1) <- flatten d fl (mkTyVarTy tv) -- co1 :: xi1 ~ tv ; if isReflCo co1 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 } } @@ -1219,8 +1248,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 @@ -1246,21 +1276,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/TcHsSyn.lhs b/compiler/typecheck/TcHsSyn.lhs index 4f8cdb2a77..12bb2821fd 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') }) @@ -1113,10 +1117,31 @@ zonkEvBinds env binds add (EvBind var _) vars = var : vars zonkEvBind :: ZonkEnv -> EvBind -> TcM EvBind + + zonkEvBind env (EvBind var term) - = do { var' <- zonkEvBndr env var - ; term' <- zonkEvTerm env term - ; return (EvBind var' term') } + = 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 {} <- getCoVar_maybe co + -> do { term'@(EvCoercionBox (CoVarCo cv')) <- zonkEvTerm env term + ; let 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} %************************************************************************ @@ -1186,9 +1211,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 7fc6a966a4..18f4e552a4 100644 --- a/compiler/typecheck/TcInteract.lhs +++ b/compiler/typecheck/TcInteract.lhs @@ -51,6 +51,7 @@ import VarEnv import qualified Data.Traversable as Traversable import Control.Monad( when ) +import Pair ( pSnd ) import UniqFM import FastString ( sLit ) import DynFlags @@ -107,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) @@ -136,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 () @@ -236,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} @@ -292,70 +290,124 @@ 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 +-- 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 - = do { (wl,ieqs,solved_out) <- modifyInertTcS (kick_out_rewritable ct) - - -- Rewrite the inert_eqs on the spot! - ; let ct_subst = unitVarEnv (cc_tyvar ct) (ct, mkEqVarLCo (cc_id ct)) - inscope = mkInScopeSet $ tyVarsOfCt ct - - ; new_ieqs <- rewriteInertEqsFromInertEq (ct_subst,inscope) ieqs + = {-# 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 })) - - -- Rewrite the rewritable solved on the spot and stick them back in the inerts - ; _unused <- mapBagM (rewrite_solved (ct_subst,inscope)) solved_out + -- 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 -> return () - ContinueWith ct -> updInertSetTcS ct } - - -rewriteInertEqsFromInertEq :: (TyVarEnv (Ct,Coercion), InScopeSet) -- A new substitution - -> TyVarEnv (Ct,Coercion) -- The inert equalities - -> TcS (TyVarEnv (Ct,Coercion)) -- The new inert equalities -rewriteInertEqsFromInertEq the_subst ieqs = Traversable.mapM do_one ieqs - where do_one (ct,co) - | ev <- cc_id ct, fl <- cc_flavor ct - = do { (new_ev,not_rewritten) <- rewriteFromInertEqs the_subst fl ev - ; let EqPred _ xi = classifyPredType (evVarPred new_ev) - ; if not_rewritten then - return (ct,co) -- return the same +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: +-- 1) If current inert element cannot itself rewrite subst_fl then: +-- a) if it is rewritable by subst fl throw him out +-- b) if it is not rewritable by subst keep him in as is +-- 2) otherwise +-- a) if it is rewritable by subst fl rewrite him on the spot +-- b) if it is not rewritable by subst fl then keep him as is + + = do { mieqs <- Traversable.mapM do_one ieqs -- mieqs :: TyVarEnv (Maybe (Ct,Coercion)) + ; case Traversable.sequence mieqs of + Nothing -> return emptyVarEnv + Just final_ieqs -> return final_ieqs } + + where do_one (ct,inert_co) + | (not (subst_fl `canRewrite` fl)) || isReflCo co + -- If the inert is not rewritable we just keep it + = return (Just (ct,inert_co)) + -- Inert is definitely rewritable + | not (fl `canRewrite` subst_fl) -- But the inert cannot itself rewrite the subst item + -- so there is need for recanonicalization. + = do { updWorkListTcS (extendWorkListEq ct) + ; return Nothing } + | otherwise -- Or the inert can rewrite subst as well, so it's safe to rewrite on-the-spot + = 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 - return (ct { cc_id = new_ev, cc_rhs = xi }, mkEqVarLCo new_ev) } + 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 (Just (ct',evco')) } + where ev = cc_id ct + fl = cc_flavor ct + tv = cc_tyvar ct + rhs = cc_rhs ct + co = liftCoSubstWith [subst_tv] [subst_co] rhs + + + +-- (eqs_out, eqs_in) = partitionEqMap +-- (\inert_ct -> (not (cc_flavor inert_ct `canRewrite` fl)) && +-- rewritable inert_ct) eqmap +-- -- Why not just (rewritable_inert ct)? Check out Note [Delicate equality kick-out] + -kick_out_rewritable :: Ct -> InertSet -> ((WorkList,TyVarEnv (Ct,Coercion),Cts), InertSet) + +-- {- +-- traceTcS "rewriteInertEqsFromInertEq" $ +-- vcat [ text "rewriting equality: " <+> ppr ct +-- , text "from: " <+> ppr subst_co <+> text "of flavor: " <+> ppr subst_fl +-- , text "can rewrite? " <+> ppr (subst_fl `canRewrite` fl) ] +-- -} + + + +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 @@ -364,15 +416,14 @@ kick_out_rewritable ct (IS { inert_eqs = eqmap , inert_irreds = irreds , inert_frozen = frozen } ) - = ((kicked_out, eqs_in, feqs_out_solved `andCts` dicts_out_solved), remaining) + = ((kicked_out, eqmap), remaining) where - - kicked_out = WorkList { wl_eqs = eqs_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,39 +434,46 @@ kick_out_rewritable ct (IS { inert_eqs = eqmap fl = cc_flavor ct tv = cc_tyvar ct - - (eqs_out, eqs_in) = partitionEqMap - (\inert_ct -> rewritable inert_ct && - not (cc_flavor inert_ct `canRewrite` fl)) eqmap - -- Delicate: - -- We want to throw out only the rewritables which cannot - -- themselves rewrite the workitem. Because, what will remain - -- in eqs_in, even if rewritable, can be readily substituted - -- in-place from the new item, without dangers for occurs - -- loops or further need for canonicalization. + + (ips_out, ips_in) = partitionCCanMap rewritable ipmap - (ips_out, ips_in) = partitionCCanMap rewritable ipmap - - (feqs_out_all, feqs_in) = partitionCtTypeMap rewritable funeqmap - (feqs_out_solved, feqs_out) = partitionBag is_solved feqs_out_all - - (dicts_out_all, dicts_in) = partitionCCanMap rewritable dictmap - (dicts_out_solved, dicts_out) = partitionBag is_solved dicts_out_all + (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) && (tv `elemVarSet` tyVarsOfCt ct) +\end{code} + +Note [Delicate equality kick-out] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - is_solved ct - | Just GivenSolved <- isGiven_maybe (cc_flavor ct) - = True - | otherwise = False +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 @@ -484,21 +542,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] @@ -584,7 +628,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) @@ -593,36 +637,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} - ********************************************************************************* * * @@ -798,9 +822,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 @@ -808,13 +831,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 @@ -839,40 +862,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 @@ -891,14 +914,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) } @@ -1350,30 +1373,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 @@ -1394,25 +1419,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 } } + , 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/TcRnTypes.lhs b/compiler/typecheck/TcRnTypes.lhs index da2c8981ed..a7074e6207 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 a777706f86..e1e1d96b8e 100644 --- a/compiler/typecheck/TcSMonad.lhs +++ b/compiler/typecheck/TcSMonad.lhs @@ -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 @@ -493,9 +491,17 @@ updInertSet is item | isCTyEqCan item = let upd_err a b = pprPanic "updInertSet" $ vcat [text "Multiple inert equalities:", ppr a, 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' } @@ -668,11 +674,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 @@ -1058,8 +1064,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 @@ -1075,15 +1081,10 @@ 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 +setEvBind ev t fl = do { tc_evbinds <- getTcEvBinds ; wrapTcS $ TcM.addTcEvBind tc_evbinds ev t @@ -1092,6 +1093,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 @@ -1275,7 +1281,9 @@ 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 { eref <- getTcSEvVarCache + = 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) @@ -1283,11 +1291,13 @@ newEvVar fl pty -> pprTrace "Interesting: given newEvVar, missed caching opportunity!" empty $ return () _ -> return () - ; new <- forceNewEvVar fl pty +-} + 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) @@ -1338,9 +1348,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) } @@ -1377,13 +1388,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 @@ -1447,6 +1458,7 @@ getInertEqs :: TcS (TyVarEnv (Ct,Coercion), InScopeSet) getInertEqs = do { inert <- getTcSInerts ; return (inert_eqs inert, inert_eq_tvs inert) } +{-- UNSAFE in the prsence of Solved flavors! Don't use! rewriteFromInertEqs :: (TyVarEnv (Ct,Coercion), InScopeSet) -- Precondition: Ct are CTyEqCans only! -> CtFlavor @@ -1458,7 +1470,7 @@ rewriteFromInertEqs (subst,inscope) fl v ; if isReflCo co then return (v,True) else do { traceTcS "rewriteFromInertEqs" $ text "Original item =" <+> ppr v <+> dcolon <+> ppr (evVarPred v) - ; delCachedEvVar v + ; delCachedEvVar v fl ; evc <- newEvVar fl (pSnd (liftedCoercionKind co)) ; let v' = evc_the_evvar evc ; if isNewEvVar evc then @@ -1476,7 +1488,7 @@ rewriteFromInertEqs (subst,inscope) fl v _ -> return () ; return (v',True) } -- As if rewriting never happened? } } - +--} -- See Note [LiftInertEqs] liftInertEqsTy :: (TyVarEnv (Ct,Coercion),InScopeSet) 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 |