(1) More lenient kind checking, (2) Fixed orientation problems and avoiding double...
authordimitris@microsoft.com <unknown>
Wed, 20 Oct 2010 11:55:26 +0000 (11:55 +0000)
committerdimitris@microsoft.com <unknown>
Wed, 20 Oct 2010 11:55:26 +0000 (11:55 +0000)
compiler/typecheck/TcCanonical.lhs
compiler/typecheck/TcInteract.lhs
compiler/typecheck/TcSMonad.lhs

index e9c6902..2331d2d 100644 (file)
@@ -1,7 +1,7 @@
 \begin{code}
 module TcCanonical(
     mkCanonical, mkCanonicals, canWanteds, canGivens, canOccursCheck, 
-    canEq
+    canEq, canEqLeafTyVarLeft 
  ) where
 
 #include "HsVersions.h"
@@ -248,17 +248,23 @@ canEq fl cv ty1 ty2
 
 -- If one side is a variable, orient and flatten, 
 -- WITHOUT expanding type synonyms, so that we tend to 
--- substitute a~Age rather than a~Int when type Age=Ing
-canEq fl cv ty1@(TyVarTy {}) ty2 = canEqLeaf fl cv (classify ty1) (classify ty2)
-canEq fl cv ty1 ty2@(TyVarTy {}) = canEqLeaf fl cv (classify ty1) (classify ty2)
-      -- NB: don't use VarCls directly because tv1 or tv2 may be scolems! 
+-- substitute a ~ Age rather than a ~ Int when @type Age = Int@
+canEq fl cv ty1@(TyVarTy {}) ty2 
+  = do { untch <- getUntouchables 
+       ; canEqLeaf untch fl cv (classify ty1) (classify ty2) }
+canEq fl cv ty1 ty2@(TyVarTy {}) 
+  = do { untch <- getUntouchables 
+       ; canEqLeaf untch fl cv (classify ty1) (classify ty2) }
+      -- NB: don't use VarCls directly because tv1 or tv2 may be scolems!
 
 canEq fl cv (TyConApp fn tys) ty2 
   | isSynFamilyTyCon fn, length tys == tyConArity fn
-  = canEqLeaf fl cv (FunCls fn tys) (classify ty2)
+  = do { untch <- getUntouchables 
+       ; canEqLeaf untch fl cv (FunCls fn tys) (classify ty2) }
 canEq fl cv ty1 (TyConApp fn tys)
   | isSynFamilyTyCon fn, length tys == tyConArity fn
-  = canEqLeaf fl cv (classify ty1) (FunCls fn tys) 
+  = do { untch <- getUntouchables 
+       ; canEqLeaf untch fl cv (classify ty1) (FunCls fn tys) }
 
 canEq fl cv s1 s2
   | Just (t1a,t1b,t1c) <- splitCoPredTy_maybe s1, 
@@ -519,40 +525,39 @@ classify ty                | Just ty' <- tcView ty
                            = OtherCls ty
 
 -- See note [Canonical ordering for equality constraints].
-reOrient :: TypeClassifier -> TypeClassifier -> Bool   
+reOrient :: Untouchables -> TypeClassifier -> TypeClassifier -> Bool   
 -- (t1 `reOrient` t2) responds True 
 --   iff we should flip to (t2~t1)
 -- We try to say False if possible, to minimise evidence generation
 --
 -- Postcondition: After re-orienting, first arg is not OTherCls
-reOrient (OtherCls {}) (FunCls {})   = True
-reOrient (OtherCls {}) (FskCls {})   = True
-reOrient (OtherCls {}) (VarCls {})   = True
-reOrient (OtherCls {}) (OtherCls {}) = panic "reOrient"  -- One must be Var/Fun
+reOrient _untch (OtherCls {}) (FunCls {})   = True
+reOrient _untch (OtherCls {}) (FskCls {})   = True
+reOrient _untch (OtherCls {}) (VarCls {})   = True
+reOrient _untch (OtherCls {}) (OtherCls {}) = panic "reOrient"  -- One must be Var/Fun
 
