[commit: ghc] master: Document and improve superclass expansion (8871737)

git at git.haskell.org git at git.haskell.org
Mon Feb 8 15:07:40 UTC 2016


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/8871737db588b1cb8f7d33d60c5af80b85b2422d/ghc

>---------------------------------------------------------------

commit 8871737db588b1cb8f7d33d60c5af80b85b2422d
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date:   Mon Feb 8 13:14:02 2016 +0000

    Document and improve superclass expansion
    
    When investigating Trac #11523 I found that superclass
    expansion was a little over-aggressive; we were sort of
    unrolling each loop twice.
    
    This patch corrects that, and adds explanatory comments.


>---------------------------------------------------------------

8871737db588b1cb8f7d33d60c5af80b85b2422d
 compiler/typecheck/TcCanonical.hs | 45 ++++++++++++++++++++++++++++-----------
 compiler/typecheck/TcRnTypes.hs   |  3 ++-
 2 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/compiler/typecheck/TcCanonical.hs b/compiler/typecheck/TcCanonical.hs
index 5dc35ac..75996f8 100644
--- a/compiler/typecheck/TcCanonical.hs
+++ b/compiler/typecheck/TcCanonical.hs
@@ -366,21 +366,37 @@ mkGivensWithSuperClasses :: CtLoc -> [EvId] -> TcS [Ct]
 -- From a given EvId, make its Ct, plus the Ct's of its superclasses
 -- See Note [The superclass story]
 -- The loop-breaking here follows Note [Expanding superclasses] in TcType
+--
+-- Example:  class D a => C a
+--           class C [a] => D a
+-- makeGivensWithSuperClasses (C x) will return (C x, D x, C[x])
+--   i.e. up to and including the first repetition of C
 mkGivensWithSuperClasses loc ev_ids = concatMapM go ev_ids
   where
-    go ev_id = mk_superclasses emptyNameSet $
-               CtGiven { ctev_evar = ev_id
-                       , ctev_pred = evVarPred ev_id
-                       , ctev_loc  = loc }
+    go ev_id = mk_superclasses emptyNameSet this_ev
+       where
+         this_ev = CtGiven { ctev_evar = ev_id
+                           , ctev_pred = evVarPred ev_id
+                           , ctev_loc = loc }
 
 makeSuperClasses :: [Ct] -> TcS [Ct]
 -- Returns strict superclasses, transitively, see Note [The superclasses story]
 -- See Note [The superclass story]
 -- The loop-breaking here follows Note [Expanding superclasses] in TcType
+-- Specifically, for an incoming (C t) constraint, we return all of (C t)'s
+--    superclasses, up to /and including/ the first repetition of C
+--
+-- Example:  class D a => C a
+--           class C [a] => D a
+-- makeSuperClasses (C x) will return (D x, C [x])
+--
+-- NB: the incoming constraints have had their cc_pend_sc flag already
+--     flipped to False, by isPendingScDict, so we are /obliged/ to at
+--     least produce the immediate superclasses
 makeSuperClasses cts = concatMapM go cts
   where
     go (CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys })
-          = mk_strict_superclasses emptyNameSet ev cls tys
+          = mk_strict_superclasses (unitNameSet (className cls)) ev cls tys
     go ct = pprPanic "makeSuperClasses" (ppr ct)
 
 mk_superclasses :: NameSet -> CtEvidence -> TcS [Ct]
@@ -393,13 +409,13 @@ mk_superclasses rec_clss ev
   = return [mkNonCanonical ev]
 
 mk_superclasses_of :: NameSet -> CtEvidence -> Class -> [Type] -> TcS [Ct]
--- Return this class constraint, plus its superclasses
+-- Always return this class constraint,
+-- and expand its superclasses
 mk_superclasses_of rec_clss ev cls tys
-  | loop_found
-  = return [this_ct]
-  | otherwise
-  = do { sc_cts <- mk_strict_superclasses rec_clss' ev cls tys
-       ; return (this_ct : sc_cts) }
+  | loop_found = return [this_ct]  -- cc_pend_sc of this_ct = True
+  | otherwise  = do { sc_cts <- mk_strict_superclasses rec_clss' ev cls tys
+                    ; return (this_ct : sc_cts) }
+                                   -- cc_pend_sc of this_ct = False
   where
     cls_nm     = className cls
     loop_found = cls_nm `elemNameSet` rec_clss
@@ -407,15 +423,19 @@ mk_superclasses_of rec_clss ev cls tys
                | otherwise         = rec_clss `extendNameSet` cls_nm
     this_ct    = CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys
                           , cc_pend_sc = loop_found }
+                 -- NB: If there is a loop, we cut off, so we have not
+                 --     added the superclasses, hence cc_pend_sc = True
 
 mk_strict_superclasses :: NameSet -> CtEvidence -> Class -> [Type] -> TcS [Ct]
+-- Always return the immediate superclasses of (cls tys);
+-- and expand their superclasses, provided none of them are in rec_clss
+-- nor are repeated
 mk_strict_superclasses rec_clss ev cls tys
   | CtGiven { ctev_evar = evar, ctev_loc = loc } <- ev
   = do { sc_evs <- newGivenEvVars (mk_given_loc loc)
                                   (mkEvScSelectors (EvId evar) cls tys)
        ; concatMapM (mk_superclasses rec_clss) sc_evs }
 
-
   | isEmptyVarSet (tyCoVarsOfTypes tys)
   = return [] -- Wanteds with no variables yield no deriveds.
               -- See Note [Improvement from Ground Wanteds]
@@ -445,7 +465,6 @@ mk_strict_superclasses rec_clss ev cls tys
        = loc        -- is only used for Givens, but does no harm
 
 
-
 {-
 ************************************************************************
 *                                                                      *
diff --git a/compiler/typecheck/TcRnTypes.hs b/compiler/typecheck/TcRnTypes.hs
index 151e370..0474f74 100644
--- a/compiler/typecheck/TcRnTypes.hs
+++ b/compiler/typecheck/TcRnTypes.hs
@@ -1366,7 +1366,7 @@ data Ct
       cc_class  :: Class,
       cc_tyargs :: [Xi],       -- cc_tyargs are function-free, hence Xi
       cc_pend_sc :: Bool       -- True <=> (a) cc_class has superclasses
-                               --          (b) we have not yet added those
+                               --          (b) we have not (yet) added those
                                --              superclasses as Givens
            -- NB: cc_pend_sc is used for G/W/D.  For W/D the reason
            --     we need superclasses is to expose possible improvement
@@ -1769,6 +1769,7 @@ isUserTypeErrorCt ct = case getUserTypeErrorMsg ct of
                          _      -> False
 
 isPendingScDict :: Ct -> Maybe Ct
+-- Says whether cc_pend_sc is True, AND if so flips the flag
 isPendingScDict ct@(CDictCan { cc_pend_sc = True })
                   = Just (ct { cc_pend_sc = False })
 isPendingScDict _ = Nothing



More information about the ghc-commits mailing list