-reOrient (FunCls {})   (VarCls tv2)   = isMetaTyVar tv2
+reOrient _untch (FunCls {})   (VarCls tv2)  = isMetaTyVar tv2
   -- See Note [No touchables as FunEq RHS] in TcSMonad
-  -- For convenience we enforce the stronger invariant that no 
-  -- meta type variable is the RHS of a function equality
-reOrient (FunCls {}) _                = False   -- Fun/Other on rhs
+reOrient _untch (FunCls {}) _               = False             -- Fun/Other on rhs
 
-reOrient (VarCls tv1) (FunCls {})   = not (isMetaTyVar tv1)
+reOrient _untch (VarCls tv1) (FunCls {})    = not $ isMetaTyVar tv1
 
-reOrient (VarCls {})  (FskCls {})   = True  
+reOrient _untch (VarCls tv1)  (FskCls {})   = not $ isMetaTyVar tv1
       -- See Note [Loopy Spontaneous Solving, Example 4]
 
-reOrient (VarCls {})  (OtherCls {}) = False
-reOrient (VarCls {})  (VarCls {})   = False
+reOrient _untch (VarCls {})  (OtherCls {})  = False
+reOrient _untch (VarCls {})  (VarCls {})    = False
 
-reOrient (FskCls {}) (VarCls {})    = False 
+reOrient _untch (FskCls {}) (VarCls tv2)    = isMetaTyVar tv2 
       -- See Note [Loopy Spontaneous Solving, Example 4]
 
-reOrient (FskCls {}) (FskCls {})    = False
-reOrient (FskCls {}) (FunCls {})    = True 
-reOrient (FskCls {}) (OtherCls {})  = False 
+reOrient _untch (FskCls {}) (FskCls {})     = False
+reOrient _untch (FskCls {}) (FunCls {})     = True 
+reOrient _untch (FskCls {}) (OtherCls {})   = False 
 
 ------------------
-canEqLeaf :: CtFlavor -> CoVar 
+canEqLeaf :: Untouchables 
+          -> CtFlavor -> CoVar 
           -> TypeClassifier -> TypeClassifier -> TcS CanonicalCts 
 -- Canonicalizing "leaf" equality constraints which cannot be
 -- decomposed further (ie one of the types is a variable or
@@ -561,8 +566,8 @@ canEqLeaf :: CtFlavor -> CoVar
   -- Preconditions: 
   --    * one of the two arguments is not OtherCls
   --    * the two types are not equal (looking through synonyms)
-canEqLeaf fl cv cls1 cls2 
-  | cls1 `reOrient` cls2 
+canEqLeaf untch fl cv cls1 cls2 
+  | cls1 `re_orient` cls2
   = do { cv' <- if isWanted fl 
                 then do { cv' <- newWantedCoVar s2 s1 
                         ; setWantedCoBind cv $ mkSymCoercion (mkCoVarCoercion cv') 
@@ -573,6 +578,7 @@ canEqLeaf fl cv cls1 cls2
   | otherwise
   = canEqLeafOriented fl cv cls1 s2
   where
+    re_orient = reOrient untch 
     s1 = unClassify cls1  
     s2 = unClassify cls2  
 
@@ -598,13 +604,15 @@ canEqLeafOriented fl cv cls1@(FunCls fn tys) s2
 
 -- Otherwise, we have a variable on the left, so call canEqLeafTyVarLeft
 canEqLeafOriented fl cv (FskCls tv) s2 
-  = canEqLeafTyVarLeft fl cv tv s2 
+  = do { (cc,ccs) <- canEqLeafTyVarLeft fl cv tv s2 
+       ; return $ ccs `extendCCans` cc } 
 canEqLeafOriented fl cv (VarCls tv) s2 
-  = canEqLeafTyVarLeft fl cv tv s2 
+  = do { (cc,ccs) <- canEqLeafTyVarLeft fl cv tv s2 
+       ; return $ ccs `extendCCans` cc } 
 canEqLeafOriented _ cv (OtherCls ty1) ty2 
   = pprPanic "canEqLeaf" (ppr cv $$ ppr ty1 $$ ppr ty2)
 
-canEqLeafTyVarLeft :: CtFlavor -> CoVar -> TcTyVar -> TcType -> TcS CanonicalCts 
+canEqLeafTyVarLeft :: CtFlavor -> CoVar -> TcTyVar -> TcType -> TcS (CanonicalCt, CanonicalCts)
 -- Establish invariants of CTyEqCans 
 canEqLeafTyVarLeft fl cv tv s2 
   | isGiven fl && not (k1 `compatKind` k2) -- Establish the kind invariant for CTyEqCan
@@ -620,7 +628,7 @@ canEqLeafTyVarLeft fl cv tv s2
                                  , cc_tyvar  = tv
                                  , cc_rhs    = xi2'
                                  } 
-       ; return $ ccs2 `extendCCans` final_cc }
+       ; return $ (final_cc, ccs2) }
   where
     k1 = tyVarKind tv
     k2 = typeKind s2
index c03384f..5285435 100644 (file)
@@ -211,9 +211,6 @@ getFDImprovements :: InertSet -> FDImprovements
 getFDImprovements = inert_fds 
 
 
-isWantedCt :: CanonicalCt -> Bool 
-isWantedCt ct = isWanted (cc_flavor ct)
-
 {- TODO: Later ...
 data Inert = IS { class_inerts :: FiniteMap Class Atomics
                  ip_inerts    :: FiniteMap Class Atomics
@@ -471,23 +468,27 @@ Note [Efficient Orientation]
 There are two cases where we have to be careful about 
 orienting equalities to get better efficiency. 
 
-Case 1: In Spontaneous Solving 
+Case 2: In Rewriting Equalities (function rewriteEqLHS) 
 
-     The OrientFlag is used to preserve the original orientation of a
-     spontaneously solved equality (insofar the canonical constraints
-     invariants allow it). This way we hope to be more efficient since
-     when reaching the spontaneous solve stage, a particular
-     constraint has already been inert-ified wrt to the preexisting
-     inerts.
+    When rewriting two equalities with the same LHS:
+          (a)  (tv ~ xi1) 
+          (b)  (tv ~ xi2) 
+    We have a choice of producing work (xi1 ~ xi2) (up-to the
+    canonicalization invariants) However, to prevent the inert items
+    from getting kicked out of the inerts first, we prefer to
+    canonicalize (xi1 ~ xi2) if (b) comes from the inert set, or (xi2
+    ~ xi1) if (a) comes from the inert set.
+    
+    This choice is implemented using the WhichComesFromInert flag. 
 
-     Example: 
+Case 2: In Spontaneous Solving 
+     Example 2a:
      Inerts:   [w1] : D alpha 
                [w2] : C beta 
                [w3] : F alpha ~ Int 
                [w4] : H beta  ~ Int 
      Untouchables = [beta] 
      Then a wanted (beta ~ alpha) comes along. 
-
         1) While interacting with the inerts it is going to kick w2,w4
            out of the inerts
         2) Then, it will spontaneoulsy be solved by (alpha := beta)
@@ -495,24 +496,26 @@ Case 1: In Spontaneous Solving
            solved (alpha ~ beta) is no good because, in the next
            iteration, it will kick out w1,w3 as well so we will end up
            with *all* the inert equalities back in the worklist!
-
-     So, we instead solve (alpha := beta), but we preserve the
-     original orientation, so that we get a given (beta ~ alpha),
-     which will result in no more inerts getting kicked out of the
-     inert set in the next iteration.
-
-Case 2: In Rewriting Equalities (function rewriteEqLHS) 
-
-    When rewriting two equalities with the same LHS:
-          (a)  (tv ~ xi1) 
-          (b)  (tv ~ xi2) 
-    We have a choice of producing work (xi1 ~ xi2) (up-to the
-    canonicalization invariants) However, to prevent the inert items
-    from getting kicked out of the inerts first, we prefer to
-    canonicalize (xi1 ~ xi2) if (b) comes from the inert set, or (xi2
-    ~ xi1) if (a) comes from the inert set.
-    
-    This choice is implemented using the WhichComesFromInert flag. 
+      
+      So it is tempting to just add (beta ~ alpha) instead, that is, 
+      maintain the original orietnation of the constraint. 
+
+      But that does not work very well, because it may cause the 
+      "double unification problem" (See Note [Avoid double unifications]). 
+      For instance: 
+
+      Example 2b: 
+           [w1] : fsk1 ~ alpha 
+           [w2] : fsk2 ~ alpha 
+           ---
+      At the end of the interaction suppose we spontaneously solve alpha := fsk1 
+      but keep [Given] fsk1 ~ alpha. Then, the second time around we see the 
+      constraint (fsk2 ~ alpha), and we unify *again* alpha := fsk2, which is wrong.
+
+      Our conclusion is that, while in some cases (Example 2a), it makes sense to 
+      preserve the original orientation, it is hard to do this in a sound way. 
+      So we *don't* do this for now, @solveWithIdentity@ outputs a constraint that 
+      is oriented with the unified variable on the left. 
 
 Case 3: Functional Dependencies and IP improvement work
     TODO. Optimisation not yet implemented there. 
@@ -527,23 +530,32 @@ spontaneousSolveStage workItem inerts
                            , sr_inerts     = inerts
                            , sr_stop       = ContinueWith workItem }
 
-           Just workList' -> -- He has been solved; workList' are all givens
-               return $ SR { sr_new_work = workList'
-                           , sr_inerts   = inerts 
-                           , sr_stop     = Stop }
+           Just (workItem', workList')
+               | not (isGivenCt workItem) -- Original was wanted or derived but we have now made him 
+                                          -- given so we have to interact him with the inerts due to
+                                          -- its status change. This in turn may produce more work.
+                   -> do { (new_inert, new_work) <- runSolverPipeline [ ("recursive interact with inert eqs", interactWithInertEqsStage)
+                                                                      , ("recursive interact with inerts", interactWithInertsStage)
+                                                                      ] inerts workItem'
+                         ; return $ SR { sr_new_work = new_work `unionWorkLists` workList'
+                                       , sr_inerts   = new_inert -- will include workItem' 
+                                       , sr_stop     = Stop }
+                         }
+               | otherwise 
+                   -> -- Original was given; he must then be inert all right, and
+                      -- workList' are all givens from flattening
+                      return $ SR { sr_new_work = workList' 
+                                  , sr_inerts   = inerts `updInertSet` workItem' 
+                                  , sr_stop     = Stop }
        }
 
-
-data OrientFlag = OrientThisWay 
-                | OrientOtherWay -- See Note [Efficient Orientation]
-
 -- @trySpontaneousSolve wi@ solves equalities where one side is a
 -- touchable unification variable. Returns:
 --   * Nothing if we were not able to solve it
 --   * Just wi' if we solved it, wi' (now a "given") should be put in the work list.
 --                 See Note [Touchables and givens] 
 -- NB: just passing the inerts through for the skolem equivalence classes
-trySpontaneousSolve :: WorkItem -> InertSet -> TcS (Maybe SWorkList)
+trySpontaneousSolve :: WorkItem -> InertSet -> TcS (Maybe (WorkItem, SWorkList)) 
 trySpontaneousSolve workItem@(CTyEqCan { cc_id = cv, cc_flavor = gw, cc_tyvar = tv1, cc_rhs = xi }) inerts 
   | isGiven gw
   = return Nothing
@@ -552,12 +564,12 @@ trySpontaneousSolve workItem@(CTyEqCan { cc_id = cv, cc_flavor = gw, cc_tyvar =
        ; tch2 <- isTouchableMetaTyVar tv2
        ; case (tch1, tch2) of
            (True,  True)  -> trySpontaneousEqTwoWay inerts cv gw tv1 tv2
-           (True,  False) -> trySpontaneousEqOneWay OrientThisWay  inerts cv gw tv1 xi
-           (False, True)  -> trySpontaneousEqOneWay OrientOtherWay inerts cv gw tv2 (mkTyVarTy tv1)
+           (True,  False) -> trySpontaneousEqOneWay inerts cv gw tv1 xi
+           (False, True)  -> trySpontaneousEqOneWay inerts cv gw tv2 (mkTyVarTy tv1)
           _ -> return Nothing }
   | otherwise
   = do { tch1 <- isTouchableMetaTyVar tv1
-       ; if tch1 then trySpontaneousEqOneWay OrientThisWay inerts cv gw tv1 xi
+       ; if tch1 then trySpontaneousEqOneWay inerts cv gw tv1 xi
                  else do { traceTcS "Untouchable LHS, can't spontaneously solve workitem:" (ppr workItem) 
                          ; return Nothing }
        }
@@ -568,19 +580,16 @@ trySpontaneousSolve workItem@(CTyEqCan { cc_id = cv, cc_flavor = gw, cc_tyvar =
 trySpontaneousSolve _ _ = return Nothing 
 
 ----------------
-trySpontaneousEqOneWay :: OrientFlag 
-                       -> InertSet -> CoVar -> CtFlavor -> TcTyVar -> Xi 
-                       -> TcS (Maybe SWorkList)
--- NB: The OrientFlag is there to help us recover the orientation of the original 
--- constraint which is important for enforcing the canonical constraints invariants. 
--- Also, tv is a MetaTyVar, not untouchable
-trySpontaneousEqOneWay or_flag inerts cv gw tv xi      
+trySpontaneousEqOneWay :: InertSet -> CoVar -> CtFlavor -> TcTyVar -> Xi 
+                       -> TcS (Maybe (WorkItem,SWorkList))
+-- tv is a MetaTyVar, not untouchable
+trySpontaneousEqOneWay inerts cv gw tv xi      
   | not (isSigTyVar tv) || isTyVarTy xi 
   = do { kxi <- zonkTcTypeTcS xi >>= return . typeKind  -- Must look through the TcTyBinds
                                                         -- hence kxi and not typeKind xi
                                                         -- See Note [Kind Errors]
        ; if kxi `isSubKind` tyVarKind tv then
-             solveWithIdentity or_flag inerts cv gw tv xi
+             solveWithIdentity inerts cv gw tv xi
          else if tyVarKind tv `isSubKind` kxi then 
              return Nothing -- kinds are compatible but we can't solveWithIdentity this way
                             -- This case covers the  a_touchable :: * ~ b_untouchable :: ?? 
@@ -593,13 +602,13 @@ trySpontaneousEqOneWay or_flag inerts cv gw tv xi
 
 ----------------
 trySpontaneousEqTwoWay :: InertSet -> CoVar -> CtFlavor -> TcTyVar -> TcTyVar
-                       -> TcS (Maybe SWorkList)
+                       -> TcS (Maybe (WorkItem,SWorkList))
 -- Both tyvars are *touchable* MetaTyvars so there is only a chance for kind error here
 trySpontaneousEqTwoWay inerts cv gw tv1 tv2
   | k1 `isSubKind` k2
-  , nicer_to_update_tv2 = solveWithIdentity OrientOtherWay inerts cv gw tv2 (mkTyVarTy tv1)
+  , nicer_to_update_tv2 = solveWithIdentity inerts cv gw tv2 (mkTyVarTy tv1)
   | k2 `isSubKind` k1 
-  = solveWithIdentity OrientThisWay inerts cv gw tv1 (mkTyVarTy tv2) 
+  = solveWithIdentity inerts cv gw tv1 (mkTyVarTy tv2) 
   | otherwise -- None is a subkind of the other, but they are both touchable! 
   = kindErrorTcS gw (mkTyVarTy tv1) (mkTyVarTy tv2) -- See Note [Kind errors]
   where
@@ -663,8 +672,8 @@ Caveat:
 Note [Loopy Spontaneous Solving] 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Example 1: (The problem of loopy spontaneous solving) 
-****************************************************************************
+Example 1: [The problem of loopy spontaneous solving]
+----------
 Consider the original wanted: 
    wanted :  Maybe (E alpha) ~ alpha 
 where E is a type family, such that E (T x) = x. After canonicalization, 
@@ -681,8 +690,8 @@ actually solving. But this occurs check *must look through* flatten skolems.
 However, it may be the case that the flatten skolem in hand is equal to some other 
 flatten skolem whith *does not* mention our unification variable. Here's a typical example:
 
-Example 2: (The need of keeping track of flatten skolem equivalence classes) 
-****************************************************************************
+Example 2: [The need of keeping track of flatten skolem equivalence classes]
+----------
 Original wanteds: 
    g: F alpha ~ F beta 
    w: alpha ~ F alpha 
@@ -701,8 +710,8 @@ We will look inside f2, which immediately mentions (F alpha), so it's not good t
 by looking at the equivalence class of the flatten skolems, we can see that it is fine to 
 unify (alpha ~ f1) which solves our goals! 
 
-Example 3: (The need of looking through TyBinds for already spontaneously solved variables)
-*******************************************************************************************
+Example 3: [The need of looking through TyBinds for already spontaneously solved variables]
+----------
 A similar problem happens because of other spontaneous solving. Suppose we have the 
 following wanteds, arriving in this exact order:
   (first)  w: beta ~ alpha 
@@ -716,8 +725,8 @@ that is wrong since fsk mentions beta, which has already secretly been unified t
 To avoid this problem, the same occurs check must unveil rewritings that can happen because 
 of spontaneously having solved other constraints. 
 
-Example 4: (Orientation of (tv ~ xi) equalities) 
-************************************************
+Example 4: [Orientation of (tv ~ xi) equalities] 
+----------
 We orient equalities (tv ~ xi) so that flatten skolems appear on the left, if possible. Here
 is an example of why this is needed: 
 
@@ -736,7 +745,30 @@ By orienting the equalities so that flatten skolems are in the LHS we are elimin
 as much as possible from the RHS of other wanted equalities, and hence it suffices to look 
 in their flatten skolem equivalence classes. 
 
-This situation appears in the IndTypesPerf test case, inside indexed-types/.
+NB: This situation appears in the IndTypesPerf test case, inside indexed-types/.
+
+Caveat: You may wonder if we should be doing this for unification variables as well. 
+However, Note [Efficient Orientation], Case 2, demonstrates that this is not possible 
+at least for touchable unification variables which we have to keep oriented with the 
+touchable on the LHS to be able to eliminate it. So then, what about untouchables? 
+
+Example 4a: 
+-----------
+  Untouchable = beta, Touchable = alpha 
+
+  [Wanted] w1: alpha ~ fsk 
+  [Given]  g1: F alpha ~ fsk 
+  [Given]  g2: beta ~ fsk 
+  Flatten skolem equivalence class = [] 
+
+Should we be able to unify  alpha := beta to solve the constraint? Arguably yes, but 
+that implies that an *untouchable* unification variable (beta) is in the same equivalence
+class as a flatten skolem that mentions @alpha@. I.e. g2 means that: 
+  beta ~ F alpha
+But I do not think that there is any way to produce evidence for such a constraint from
+the outside other than beta := F alpha, which violates the OutsideIn-ness.  
+
+
 
 Note [Avoid double unifications] 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -758,50 +790,69 @@ unification variables as RHS of type family equations: F xis ~ alpha.
 
 \begin{code}
 ----------------
-solveWithIdentity :: OrientFlag 
-                  -> InertSet 
+solveWithIdentity :: InertSet 
                   -> CoVar -> CtFlavor -> TcTyVar -> Xi 
-                  -> TcS (Maybe SWorkList)
+                  -> TcS (Maybe (WorkItem, SWorkList)) 
 -- Solve with the identity coercion 
 -- Precondition: kind(xi) is a sub-kind of kind(tv)
 -- Precondition: CtFlavor is Wanted or Derived
 -- See [New Wanted Superclass Work] to see why solveWithIdentity 
 --     must work for Derived as well as Wanted
-solveWithIdentity or_flag inerts cv gw tv xi 
+-- Returns: (workItem, workList) where 
+--        workItem = the new Given constraint
+--        workList = some additional work that may have been produced as a result of flattening
+--                   in case we did some chasing through flatten skolem equivalence classes.
+solveWithIdentity inerts cv gw tv xi 
   = do { tybnds <- getTcSTyBindsMap
        ; case occurCheck tybnds inerts tv xi of 
            Nothing              -> return Nothing 
            Just (xi_unflat,coi) -> solve_with xi_unflat coi }
   where
-    solve_with xi_unflat coi  -- coi : xi_unflat ~ xi  
+    solve_with xi_unflat coi  -- coi : xi_unflat ~ xi
       = do { traceTcS "Sneaky unification:" $ 
                        vcat [text "Coercion variable:  " <+> ppr gw, 
                              text "Coercion:           " <+> pprEq (mkTyVarTy tv) xi,
                              text "Left  Kind is     : " <+> ppr (typeKind (mkTyVarTy tv)),
                              text "Right Kind is     : " <+> ppr (typeKind xi)
                   ]
---           ; setWantedTyBind tv xi_unflat        -- Set tv := xi_unflat
---           ; cv_given <- newGivOrDerCoVar (mkTyVarTy tv) xi_unflat xi_unflat
+
+           ; setWantedTyBind tv xi_unflat        -- Set tv := xi_unflat
+           ; cv_given <- newGivOrDerCoVar (mkTyVarTy tv) xi_unflat xi_unflat
            ; let flav = mkGivenFlavor gw UnkSkol 
-           ; (cts, co) <- case coi of 
-               ACo co  -> do { cv_given <- newGivOrDerCoVar (mkTyVarTy tv)  xi_unflat xi_unflat
-                             ; setWantedTyBind tv xi_unflat
-                             ; can_eqs <- case or_flag of 
-                                            OrientThisWay  -> canEq flav cv_given (mkTyVarTy tv) xi_unflat
-                                            OrientOtherWay -> canEq flav cv_given xi_unflat (mkTyVarTy tv) 
-                             ; return (can_eqs, co) }
-               IdCo co -> do { cv_given <- newGivOrDerCoVar (mkTyVarTy tv) xi xi 
-                             ; setWantedTyBind tv xi
-                             ; can_eqs <- case or_flag of 
-                                            OrientThisWay  -> canEq flav cv_given (mkTyVarTy tv) xi
-                                            OrientOtherWay -> canEq flav cv_given xi (mkTyVarTy tv)
-                             ; return (can_eqs, co) }
+           ; (ct,cts, co) <- case coi of 
+               ACo co  -> do { (cc,ccs) <- canEqLeafTyVarLeft flav cv_given tv xi_unflat
+                             ; return (cc, ccs, co) } 
+               IdCo co -> return $ (CTyEqCan { cc_id = cv_given 
+                                             , cc_flavor = mkGivenFlavor gw UnkSkol
+                                             , cc_tyvar = tv, cc_rhs = xi }
+                                      -- xi, *not* xi_unflat because 
+                                      -- xi_unflat may require flattening!
+                                   , emptyWorkList, co)
            ; case gw of 
                Wanted  {} -> setWantedCoBind  cv co
                Derived {} -> setDerivedCoBind cv co 
                _          -> pprPanic "Can't spontaneously solve *given*" empty 
-                     -- See Note [Avoid double unifications] 
-           ; return $ Just cts }
+                     -- See Note [Avoid double unifications]
+           ; return $ Just (ct,cts)
+           }
+
+--            ; let flav = mkGivenFlavor gw UnkSkol 
+--            ; (cts, co) <- case coi of 
+--                             -- TODO: Optimise this, along the way it used to be 
+--                ACo co  -> do { cv_given <- newGivOrDerCoVar (mkTyVarTy tv)  xi_unflat xi_unflat
+--                              ; setWantedTyBind tv xi_unflat
+--                              ; can_eqs <- canEq flav cv_given (mkTyVarTy tv) xi_unflat
+--                              ; return (can_eqs, co) }
+--                IdCo co -> do { cv_given <- newGivOrDerCoVar (mkTyVarTy tv) xi xi 
+--                              ; setWantedTyBind tv xi
+--                              ; can_eqs <- canEq flav cv_given (mkTyVarTy tv) xi
+--                              ; return (can_eqs, co) }
+--            ; case gw of 
+--                Wanted  {} -> setWantedCoBind  cv co
+--                Derived {} -> setDerivedCoBind cv co 
+--                _          -> pprPanic "Can't spontaneously solve *given*" empty 
+--                   -- See Note [Avoid double unifications] 
+--            ; return $ Just cts }
 
 occurCheck :: VarEnv (TcTyVar, TcType) -> InertSet
            -> TcTyVar -> TcType -> Maybe (TcType,CoercionI) 
index a487fe0..d558e69 100644 (file)
@@ -10,6 +10,8 @@ module TcSMonad (
     makeGivens, makeSolvedByInst,
 
     CtFlavor (..), isWanted, isGiven, isDerived, isDerivedSC, isDerivedByInst, 
+    isGivenCt, isWantedCt, 
+
     DerivedOrig (..), 
     canRewrite, canSolve,
     combineCtLoc, mkGivenFlavor,
@@ -140,7 +142,7 @@ data CanonicalCt
   | CIPCan {   -- ?x::tau
       -- See note [Canonical implicit parameter constraints].
       cc_id     :: EvVar,
-      cc_flavor :: CtFlavor, 
+      cc_flavor :: CtFlavor,
       cc_ip_nm  :: IPName Name,
       cc_ip_ty  :: TcTauType
     }
@@ -150,8 +152,9 @@ data CanonicalCt
        --   * tv not in tvs(xi)   (occurs check)
        --   * If constraint is given then typeKind xi `compatKind` typeKind tv 
        --                See Note [Spontaneous solving and kind compatibility] 
-       --   * if xi is a flatten skolem then tv must be a flatten skolem
-       --     i.e. equalities prefer flatten skolems in their LHS. 
+       --   * if @xi@ is a flatten skolem then @tv@ can only be: 
+       --              - a flatten skolem or a unification variable
+       --     i.e. equalities prefer flatten skolems in their LHS 
        --                See Note [Loopy Spontaneous Solving, Example 4]
        --                Also related to [Flatten Skolem Equivalence Classes]
       cc_id     :: EvVar, 
@@ -331,6 +334,11 @@ isDerivedByInst :: CtFlavor -> Bool
 isDerivedByInst (Derived _ DerInst) = True 
 isDerivedByInst _                   = False 
 
+isWantedCt :: CanonicalCt -> Bool 
+isWantedCt ct = isWanted (cc_flavor ct)
+isGivenCt :: CanonicalCt -> Bool 
+isGivenCt ct = isGiven (cc_flavor ct) 
+
 canSolve :: CtFlavor -> CtFlavor -> Bool 
 -- canSolve ctid1 ctid2 
 -- The constraint ctid1 can be used to solve ctid2