Add HsCoreTy to HsType
[ghc-hetmet.git] / compiler / typecheck / TcGenDeriv.lhs
index ec17e69..525f095 100644 (file)
@@ -1,7 +1,9 @@
 %
+% (c) The University of Glasgow 2006
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-\section[TcGenDeriv]{Generating derived instance declarations}
+
+TcGenDeriv: Generating derived instance declarations
 
 This module is nominally ``subordinate'' to @TcDeriv@, which is the
 ``official'' interface to deriving-related things.
@@ -10,6 +12,8 @@ This is where we do all the grimy bindings' generation.
 
 \begin{code}
 module TcGenDeriv (
+       DerivAuxBinds, isDupAux,
+
        gen_Bounded_binds,
        gen_Enum_binds,
        gen_Eq_binds,
@@ -19,58 +23,72 @@ module TcGenDeriv (
        gen_Show_binds,
        gen_Data_binds,
        gen_Typeable_binds,
-       gen_tag_n_con_monobind,
-
-       con2tag_RDR, tag2con_RDR, maxtag_RDR,
-
-       TagThingWanted(..)
+       gen_Functor_binds, 
+       FFoldType(..), functorLikeTraverse, 
+       deepSubtypesContaining, foldDataConArgs,
+       gen_Foldable_binds,
+       gen_Traversable_binds,
+       genAuxBind
     ) where
 
 #include "HsVersions.h"
 
 import HsSyn
-import RdrName         ( RdrName, mkVarUnqual, getRdrName, mkRdrUnqual,
-                          mkDerivedRdrName )
-import BasicTypes      ( Fixity(..), maxPrecedence, Boxity(..) )
-import DataCon         ( isNullarySrcDataCon, dataConTag,
-                         dataConOrigArgTys, dataConSourceArity, fIRST_TAG,
-                         DataCon, dataConName, dataConIsInfix,
-                         dataConFieldLabels )
-import Name            ( getOccString, getSrcLoc, Name, NamedThing(..) )
-
-import HscTypes                ( FixityEnv, lookupFixity )
+import RdrName
+import BasicTypes
+import DataCon
+import Name
+
+import HscTypes
 import PrelInfo
 import PrelNames
-import MkId            ( eRROR_ID )
-import PrimOp          ( PrimOp(..) )
-import SrcLoc          ( Located(..), noLoc, srcLocSpan )
-import TyCon           ( TyCon, isNewTyCon, tyConDataCons, isEnumerationTyCon, tyConArity,
-                         maybeTyConSingleCon, tyConFamilySize, tyConTyVars, tyConName
-                       )
-import TcType          ( isUnLiftedType, tcEqType, Type )
-import TysPrim         ( charPrimTy, intPrimTy, wordPrimTy, addrPrimTy, floatPrimTy, doublePrimTy,
-                         intPrimTyCon )
-import TysWiredIn      ( charDataCon, intDataCon, floatDataCon, doubleDataCon,
-                         intDataCon_RDR, true_RDR, false_RDR )
-import Util            ( zipWithEqual, isSingleton,
-                         zipWith3Equal, nOfThem, zipEqual )
-import Constants
-import List            ( partition, intersperse )
+import PrimOp
+import SrcLoc
+import TyCon
+import TcType
+import TysPrim
+import TysWiredIn
+import Type
+import Var( TyVar )
+import TypeRep
+import VarSet
+import State
+import Util
+import MonadUtils
 import Outputable
 import FastString
-import OccName
 import Bag
+import Data.List       ( partition, intersperse )
+\end{code}
+
+\begin{code}
+type DerivAuxBinds = [DerivAuxBind]
+
+data DerivAuxBind              -- Please add these auxiliary top-level bindings
+  = GenCon2Tag TyCon           -- The con2Tag for given TyCon
+  | GenTag2Con TyCon           -- ...ditto tag2Con
+  | GenMaxTag  TyCon           -- ...and maxTag
+       -- All these generate ZERO-BASED tag operations
+       -- I.e first constructor has tag 0
+
+       -- Scrap your boilerplate
+  | MkDataCon DataCon          -- For constructor C we get $cC :: Constr
+  | MkTyCon   TyCon            -- For tycon T we get       $tT :: DataType
+
+
+isDupAux :: DerivAuxBind -> DerivAuxBind -> Bool
+isDupAux (GenCon2Tag tc1) (GenCon2Tag tc2) = tc1 == tc2
+isDupAux (GenTag2Con tc1) (GenTag2Con tc2) = tc1 == tc2
+isDupAux (GenMaxTag tc1)  (GenMaxTag tc2)  = tc1 == tc2
+isDupAux (MkDataCon dc1)  (MkDataCon dc2)  = dc1 == dc2
+isDupAux (MkTyCon tc1)    (MkTyCon tc2)    = tc1 == tc2
+isDupAux _                _                = False
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Generating code, by derivable class}
-%*                                                                     *
-%************************************************************************
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Eq@ instance declarations}
+               Eq instances
 %*                                                                     *
 %************************************************************************
 
@@ -143,33 +161,34 @@ instance ... Eq (Foo ...) where
 
 
 \begin{code}
-gen_Eq_binds :: TyCon -> LHsBinds RdrName
-
-gen_Eq_binds tycon
-  = let
-       tycon_loc = getSrcSpan tycon
-
-        (nullary_cons, nonnullary_cons)
-           | isNewTyCon tycon = ([], tyConDataCons tycon)
-           | otherwise       = partition isNullarySrcDataCon (tyConDataCons tycon)
-
-       rest
-         = if (null nullary_cons) then
-               case maybeTyConSingleCon tycon of
-                 Just _ -> []
-                 Nothing -> -- if cons don't match, then False
-                    [([nlWildPat, nlWildPat], false_Expr)]
-           else -- calc. and compare the tags
-                [([a_Pat, b_Pat],
-                   untag_Expr tycon [(a_RDR,ah_RDR), (b_RDR,bh_RDR)]
-                              (genOpApp (nlHsVar ah_RDR) eqInt_RDR (nlHsVar bh_RDR)))]
-    in
-    listToBag [
-      mk_FunBind tycon_loc eq_RDR ((map pats_etc nonnullary_cons) ++ rest),
-      mk_easy_FunBind tycon_loc ne_RDR [a_Pat, b_Pat] (
-       nlHsApp (nlHsVar not_RDR) (nlHsPar (nlHsVarApps eq_RDR [a_RDR, b_RDR])))
-    ]
+gen_Eq_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Eq_binds loc tycon
+  = (method_binds, aux_binds)
   where
+    (nullary_cons, nonnullary_cons)
+       | isNewTyCon tycon = ([], tyConDataCons tycon)
+       | otherwise           = partition isNullarySrcDataCon (tyConDataCons tycon)
+
+    no_nullary_cons = null nullary_cons
+
+    rest | no_nullary_cons
+        = case tyConSingleDataCon_maybe tycon of
+                 Just _ -> []
+                 Nothing -> -- if cons don't match, then False
+                    [([nlWildPat, nlWildPat], false_Expr)]
+        | otherwise -- calc. and compare the tags
+        = [([a_Pat, b_Pat],
+           untag_Expr tycon [(a_RDR,ah_RDR), (b_RDR,bh_RDR)]
+                      (genOpApp (nlHsVar ah_RDR) eqInt_RDR (nlHsVar bh_RDR)))]
+
+    aux_binds | no_nullary_cons = []
+             | otherwise       = [GenCon2Tag tycon]
+
+    method_binds = listToBag [
+                       mk_FunBind loc eq_RDR ((map pats_etc nonnullary_cons) ++ rest),
+                       mk_easy_FunBind loc ne_RDR [a_Pat, b_Pat] (
+                       nlHsApp (nlHsVar not_RDR) (nlHsPar (nlHsVarApps eq_RDR [a_RDR, b_RDR])))]
+
     ------------------------------------------------------------------
     pats_etc data_con
       = let
@@ -193,176 +212,294 @@ gen_Eq_binds tycon
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Ord@ instance declarations}
+       Ord instances
 %*                                                                     *
 %************************************************************************
 
-For a derived @Ord@, we concentrate our attentions on @compare@
-\begin{verbatim}
-compare :: a -> a -> Ordering
-data Ordering = LT | EQ | GT deriving ()
-\end{verbatim}
-
-We will use the same example data type as above:
-\begin{verbatim}
-data Foo ... = N1 | N2 ... | Nn | O1 a b | O2 Int | O3 Double b b | ...
-\end{verbatim}
+Note [Generating Ord instances]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Suppose constructors are K1..Kn, and some are nullary.  
+The general form we generate is:
+
+* Do case on first argument
+       case a of
+          K1 ... -> rhs_1
+          K2 ... -> rhs_2
+          ...
+          Kn ... -> rhs_n
+          _ -> nullary_rhs
+
+* To make rhs_i
+     If i = 1, 2, n-1, n, generate a single case. 
+       rhs_2    case b of 
+                   K1 {}  -> LT
+                   K2 ... -> ...eq_rhs(K2)...
+                   _      -> GT
+
+     Otherwise do a tag compare against the bigger range
+     (because this is the one most likely to succeed)
+        rhs_3    case tag b of tb ->
+                 if 3 <# tg then GT
+                 else case b of 
+                         K3 ... -> ...eq_rhs(K3)....
+                         _      -> LT
+
+* To make eq_rhs(K), which knows that 
+    a = K a1 .. av
+    b = K b1 .. bv
+  we just want to compare (a1,b1) then (a2,b2) etc.
+  Take care on the last field to tail-call into comparing av,bv
+
+* To make nullary_rhs generate this
+     case con2tag a of a# -> 
+     case con2tag b of -> 
+     a# `compare` b#
+
+Several special cases:
+
+* Two or fewer nullary constructors: don't generate nullary_rhs
+
+* Be careful about unlifted comparisons.  When comparing unboxed
+  values we can't call the overloaded functions.  
+  See function unliftedOrdOp
+
+Note [Do not rely on compare]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It's a bad idea to define only 'compare', and build the other binary
+comparisions on top of it; see Trac #2130, #4019.  Reason: we don't
+want to laboriously make a three-way comparison, only to extract a
+binary result, something like this:
+     (>) (I# x) (I# y) = case <# x y of
+                            True -> False
+                            False -> case ==# x y of 
+                                       True  -> False
+                                       False -> True
+
+So for sufficiently small types (few constructors, or all nullary) 
+we generate all methods; for large ones we just use 'compare'.
 
-\begin{itemize}
-\item
-  We do all the other @Ord@ methods with calls to @compare@:
-\begin{verbatim}
-instance ... (Ord <wurble> <wurble>) where
-    a <  b  = case (compare a b) of { LT -> True;  EQ -> False; GT -> False }
-    a <= b  = case (compare a b) of { LT -> True;  EQ -> True;  GT -> False }
-    a >= b  = case (compare a b) of { LT -> False; EQ -> True;  GT -> True  }
-    a >  b  = case (compare a b) of { LT -> False; EQ -> False; GT -> True  }
+\begin{code}
+data OrdOp = OrdCompare | OrdLT | OrdLE | OrdGE | OrdGT
+
+------------
+ordMethRdr :: OrdOp -> RdrName
+ordMethRdr op
+  = case op of
+       OrdCompare -> compare_RDR
+       OrdLT      -> lt_RDR
+       OrdLE      -> le_RDR
+       OrdGE      -> ge_RDR
+       OrdGT      -> gt_RDR
+
+------------
+ltResult :: OrdOp -> LHsExpr RdrName
+-- Knowing a<b, what is the result for a `op` b?
+ltResult OrdCompare = ltTag_Expr
+ltResult OrdLT      = true_Expr
+ltResult OrdLE      = true_Expr
+ltResult OrdGE      = false_Expr
+ltResult OrdGT      = false_Expr
+
+------------
+eqResult :: OrdOp -> LHsExpr RdrName
+-- Knowing a=b, what is the result for a `op` b?
+eqResult OrdCompare = eqTag_Expr
+eqResult OrdLT      = false_Expr
+eqResult OrdLE      = true_Expr
+eqResult OrdGE      = true_Expr
+eqResult OrdGT      = false_Expr
+
+------------
+gtResult :: OrdOp -> LHsExpr RdrName
+-- Knowing a>b, what is the result for a `op` b?
+gtResult OrdCompare = gtTag_Expr
+gtResult OrdLT      = false_Expr
+gtResult OrdLE      = false_Expr
+gtResult OrdGE      = true_Expr
+gtResult OrdGT      = true_Expr
+
+------------
+gen_Ord_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Ord_binds loc tycon
+  = (unitBag (mkOrdOp OrdCompare) `unionBags` other_ops, aux_binds)
+  where
+    aux_binds | single_con_type = []
+              | otherwise       = [GenCon2Tag tycon]
 
-    max a b = case (compare a b) of { LT -> b; EQ -> a;  GT -> a }
-    min a b = case (compare a b) of { LT -> a; EQ -> b;  GT -> b }
+       -- Note [Do not rely on compare]
+    other_ops | (last_tag - first_tag) <= 2    -- 1-3 constructors
+                || null non_nullary_cons       -- Or it's an enumeration
+              = listToBag (map mkOrdOp [OrdLT,OrdLE,OrdGE,OrdGT])
+             | otherwise
+              = emptyBag
 
-    -- compare to come...
-\end{verbatim}
+    get_tag con = dataConTag con - fIRST_TAG   
+       -- We want *zero-based* tags, because that's what 
+       -- con2Tag returns (generated by untag_Expr)!
 
-\item
-  @compare@ always has two parts.  First, we use the compared
-  data-constructors' tags to deal with the case of different
-  constructors:
-\begin{verbatim}
-compare a b = case (con2tag_Foo a) of { a# ->
-             case (con2tag_Foo b) of { b# ->
-             case (a# ==# b#)     of {
-              True  -> cmp_eq a b
-              False -> case (a# <# b#) of
-                        True  -> _LT
-                        False -> _GT
-             }}}
-  where
-    cmp_eq = ... to come ...
-\end{verbatim}
-
-\item
-  We are only left with the ``help'' function @cmp_eq@, to deal with
-  comparing data constructors with the same tag.
+    tycon_data_cons = tyConDataCons tycon
+    single_con_type = isSingleton tycon_data_cons
+    (first_con : _) = tycon_data_cons
+    (last_con : _)  = reverse tycon_data_cons
+    first_tag      = get_tag first_con
+    last_tag       = get_tag last_con
 
-  For the ordinary constructors (if any), we emit the sorta-obvious
-  compare-style stuff; for our example:
-\begin{verbatim}
-cmp_eq (O1 a1 b1) (O1 a2 b2)
-  = case (compare a1 a2) of { LT -> LT; EQ -> compare b1 b2; GT -> GT }
-
-cmp_eq (O2 a1) (O2 a2)
-  = compare a1 a2
-
-cmp_eq (O3 a1 b1 c1) (O3 a2 b2 c2)
-  = case (compare a1 a2) of {
-      LT -> LT;
-      GT -> GT;
-      EQ -> case compare b1 b2 of {
-             LT -> LT;
-             GT -> GT;
-             EQ -> compare c1 c2
-           }
-    }
-\end{verbatim}
+    (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon tycon_data_cons
+    
 
-  Again, we must be careful about unlifted comparisons.  For example,
-  if \tr{a1} and \tr{a2} were \tr{Int#}s in the 2nd example above, we'd need to
-  generate:
+    mkOrdOp :: OrdOp -> LHsBind RdrName
+    -- Returns a binding   op a b = ... compares a and b according to op ....
+    mkOrdOp op = mk_easy_FunBind loc (ordMethRdr op) [a_Pat, b_Pat] (mkOrdOpRhs op)
 
-\begin{verbatim}
-cmp_eq lt eq gt (O2 a1) (O2 a2)
-  = compareInt# a1 a2
-  -- or maybe the unfolded equivalent
-\end{verbatim}
+    mkOrdOpRhs :: OrdOp -> LHsExpr RdrName
+    mkOrdOpRhs op      -- RHS for comparing 'a' and 'b' according to op
+      | length nullary_cons <= 2  -- Two nullary or fewer, so use cases
+      = nlHsCase (nlHsVar a_RDR) $ 
+        map (mkOrdOpAlt op) tycon_data_cons
+       -- i.e.  case a of { C1 x y -> case b of C1 x y -> ....compare x,y...
+        --                   C2 x   -> case b of C2 x -> ....comopare x.... }
 
-\item
-  For the remaining nullary constructors, we already know that the
-  tags are equal so:
-\begin{verbatim}
-cmp_eq _ _ = EQ
-\end{verbatim}
-\end{itemize}
+      | null non_nullary_cons   -- All nullary, so go straight to comparing tags
+      = mkTagCmp op    
 
-If there is only one constructor in the Data Type we don't need the WildCard Pattern. 
-JJQC-30-Nov-1997
+      | otherwise               -- Mixed nullary and non-nullary
+      = nlHsCase (nlHsVar a_RDR) $
+        (map (mkOrdOpAlt op) non_nullary_cons 
+         ++ [mkSimpleHsAlt nlWildPat (mkTagCmp op)])
 
-\begin{code}
-gen_Ord_binds :: TyCon -> LHsBinds RdrName
 
-gen_Ord_binds tycon
-  = unitBag compare    -- `AndMonoBinds` compare       
-               -- The default declaration in PrelBase handles this
+    mkOrdOpAlt :: OrdOp -> DataCon -> LMatch RdrName
+    -- Make the alternative  (Ki a1 a2 .. av -> 
+    mkOrdOpAlt op data_con
+      = mkSimpleHsAlt (nlConVarPat data_con_RDR as_needed) (mkInnerRhs op data_con)
+      where
+        as_needed    = take (dataConSourceArity data_con) as_RDRs
+        data_con_RDR = getRdrName data_con
+
+    mkInnerRhs op data_con
+      | single_con_type
+      = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con ]
+
+      | tag == first_tag
+      = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (ltResult op) ]
+      | tag == last_tag 
+      = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (gtResult op) ]
+      
+      | tag == first_tag + 1
+      = nlHsCase (nlHsVar b_RDR) [ mkSimpleHsAlt (nlConWildPat first_con) (gtResult op)
+                                 , mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (ltResult op) ]
+      | tag == last_tag - 1
+      = nlHsCase (nlHsVar b_RDR) [ mkSimpleHsAlt (nlConWildPat last_con) (ltResult op)
+                                 , mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (gtResult op) ]
+
+      | tag > last_tag `div` 2 -- lower range is larger
+      = untag_Expr tycon [(b_RDR, bh_RDR)] $
+        nlHsIf (genOpApp (nlHsVar bh_RDR) ltInt_RDR tag_lit)
+              (gtResult op) $  -- Definitely GT
+        nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (ltResult op) ]
+      
+      | otherwise              -- upper range is larger
+      = untag_Expr tycon [(b_RDR, bh_RDR)] $
+        nlHsIf (genOpApp (nlHsVar bh_RDR) gtInt_RDR tag_lit)
+              (ltResult op) $  -- Definitely LT
+        nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con
+                                 , mkSimpleHsAlt nlWildPat (gtResult op) ]
+      where
+        tag     = get_tag data_con 
+        tag_lit = noLoc (HsLit (HsIntPrim (toInteger tag)))
+
+    mkInnerEqAlt :: OrdOp -> DataCon -> LMatch RdrName
+    -- First argument 'a' known to be built with K
+    -- Returns a case alternative  Ki b1 b2 ... bv -> compare (a1,a2,...) with (b1,b2,...)
+    mkInnerEqAlt op data_con
+      = mkSimpleHsAlt (nlConVarPat data_con_RDR bs_needed) $
+        mkCompareFields tycon op (dataConOrigArgTys data_con) 
+      where
+        data_con_RDR = getRdrName data_con
+        bs_needed    = take (dataConSourceArity data_con) bs_RDRs
+
+    mkTagCmp :: OrdOp -> LHsExpr RdrName  
+    -- Both constructors known to be nullary
+    -- genreates (case data2Tag a of a# -> case data2Tag b of b# -> a# `op` b#
+    mkTagCmp op = untag_Expr tycon [(a_RDR, ah_RDR),(b_RDR, bh_RDR)] $
+                  unliftedOrdOp tycon intPrimTy op ah_RDR bh_RDR
+        
+mkCompareFields :: TyCon -> OrdOp -> [Type] -> LHsExpr RdrName
+-- Generates nested comparisons for (a1,a2...) against (b1,b2,...)
+-- where the ai,bi have the given types
+mkCompareFields tycon op tys
+  = go tys as_RDRs bs_RDRs
   where
-    tycon_loc = getSrcSpan tycon
-    --------------------------------------------------------------------
-
-    compare = L tycon_loc (mkFunBind (L tycon_loc compare_RDR) compare_matches)
-    compare_matches = [mkMatch [a_Pat, b_Pat] compare_rhs cmp_eq_binds]
-    cmp_eq_binds    = HsValBinds (ValBindsIn (unitBag cmp_eq) [])
-
-    compare_rhs
-       | single_con_type = cmp_eq_Expr a_Expr b_Expr
-       | otherwise
-       = untag_Expr tycon [(a_RDR, ah_RDR), (b_RDR, bh_RDR)]
-                 (cmp_tags_Expr eqInt_RDR ah_RDR bh_RDR
-                       (cmp_eq_Expr a_Expr b_Expr)     -- True case
-                       -- False case; they aren't equal
-                       -- So we need to do a less-than comparison on the tags
-                       (cmp_tags_Expr ltInt_RDR ah_RDR bh_RDR ltTag_Expr gtTag_Expr))
-
-    tycon_data_cons = tyConDataCons tycon
-    single_con_type = isSingleton tycon_data_cons
-    (nullary_cons, nonnullary_cons)
-       | isNewTyCon tycon = ([], tyConDataCons tycon)
-       | otherwise       = partition isNullarySrcDataCon tycon_data_cons
-
-    cmp_eq = mk_FunBind tycon_loc cmp_eq_RDR cmp_eq_match
-    cmp_eq_match
-      | isEnumerationTyCon tycon
-                          -- We know the tags are equal, so if it's an enumeration TyCon,
-                          -- then there is nothing left to do
-                          -- Catch this specially to avoid warnings
-                          -- about overlapping patterns from the desugarer,
-                          -- and to avoid unnecessary pattern-matching
-      = [([nlWildPat,nlWildPat], eqTag_Expr)]
+    go []   _      _          = eqResult op
+    go [ty] (a:_)  (b:_)
+      | isUnLiftedType ty     = unliftedOrdOp tycon ty op a b
+      | otherwise             = genOpApp (nlHsVar a) (ordMethRdr op) (nlHsVar b)
+    go (ty:tys) (a:as) (b:bs) = mk_compare ty a b 
+                                  (ltResult op) 
+                                  (go tys as bs)
+                                  (gtResult op) 
+    go _ _ _ = panic "mkCompareFields"
+
+    -- (mk_compare ty a b) generates
+    --    (case (compare a b) of { LT -> <lt>; EQ -> <eq>; GT -> <bt> })
+    -- but with suitable special cases for 
+    mk_compare ty a b lt eq gt
+      | isUnLiftedType ty
+      = unliftedCompare lt_op eq_op a_expr b_expr lt eq gt
       | otherwise
-      = map pats_etc nonnullary_cons ++
-       (if single_con_type then        -- Omit wildcards when there's just one 
-             []                        -- constructor, to silence desugarer
-       else
-              [([nlWildPat, nlWildPat], default_rhs)])
-
+      = nlHsCase (nlHsPar (nlHsApp (nlHsApp (nlHsVar compare_RDR) a_expr) b_expr))
+          [mkSimpleHsAlt (nlNullaryConPat ltTag_RDR) lt,
+           mkSimpleHsAlt (nlNullaryConPat eqTag_RDR) eq,
+           mkSimpleHsAlt (nlNullaryConPat gtTag_RDR) gt]
       where
-       pats_etc data_con
-         = ([con1_pat, con2_pat],
-            nested_compare_expr tys_needed as_needed bs_needed)
-         where
-           con1_pat = nlConVarPat data_con_RDR as_needed
-           con2_pat = nlConVarPat data_con_RDR bs_needed
-
-           data_con_RDR = getRdrName data_con
-           con_arity   = length tys_needed
-           as_needed   = take con_arity as_RDRs
-           bs_needed   = take con_arity bs_RDRs
-           tys_needed  = dataConOrigArgTys data_con
-
-           nested_compare_expr [ty] [a] [b]
-             = careful_compare_Case tycon ty eqTag_Expr (nlHsVar a) (nlHsVar b)
-
-           nested_compare_expr (ty:tys) (a:as) (b:bs)
-             = let eq_expr = nested_compare_expr tys as bs
-               in  careful_compare_Case tycon ty eq_expr (nlHsVar a) (nlHsVar b)
-
-       default_rhs | null nullary_cons = impossible_Expr       -- Keep desugarer from complaining about
-                                                               -- inexhaustive patterns
-                   | otherwise         = eqTag_Expr            -- Some nullary constructors;
-                                                               -- Tags are equal, no args => return EQ
+        a_expr = nlHsVar a
+        b_expr = nlHsVar b
+        (lt_op, _, eq_op, _, _) = primOrdOps "Ord" tycon ty
+
+unliftedOrdOp :: TyCon -> Type -> OrdOp -> RdrName -> RdrName -> LHsExpr RdrName
+unliftedOrdOp tycon ty op a b
+  = case op of
+       OrdCompare -> unliftedCompare lt_op eq_op a_expr b_expr 
+                                     ltTag_Expr eqTag_Expr gtTag_Expr
+       OrdLT      -> wrap lt_op
+       OrdLE      -> wrap le_op
+       OrdGE      -> wrap ge_op
+       OrdGT      -> wrap gt_op
+  where
+   (lt_op, le_op, eq_op, ge_op, gt_op) = primOrdOps "Ord" tycon ty
+   wrap prim_op = genOpApp a_expr (primOpRdrName prim_op) b_expr 
+   a_expr = nlHsVar a
+   b_expr = nlHsVar b
+
+unliftedCompare :: PrimOp -> PrimOp 
+                -> LHsExpr RdrName -> LHsExpr RdrName  -- What to cmpare
+                -> LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName  -- Three results
+                -> LHsExpr RdrName
+-- Return (if a < b then lt else if a == b then eq else gt)
+unliftedCompare lt_op eq_op a_expr b_expr lt eq gt
+  = nlHsIf (genOpApp a_expr (primOpRdrName lt_op) b_expr) lt $
+                       -- Test (<) first, not (==), becuase the latter
+                       -- is true less often, so putting it first would
+                               -- mean more tests (dynamically)
+        nlHsIf (genOpApp a_expr (primOpRdrName eq_op) b_expr) eq gt
+
+nlConWildPat :: DataCon -> LPat RdrName
+-- The pattern (K {})
+nlConWildPat con = noLoc (ConPatIn (noLoc (getRdrName con))
+                                   (RecCon (HsRecFields { rec_flds = [] 
+                                                        , rec_dotdot = Nothing })))
 \end{code}
 
+                            
+
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Enum@ instance declarations}
+       Enum instances
 %*                                                                     *
 %************************************************************************
 
@@ -402,23 +539,24 @@ instance ... Enum (Foo ...) where
 For @enumFromTo@ and @enumFromThenTo@, we use the default methods.
 
 \begin{code}
-gen_Enum_binds :: TyCon -> LHsBinds RdrName
-
-gen_Enum_binds tycon
-  = listToBag [
-       succ_enum,
-       pred_enum,
-       to_enum,
-       enum_from,
-       enum_from_then,
-       from_enum
-    ]
+gen_Enum_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Enum_binds loc tycon
+  = (method_binds, aux_binds)
   where
-    tycon_loc = getSrcSpan tycon
-    occ_nm    = getOccString tycon
+    method_binds = listToBag [
+                       succ_enum,
+                       pred_enum,
+                       to_enum,
+                       enum_from,
+                       enum_from_then,
+                       from_enum
+                   ]
+    aux_binds = [GenCon2Tag tycon, GenTag2Con tycon, GenMaxTag tycon]
+
+    occ_nm = getOccString tycon
 
     succ_enum
-      = mk_easy_FunBind tycon_loc succ_RDR [a_Pat] $
+      = mk_easy_FunBind loc succ_RDR [a_Pat] $
        untag_Expr tycon [(a_RDR, ah_RDR)] $
        nlHsIf (nlHsApps eq_RDR [nlHsVar (maxtag_RDR tycon),
                               nlHsVarApps intDataCon_RDR [ah_RDR]])
@@ -428,7 +566,7 @@ gen_Enum_binds tycon
                                        nlHsIntLit 1]))
                    
     pred_enum
-      = mk_easy_FunBind tycon_loc pred_RDR [a_Pat] $
+      = mk_easy_FunBind loc pred_RDR [a_Pat] $
        untag_Expr tycon [(a_RDR, ah_RDR)] $
        nlHsIf (nlHsApps eq_RDR [nlHsIntLit 0,
                               nlHsVarApps intDataCon_RDR [ah_RDR]])
@@ -438,7 +576,7 @@ gen_Enum_binds tycon
                                               nlHsLit (HsInt (-1))]))
 
     to_enum
-      = mk_easy_FunBind tycon_loc toEnum_RDR [a_Pat] $
+      = mk_easy_FunBind loc toEnum_RDR [a_Pat] $
        nlHsIf (nlHsApps and_RDR
                [nlHsApps ge_RDR [nlHsVar a_RDR, nlHsIntLit 0],
                  nlHsApps le_RDR [nlHsVar a_RDR, nlHsVar (maxtag_RDR tycon)]])
@@ -446,7 +584,7 @@ gen_Enum_binds tycon
             (illegal_toEnum_tag occ_nm (maxtag_RDR tycon))
 
     enum_from
-      = mk_easy_FunBind tycon_loc enumFrom_RDR [a_Pat] $
+      = mk_easy_FunBind loc enumFrom_RDR [a_Pat] $
          untag_Expr tycon [(a_RDR, ah_RDR)] $
          nlHsApps map_RDR 
                [nlHsVar (tag2con_RDR tycon),
@@ -455,7 +593,7 @@ gen_Enum_binds tycon
                            (nlHsVar (maxtag_RDR tycon)))]
 
     enum_from_then
-      = mk_easy_FunBind tycon_loc enumFromThen_RDR [a_Pat, b_Pat] $
+      = mk_easy_FunBind loc enumFromThen_RDR [a_Pat, b_Pat] $
          untag_Expr tycon [(a_RDR, ah_RDR), (b_RDR, bh_RDR)] $
          nlHsApp (nlHsVarApps map_RDR [tag2con_RDR tycon]) $
            nlHsPar (enum_from_then_to_Expr
@@ -468,31 +606,31 @@ gen_Enum_binds tycon
                           ))
 
     from_enum
-      = mk_easy_FunBind tycon_loc fromEnum_RDR [a_Pat] $
+      = mk_easy_FunBind loc fromEnum_RDR [a_Pat] $
          untag_Expr tycon [(a_RDR, ah_RDR)] $
          (nlHsVarApps intDataCon_RDR [ah_RDR])
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Bounded@ instance declarations}
+       Bounded instances
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-gen_Bounded_binds tycon
-  = if isEnumerationTyCon tycon then
-       listToBag [ min_bound_enum, max_bound_enum ]
-    else
-       ASSERT(isSingleton data_cons)
-       listToBag [ min_bound_1con, max_bound_1con ]
+gen_Bounded_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Bounded_binds loc tycon
+  | isEnumerationTyCon tycon
+  = (listToBag [ min_bound_enum, max_bound_enum ], [])
+  | otherwise
+  = ASSERT(isSingleton data_cons)
+    (listToBag [ min_bound_1con, max_bound_1con ], [])
   where
     data_cons = tyConDataCons tycon
-    tycon_loc = getSrcSpan tycon
 
     ----- enum-flavored: ---------------------------
-    min_bound_enum = mkVarBind tycon_loc minBound_RDR (nlHsVar data_con_1_RDR)
-    max_bound_enum = mkVarBind tycon_loc maxBound_RDR (nlHsVar data_con_N_RDR)
+    min_bound_enum = mkHsVarBind loc minBound_RDR (nlHsVar data_con_1_RDR)
+    max_bound_enum = mkHsVarBind loc maxBound_RDR (nlHsVar data_con_N_RDR)
 
     data_con_1   = head data_cons
     data_con_N   = last data_cons
@@ -502,15 +640,15 @@ gen_Bounded_binds tycon
     ----- single-constructor-flavored: -------------
     arity         = dataConSourceArity data_con_1
 
-    min_bound_1con = mkVarBind tycon_loc minBound_RDR $
+    min_bound_1con = mkHsVarBind loc minBound_RDR $
                     nlHsVarApps data_con_1_RDR (nOfThem arity minBound_RDR)
-    max_bound_1con = mkVarBind tycon_loc maxBound_RDR $
+    max_bound_1con = mkHsVarBind loc maxBound_RDR $
                     nlHsVarApps data_con_1_RDR (nOfThem arity maxBound_RDR)
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Ix@ instance declarations}
+       Ix instances
 %*                                                                     *
 %************************************************************************
 
@@ -567,20 +705,19 @@ we follow the scheme given in Figure~19 of the Haskell~1.2 report
 (p.~147).
 
 \begin{code}
-gen_Ix_binds :: TyCon -> LHsBinds RdrName
+gen_Ix_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
 
-gen_Ix_binds tycon
-  = if isEnumerationTyCon tycon
-    then enum_ixes
-    else single_con_ixes
+gen_Ix_binds loc tycon
+  | isEnumerationTyCon tycon
+  = (enum_ixes, [GenCon2Tag tycon, GenTag2Con tycon, GenMaxTag tycon])
+  | otherwise
+  = (single_con_ixes, [GenCon2Tag tycon])
   where
-    tycon_loc = getSrcSpan tycon
-
     --------------------------------------------------------------
     enum_ixes = listToBag [ enum_range, enum_index, enum_inRange ]
 
     enum_range
-      = mk_easy_FunBind tycon_loc range_RDR [nlTuplePat [a_Pat, b_Pat] Boxed] $
+      = mk_easy_FunBind loc range_RDR [nlTuplePat [a_Pat, b_Pat] Boxed] $
          untag_Expr tycon [(a_RDR, ah_RDR)] $
          untag_Expr tycon [(b_RDR, bh_RDR)] $
          nlHsApp (nlHsVarApps map_RDR [tag2con_RDR tycon]) $
@@ -589,7 +726,7 @@ gen_Ix_binds tycon
                        (nlHsVarApps intDataCon_RDR [bh_RDR]))
 
     enum_index
-      = mk_easy_FunBind tycon_loc unsafeIndex_RDR 
+      = mk_easy_FunBind loc unsafeIndex_RDR 
                [noLoc (AsPat (noLoc c_RDR) 
                           (nlTuplePat [a_Pat, nlWildPat] Boxed)), 
                                d_Pat] (
@@ -605,7 +742,7 @@ gen_Ix_binds tycon
        )
 
     enum_inRange
-      = mk_easy_FunBind tycon_loc inRange_RDR [nlTuplePat [a_Pat, b_Pat] Boxed, c_Pat] $
+      = mk_easy_FunBind loc inRange_RDR [nlTuplePat [a_Pat, b_Pat] Boxed, c_Pat] $
          untag_Expr tycon [(a_RDR, ah_RDR)] (
          untag_Expr tycon [(b_RDR, bh_RDR)] (
          untag_Expr tycon [(c_RDR, ch_RDR)] (
@@ -620,11 +757,9 @@ gen_Ix_binds tycon
       = listToBag [single_con_range, single_con_index, single_con_inRange]
 
     data_con
-      =        case maybeTyConSingleCon tycon of -- just checking...
+      =        case tyConSingleDataCon_maybe tycon of -- just checking...
          Nothing -> panic "get_Ix_binds"
-         Just dc | any isUnLiftedType (dataConOrigArgTys dc)
-                 -> pprPanic "Can't derive Ix for a single-constructor type with primitive argument types:" (ppr tycon)
-                 | otherwise -> dc
+         Just dc -> dc
 
     con_arity    = dataConSourceArity data_con
     data_con_RDR = getRdrName data_con
@@ -638,7 +773,7 @@ gen_Ix_binds tycon
 
     --------------------------------------------------------------
     single_con_range
-      = mk_easy_FunBind tycon_loc range_RDR 
+      = mk_easy_FunBind loc range_RDR 
          [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed] $
        nlHsDo ListComp stmts con_expr
       where
@@ -646,14 +781,18 @@ gen_Ix_binds tycon
 
        mk_qual a b c = noLoc $ mkBindStmt (nlVarPat c)
                                 (nlHsApp (nlHsVar range_RDR) 
-                                       (nlTuple [nlHsVar a, nlHsVar b] Boxed))
+                                         (mkLHsVarTuple [a,b]))
 
     ----------------
     single_con_index
-      = mk_easy_FunBind tycon_loc unsafeIndex_RDR 
+      = mk_easy_FunBind loc unsafeIndex_RDR 
                [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed, 
                 con_pat cs_needed] 
-               (mk_index (zip3 as_needed bs_needed cs_needed))
+        -- We need to reverse the order we consider the components in
+        -- so that
+        --     range (l,u) !! index (l,u) i == i   -- when i is in range
+        -- (from http://haskell.org/onlinereport/ix.html) holds.
+               (mk_index (reverse $ zip3 as_needed bs_needed cs_needed))
       where
        -- index (l1,u1) i1 + rangeSize (l1,u1) * (index (l2,u2) i2 + ...)
        mk_index []        = nlHsIntLit 0
@@ -664,26 +803,25 @@ gen_Ix_binds tycon
            ) plus_RDR (
                genOpApp (
                    (nlHsApp (nlHsVar unsafeRangeSize_RDR) 
-                          (nlTuple [nlHsVar l, nlHsVar u] Boxed))
+                            (mkLHsVarTuple [l,u]))
                ) times_RDR (mk_index rest)
           )
        mk_one l u i
-         = nlHsApps unsafeIndex_RDR [nlTuple [nlHsVar l, nlHsVar u] Boxed, nlHsVar i]
+         = nlHsApps unsafeIndex_RDR [mkLHsVarTuple [l,u], nlHsVar i]
 
     ------------------
     single_con_inRange
-      = mk_easy_FunBind tycon_loc inRange_RDR 
+      = mk_easy_FunBind loc inRange_RDR 
                [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed, 
                 con_pat cs_needed] $
          foldl1 and_Expr (zipWith3Equal "single_con_inRange" in_range as_needed bs_needed cs_needed)
       where
-       in_range a b c = nlHsApps inRange_RDR [nlTuple [nlHsVar a, nlHsVar b] Boxed,
-                                              nlHsVar c]
+       in_range a b c = nlHsApps inRange_RDR [mkLHsVarTuple [a,b], nlHsVar c]
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Read@ instance declarations}
+       Read instances
 %*                                                                     *
 %************************************************************************
 
@@ -726,24 +864,23 @@ instance Read T where
 
 
 \begin{code}
-gen_Read_binds :: FixityEnv -> TyCon -> LHsBinds RdrName
+gen_Read_binds :: FixityEnv -> SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
 
-gen_Read_binds get_fixity tycon
-  = listToBag [read_prec, default_readlist, default_readlistprec]
+gen_Read_binds get_fixity loc tycon
+  = (listToBag [read_prec, default_readlist, default_readlistprec], [])
   where
     -----------------------------------------------------------------------
     default_readlist 
-       = mkVarBind loc readList_RDR     (nlHsVar readListDefault_RDR)
+       = mkHsVarBind loc readList_RDR     (nlHsVar readListDefault_RDR)
 
     default_readlistprec
-       = mkVarBind loc readListPrec_RDR (nlHsVar readListPrecDefault_RDR)
+       = mkHsVarBind loc readListPrec_RDR (nlHsVar readListPrecDefault_RDR)
     -----------------------------------------------------------------------
 
-    loc       = getSrcSpan tycon
     data_cons = tyConDataCons tycon
     (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon data_cons
     
-    read_prec = mkVarBind loc readPrec_RDR
+    read_prec = mkHsVarBind loc readPrec_RDR
                              (nlHsApp (nlHsVar parens_RDR) read_cons)
 
     read_cons            = foldr1 mk_alt (read_nullary_cons ++ read_non_nullary_cons)
@@ -752,39 +889,56 @@ gen_Read_binds get_fixity tycon
     read_nullary_cons 
       = case nullary_cons of
            []    -> []
-           [con] -> [nlHsDo DoExpr [bindLex (ident_pat (data_con_str con))]
-                                   (result_expr con [])]
+           [con] -> [nlHsDo DoExpr [bindLex (match_con con)] (result_expr con [])]
             _     -> [nlHsApp (nlHsVar choose_RDR) 
-                           (nlList (map mk_pair nullary_cons))]
-    
-    mk_pair con = nlTuple [nlHsLit (mkHsString (data_con_str con)),
-                                  nlHsApp (nlHsVar returnM_RDR) (nlHsVar (getRdrName con))]
-                                  Boxed
-    
+                             (nlList (map mk_pair nullary_cons))]
+        -- NB For operators the parens around (:=:) are matched by the
+       -- enclosing "parens" call, so here we must match the naked
+       -- data_con_str con
+
+    match_con con | isSym con_str = symbol_pat con_str
+                  | otherwise     = ident_pat  con_str
+                  where
+                    con_str = data_con_str con
+       -- For nullary constructors we must match Ident s for normal constrs
+       -- and   Symbol s   for operators
+
+    mk_pair con = mkLHsTupleExpr [nlHsLit (mkHsString (data_con_str con)), 
+                                 result_expr con []]
+
     read_non_nullary_con data_con
-      = nlHsApps prec_RDR [nlHsIntLit prec, nlHsDo DoExpr stmts body]
+      | is_infix  = mk_parser infix_prec  infix_stmts  body
+      | is_record = mk_parser record_prec record_stmts body
+--             Using these two lines instead allows the derived
+--             read for infix and record bindings to read the prefix form
+--      | is_infix  = mk_alt prefix_parser (mk_parser infix_prec  infix_stmts  body)
+--      | is_record = mk_alt prefix_parser (mk_parser record_prec record_stmts body)
+      | otherwise = prefix_parser
       where
-               stmts | is_infix  = infix_stmts
-             | is_record = lbl_stmts
-             | otherwise = prefix_stmts
-     
        body = result_expr data_con as_needed
        con_str = data_con_str data_con
        
-               prefix_stmts            -- T a b c
-                 = [bindLex (ident_pat (wrapOpParens con_str))]
-                   ++ read_args
+       prefix_parser = mk_parser prefix_prec prefix_stmts body
+
+       read_prefix_con
+           | isSym con_str = [read_punc "(", bindLex (symbol_pat con_str), read_punc ")"]
+           | otherwise     = [bindLex (ident_pat con_str)]
         
+       read_infix_con
+           | isSym con_str = [bindLex (symbol_pat con_str)]
+           | otherwise     = [read_punc "`", bindLex (ident_pat con_str), read_punc "`"]
+
+               prefix_stmts            -- T a b c
+                 = read_prefix_con ++ read_args
+
                infix_stmts             -- a %% b, or  a `T` b 
                  = [read_a1]
-           ++  (if isSym con_str
-                then [bindLex (symbol_pat con_str)]
-                else [read_punc "`", bindLex (ident_pat con_str), read_punc "`"])
+           ++ read_infix_con
            ++ [read_a2]
      
-               lbl_stmts               -- T { f1 = a, f2 = b }
-                 = [bindLex (ident_pat (wrapOpParens con_str)),
-                    read_punc "{"]
+               record_stmts            -- T { f1 = a, f2 = b }
+                 = read_prefix_con 
+           ++ [read_punc "{"]
                    ++ concat (intersperse [read_punc ","] field_stmts)
                    ++ [read_punc "}"]
      
@@ -798,18 +952,20 @@ gen_Read_binds get_fixity tycon
                as_needed    = take con_arity as_RDRs
        read_args    = zipWithEqual "gen_Read_binds" read_arg as_needed (dataConOrigArgTys data_con)
                (read_a1:read_a2:_) = read_args
-               prec | is_infix  = getPrecedence get_fixity dc_nm
-            | is_record = appPrecedence + 1    -- Record construction binds even more tightly
-                                               -- than application; e.g. T2 T1 {x=2} means T2 (T1 {x=2})
-            | otherwise = appPrecedence
+       
+       prefix_prec = appPrecedence
+               infix_prec  = getPrecedence get_fixity dc_nm
+       record_prec = appPrecedence + 1 -- Record construction binds even more tightly
+                                       -- than application; e.g. T2 T1 {x=2} means T2 (T1 {x=2})
 
     ------------------------------------------------------------------------
     --         Helpers
     ------------------------------------------------------------------------
-    mk_alt e1 e2     = genOpApp e1 alt_RDR e2
-    bindLex pat             = noLoc (mkBindStmt pat (nlHsVar lexP_RDR))
-    con_app c as     = nlHsVarApps (getRdrName c) as
-    result_expr c as = nlHsApp (nlHsVar returnM_RDR) (con_app c as)
+    mk_alt e1 e2       = genOpApp e1 alt_RDR e2                                        -- e1 +++ e2
+    mk_parser p ss b   = nlHsApps prec_RDR [nlHsIntLit p, nlHsDo DoExpr ss b]  -- prec p (do { ss ; b })
+    bindLex pat               = noLoc (mkBindStmt pat (nlHsVar lexP_RDR))              -- pat <- lexP
+    con_app con as     = nlHsVarApps (getRdrName con) as                       -- con as
+    result_expr con as = nlHsApp (nlHsVar returnM_RDR) (con_app con as)                -- return (con as)
     
     punc_pat s   = nlConPat punc_RDR   [nlLitPat (mkHsString s)]  -- Punc 'c'
     ident_pat s  = nlConPat ident_RDR  [nlLitPat (mkHsString s)]  -- Ident "foo"
@@ -818,9 +974,8 @@ gen_Read_binds get_fixity tycon
     data_con_str con = occNameString (getOccName con)
     
     read_punc c = bindLex (punc_pat c)
-    read_arg a ty 
-       | isUnLiftedType ty = pprPanic "Error in deriving:" (text "Can't read unlifted types yet:" <+> ppr ty)
-       | otherwise = noLoc (mkBindStmt (nlVarPat a) (nlHsVarApps step_RDR [readPrec_RDR]))
+    read_arg a ty = ASSERT( not (isUnLiftedType ty) )
+                    noLoc (mkBindStmt (nlVarPat a) (nlHsVarApps step_RDR [readPrec_RDR]))
     
     read_field lbl a = read_lbl lbl ++
                       [read_punc "=",
@@ -844,7 +999,7 @@ gen_Read_binds get_fixity tycon
 
 %************************************************************************
 %*                                                                     *
-\subsubsection{Generating @Show@ instance declarations}
+       Show instances
 %*                                                                     *
 %************************************************************************
 
@@ -872,22 +1027,21 @@ Example
                    -- the most tightly-binding operator
 
 \begin{code}
-gen_Show_binds :: FixityEnv -> TyCon -> LHsBinds RdrName
+gen_Show_binds :: FixityEnv -> SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
 
-gen_Show_binds get_fixity tycon
-  = listToBag [shows_prec, show_list]
+gen_Show_binds get_fixity loc tycon
+  = (listToBag [shows_prec, show_list], [])
   where
-    tycon_loc = getSrcSpan tycon
     -----------------------------------------------------------------------
-    show_list = mkVarBind tycon_loc showList_RDR
+    show_list = mkHsVarBind loc showList_RDR
                  (nlHsApp (nlHsVar showList___RDR) (nlHsPar (nlHsApp (nlHsVar showsPrec_RDR) (nlHsIntLit 0))))
     -----------------------------------------------------------------------
-    shows_prec = mk_FunBind tycon_loc showsPrec_RDR (map pats_etc (tyConDataCons tycon))
+    shows_prec = mk_FunBind loc showsPrec_RDR (map pats_etc (tyConDataCons tycon))
       where
        pats_etc data_con
          | nullary_con =  -- skip the showParen junk...
             ASSERT(null bs_needed)
-            ([nlWildPat, con_pat], mk_showString_app con_str)
+            ([nlWildPat, con_pat], mk_showString_app op_con_str)
          | otherwise   =
             ([a_Pat, con_pat],
                  showParen_Expr (nlHsPar (genOpApp a_Expr ge_RDR (nlHsLit (HsInt con_prec_plus_one))))
@@ -957,9 +1111,10 @@ wrapOpBackquotes s | isSym s   = s
                   | otherwise = '`' : s ++ "`"
 
 isSym :: String -> Bool
-isSym ""     = False
-isSym (c:cs) = startsVarSym c || startsConSym c
+isSym ""      = False
+isSym (c : _) = startsVarSym c || startsConSym c
 
+mk_showString_app :: String -> LHsExpr RdrName
 mk_showString_app str = nlHsApp (nlHsVar showString_RDR) (nlHsLit (mkHsString str))
 \end{code}
 
@@ -977,7 +1132,10 @@ appPrecedence = fromIntegral maxPrecedence + 1
 getPrecedence :: FixityEnv -> Name -> Integer
 getPrecedence get_fixity nm 
    = case lookupFixity get_fixity nm of
-        Fixity x _ -> fromIntegral x
+        Fixity x _assoc -> fromIntegral x
+         -- NB: the Report says that associativity is not taken 
+         --     into account for either Read or Show; hence we 
+         --     ignore associativity here
 \end{code}
 
 
@@ -999,16 +1157,15 @@ we generate
 We are passed the Typeable2 class as well as T
 
 \begin{code}
-gen_Typeable_binds :: TyCon -> LHsBinds RdrName
-gen_Typeable_binds tycon
+gen_Typeable_binds :: SrcSpan -> TyCon -> LHsBinds RdrName
+gen_Typeable_binds loc tycon
   = unitBag $
-       mk_easy_FunBind tycon_loc 
+       mk_easy_FunBind loc 
                (mk_typeOf_RDR tycon)   -- Name of appropriate type0f function
                [nlWildPat] 
                (nlHsApps mkTypeRep_RDR [tycon_rep, nlList []])
   where
-    tycon_loc = getSrcSpan tycon
-    tycon_rep = nlHsVar mkTyConRep_RDR `nlHsApp` nlHsLit (mkHsString (showSDoc (ppr tycon)))
+    tycon_rep = nlHsVar mkTyConRep_RDR `nlHsApp` nlHsLit (mkHsString (showSDocOneLine (ppr tycon)))
 
 mk_typeOf_RDR :: TyCon -> RdrName
 -- Use the arity of the TyCon to make the right typeOfn function
@@ -1023,7 +1180,7 @@ mk_typeOf_RDR tycon = varQual_RDR tYPEABLE (mkFastString ("typeOf" ++ suffix))
 
 %************************************************************************
 %*                                                                     *
-\subsection{Data}
+       Data instances
 %*                                                                     *
 %************************************************************************
 
@@ -1052,24 +1209,27 @@ we generate
     
     dataTypeOf _ = $dT
 
+    dataCast1 = gcast1   -- If T :: * -> *
+    dataCast2 = gcast2   -- if T :: * -> * -> *
+
+    
 \begin{code}
-gen_Data_binds :: FixityEnv
+gen_Data_binds :: SrcSpan
               -> TyCon 
               -> (LHsBinds RdrName,    -- The method bindings
-                  LHsBinds RdrName)    -- Auxiliary bindings
-gen_Data_binds fix_env tycon
-  = (listToBag [gfoldl_bind, gunfold_bind, toCon_bind, dataTypeOf_bind],
+                  DerivAuxBinds)       -- Auxiliary bindings
+gen_Data_binds loc tycon
+  = (listToBag [gfoldl_bind, gunfold_bind, toCon_bind, dataTypeOf_bind]
+     `unionBags` gcast_binds,
                -- Auxiliary definitions: the data type and constructors
-     datatype_bind `consBag` listToBag (map mk_con_bind data_cons))
+     MkTyCon tycon : map MkDataCon data_cons)
   where
-    tycon_loc  = getSrcSpan tycon
-    tycon_name = tyConName tycon
     data_cons  = tyConDataCons tycon
     n_cons     = length data_cons
     one_constr = n_cons == 1
 
        ------------ gfoldl
-    gfoldl_bind = mk_FunBind tycon_loc gfoldl_RDR (map gfoldl_eqn data_cons)
+    gfoldl_bind = mk_FunBind loc gfoldl_RDR (map gfoldl_eqn data_cons)
     gfoldl_eqn con = ([nlVarPat k_RDR, nlVarPat z_RDR, nlConVarPat con_name as_needed], 
                       foldl mk_k_app (nlHsVar z_RDR `nlHsApp` nlHsVar con_name) as_needed)
                   where
@@ -1079,7 +1239,7 @@ gen_Data_binds fix_env tycon
                     mk_k_app e v = nlHsPar (nlHsOpApp e k_RDR (nlHsVar v))
 
        ------------ gunfold
-    gunfold_bind = mk_FunBind tycon_loc
+    gunfold_bind = mk_FunBind loc
                               gunfold_RDR
                               [([k_Pat, z_Pat, if one_constr then nlWildPat else c_Pat], 
                                gunfold_rhs)]
@@ -1102,60 +1262,385 @@ gen_Data_binds fix_env tycon
        tag = dataConTag dc
                          
        ------------ toConstr
-    toCon_bind = mk_FunBind tycon_loc toConstr_RDR (map to_con_eqn data_cons)
+    toCon_bind = mk_FunBind loc toConstr_RDR (map to_con_eqn data_cons)
     to_con_eqn dc = ([nlWildConPat dc], nlHsVar (mk_constr_name dc))
     
        ------------ dataTypeOf
     dataTypeOf_bind = mk_easy_FunBind
-                        tycon_loc
+                        loc
                         dataTypeOf_RDR
                        [nlWildPat]
-                        (nlHsVar data_type_name)
-
-       ------------  $dT
-
-    data_type_name = mkDerivedRdrName tycon_name mkDataTOcc
-    datatype_bind  = mkVarBind
-                       tycon_loc
-                       data_type_name
-                      (           nlHsVar mkDataType_RDR 
-                         `nlHsApp` nlHsLit (mkHsString (showSDoc (ppr tycon)))
-                         `nlHsApp` nlList constrs
-                       )
-    constrs = [nlHsVar (mk_constr_name con) | con <- data_cons]
-
-
-       ------------  $cT1 etc
-    mk_constr_name con = mkDerivedRdrName (dataConName con) mkDataCOcc
-    mk_con_bind dc = mkVarBind
-                       tycon_loc
-                       (mk_constr_name dc) 
-                      (nlHsApps mkConstr_RDR (constr_args dc))
-    constr_args dc =
-        [ -- nlHsIntLit (toInteger (dataConTag dc)),           -- Tag
-          nlHsVar data_type_name,                              -- DataType
-          nlHsLit (mkHsString (occNameString dc_occ)), -- String name
-           nlList  labels,                                     -- Field labels
-          nlHsVar fixity]                                      -- Fixity
-       where
-          labels   = map (nlHsLit . mkHsString . getOccString)
-                         (dataConFieldLabels dc)
-         dc_occ   = getOccName dc
-         is_infix = isDataSymOcc dc_occ
-         fixity | is_infix  = infix_RDR
-                | otherwise = prefix_RDR
-
-gfoldl_RDR     = varQual_RDR gENERICS FSLIT("gfoldl")
-gunfold_RDR    = varQual_RDR gENERICS FSLIT("gunfold")
-toConstr_RDR   = varQual_RDR gENERICS FSLIT("toConstr")
-dataTypeOf_RDR = varQual_RDR gENERICS FSLIT("dataTypeOf")
-mkConstr_RDR   = varQual_RDR gENERICS FSLIT("mkConstr")
-mkDataType_RDR = varQual_RDR gENERICS FSLIT("mkDataType")
-conIndex_RDR   = varQual_RDR gENERICS FSLIT("constrIndex")
-prefix_RDR     = dataQual_RDR gENERICS FSLIT("Prefix")
-infix_RDR      = dataQual_RDR gENERICS FSLIT("Infix")
+                        (nlHsVar (mk_data_type_name tycon))
+
+       ------------ gcast1/2
+    tycon_kind = tyConKind tycon
+    gcast_binds | tycon_kind `eqKind` kind1 = mk_gcast dataCast1_RDR gcast1_RDR
+               | tycon_kind `eqKind` kind2 = mk_gcast dataCast2_RDR gcast2_RDR
+               | otherwise           = emptyBag
+    mk_gcast dataCast_RDR gcast_RDR 
+      = unitBag (mk_easy_FunBind loc dataCast_RDR [nlVarPat f_RDR] 
+                                 (nlHsVar gcast_RDR `nlHsApp` nlHsVar f_RDR))
+
+
+kind1, kind2 :: Kind
+kind1 = liftedTypeKind `mkArrowKind` liftedTypeKind
+kind2 = liftedTypeKind `mkArrowKind` kind1
+
+gfoldl_RDR, gunfold_RDR, toConstr_RDR, dataTypeOf_RDR, mkConstr_RDR,
+    mkDataType_RDR, conIndex_RDR, prefix_RDR, infix_RDR,
+    dataCast1_RDR, dataCast2_RDR, gcast1_RDR, gcast2_RDR,
+    constr_RDR, dataType_RDR :: RdrName
+gfoldl_RDR     = varQual_RDR  gENERICS (fsLit "gfoldl")
+gunfold_RDR    = varQual_RDR  gENERICS (fsLit "gunfold")
+toConstr_RDR   = varQual_RDR  gENERICS (fsLit "toConstr")
+dataTypeOf_RDR = varQual_RDR  gENERICS (fsLit "dataTypeOf")
+dataCast1_RDR  = varQual_RDR  gENERICS (fsLit "dataCast1")
+dataCast2_RDR  = varQual_RDR  gENERICS (fsLit "dataCast2")
+gcast1_RDR     = varQual_RDR  tYPEABLE (fsLit "gcast1")
+gcast2_RDR     = varQual_RDR  tYPEABLE (fsLit "gcast2")
+mkConstr_RDR   = varQual_RDR  gENERICS (fsLit "mkConstr")
+constr_RDR     = tcQual_RDR   gENERICS (fsLit "Constr")
+mkDataType_RDR = varQual_RDR  gENERICS (fsLit "mkDataType")
+dataType_RDR   = tcQual_RDR   gENERICS (fsLit "DataType")
+conIndex_RDR   = varQual_RDR  gENERICS (fsLit "constrIndex")
+prefix_RDR     = dataQual_RDR gENERICS (fsLit "Prefix")
+infix_RDR      = dataQual_RDR gENERICS (fsLit "Infix")
 \end{code}
 
+
+
+%************************************************************************
+%*                                                                     *
+                       Functor instances
+
+ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html
+
+%*                                                                     *
+%************************************************************************
+
+For the data type:
+
+  data T a = T1 Int a | T2 (T a)
+
+We generate the instance:
+
+  instance Functor T where
+      fmap f (T1 b1 a) = T1 b1 (f a)
+      fmap f (T2 ta)   = T2 (fmap f ta)
+
+Notice that we don't simply apply 'fmap' to the constructor arguments.
+Rather 
+  - Do nothing to an argument whose type doesn't mention 'a'
+  - Apply 'f' to an argument of type 'a'
+  - Apply 'fmap f' to other arguments 
+That's why we have to recurse deeply into the constructor argument types,
+rather than just one level, as we typically do.
+
+What about types with more than one type parameter?  In general, we only 
+derive Functor for the last position:
+
+  data S a b = S1 [b] | S2 (a, T a b)
+  instance Functor (S a) where
+    fmap f (S1 bs)    = S1 (fmap f bs)
+    fmap f (S2 (p,q)) = S2 (a, fmap f q)
+
+However, we have special cases for
+        - tuples
+        - functions
+
+More formally, we write the derivation of fmap code over type variable
+'a for type 'b as ($fmap 'a 'b).  In this general notation the derived
+instance for T is:
+
+  instance Functor T where
+      fmap f (T1 x1 x2) = T1 ($(fmap 'a 'b1) x1) ($(fmap 'a 'a) x2)
+      fmap f (T2 x1)    = T2 ($(fmap 'a '(T a)) x1)
+
+  $(fmap 'a 'b)         x  =  x     -- when b does not contain a
+  $(fmap 'a 'a)         x  =  f x
+  $(fmap 'a '(b1,b2))   x  =  case x of (x1,x2) -> ($(fmap 'a 'b1) x1, $(fmap 'a 'b2) x2)
+  $(fmap 'a '(T b1 b2)) x  =  fmap $(fmap 'a 'b2) x   -- when a only occurs in the last parameter, b2
+  $(fmap 'a '(b -> c))  x  =  \b -> $(fmap 'a' 'c) (x ($(cofmap 'a 'b) b))
+
+For functions, the type parameter 'a can occur in a contravariant position,
+which means we need to derive a function like:
+
+  cofmap :: (a -> b) -> (f b -> f a)
+
+This is pretty much the same as $fmap, only without the $(cofmap 'a 'a) case:
+
+  $(cofmap 'a 'b)         x  =  x     -- when b does not contain a
+  $(cofmap 'a 'a)         x  =  error "type variable in contravariant position"
+  $(cofmap 'a '(b1,b2))   x  =  case x of (x1,x2) -> ($(cofmap 'a 'b1) x1, $(cofmap 'a 'b2) x2)
+  $(cofmap 'a '[b])       x  =  map $(cofmap 'a 'b) x
+  $(cofmap 'a '(T b1 b2)) x  =  fmap $(cofmap 'a 'b2) x   -- when a only occurs in the last parameter, b2
+  $(cofmap 'a '(b -> c))  x  =  \b -> $(cofmap 'a' 'c) (x ($(fmap 'a 'c) b))
+
+\begin{code}
+gen_Functor_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Functor_binds loc tycon
+  = (unitBag fmap_bind, [])
+  where
+    data_cons = tyConDataCons tycon
+    fmap_bind = L loc $ mkFunBind (L loc fmap_RDR) eqns
+                                  
+    fmap_eqn con = evalState (match_for_con [f_Pat] con parts) bs_RDRs
+      where 
+        parts = foldDataConArgs ft_fmap con
+
+       -- Catch-all eqn looks like   fmap _ _ = error "impossible"
+       -- It's needed if there no data cons at all 
+    eqns | null data_cons = [mkSimpleMatch [nlWildPat, nlWildPat] 
+                                           (error_Expr "Void fmap")]
+         | otherwise      = map fmap_eqn data_cons
+
+    ft_fmap :: FFoldType (LHsExpr RdrName -> State [RdrName] (LHsExpr RdrName))
+    -- Tricky higher order type; I can't say I fully understand this code :-(
+    ft_fmap = FT { ft_triv = \x -> return x                    -- fmap f x = x
+                , ft_var  = \x -> return (nlHsApp f_Expr x)   -- fmap f x = f x
+                , ft_fun = \g h x -> mkSimpleLam (\b -> h =<< (nlHsApp x `fmap` g b)) 
+                                                              -- fmap f x = \b -> h (x (g b))
+                , ft_tup = mkSimpleTupleCase match_for_con    -- fmap f x = case x of (a1,a2,..) -> (g1 a1,g2 a2,..)
+                , ft_ty_app = \_ g  x -> do gg <- mkSimpleLam g      -- fmap f x = fmap g x
+                                            return $ nlHsApps fmap_RDR [gg,x]        
+                , ft_forall = \_ g  x -> g x
+                , ft_bad_app = panic "in other argument"
+                , ft_co_var = panic "contravariant" }
+
+    match_for_con = mkSimpleConMatch $
+        \con_name xsM -> do xs <- sequence xsM
+                            return (nlHsApps con_name xs)  -- Con (g1 v1) (g2 v2) ..
+\end{code}
+
+Utility functions related to Functor deriving.
+
+Since several things use the same pattern of traversal, this is abstracted into functorLikeTraverse.
+This function works like a fold: it makes a value of type 'a' in a bottom up way.
+
+\begin{code}
+-- Generic traversal for Functor deriving
+data FFoldType a      -- Describes how to fold over a Type in a functor like way
+   = FT { ft_triv    :: a                  -- Does not contain variable
+       , ft_var     :: a                   -- The variable itself                             
+       , ft_co_var  :: a                   -- The variable itself, contravariantly            
+       , ft_fun     :: a -> a -> a         -- Function type
+       , ft_tup     :: Boxity -> [a] -> a  -- Tuple type 
+       , ft_ty_app  :: Type -> a -> a      -- Type app, variable only in last argument        
+       , ft_bad_app :: a                   -- Type app, variable other than in last argument  
+       , ft_forall  :: TcTyVar -> a -> a   -- Forall type                                     
+     }
+
+functorLikeTraverse :: TyVar        -- ^ Variable to look for
+                   -> FFoldType a   -- ^ How to fold
+                   -> Type          -- ^ Type to process
+                   -> a
+functorLikeTraverse var (FT { ft_triv = caseTrivial,     ft_var = caseVar
+                            , ft_co_var = caseCoVar,     ft_fun = caseFun
+                            , ft_tup = caseTuple,        ft_ty_app = caseTyApp 
+                           , ft_bad_app = caseWrongArg, ft_forall = caseForAll })
+                   ty
+  = fst (go False ty)
+  where -- go returns (result of type a, does type contain var)
+        go co ty | Just ty' <- coreView ty = go co ty'
+        go co (TyVarTy    v) | v == var = (if co then caseCoVar else caseVar,True)
+        go co (FunTy (PredTy _) b)      = go co b
+        go co (FunTy x y)    | xc || yc = (caseFun xr yr,True)
+            where (xr,xc) = go (not co) x
+                  (yr,yc) = go co       y
+        go co (AppTy    x y) | xc = (caseWrongArg,   True)
+                             | yc = (caseTyApp x yr, True)
+            where (_, xc) = go co x
+                  (yr,yc) = go co y
+        go co ty@(TyConApp con args)
+               | isTupleTyCon con = (caseTuple (tupleTyConBoxity con) xrs,True)
+               | null args        = (caseTrivial,False)         -- T
+               | or (init xcs)    = (caseWrongArg,True)         -- T (..var..)    ty
+               | last xcs         =                     -- T (..no var..) ty
+                                   (caseTyApp (fst (splitAppTy ty)) (last xrs),True)
+            where (xrs,xcs) = unzip (map (go co) args)
+        go co (ForAllTy v x) | v /= var && xc = (caseForAll v xr,True)
+            where (xr,xc) = go co x
+        go _ _ = (caseTrivial,False)
+
+-- Return all syntactic subterms of ty that contain var somewhere
+-- These are the things that should appear in instance constraints
+deepSubtypesContaining :: TyVar -> Type -> [TcType]
+deepSubtypesContaining tv
+  = functorLikeTraverse tv 
+       (FT { ft_triv = []
+           , ft_var = []
+           , ft_fun = (++), ft_tup = \_ xs -> concat xs
+           , ft_ty_app = (:)
+           , ft_bad_app = panic "in other argument"
+           , ft_co_var = panic "contravariant"
+           , ft_forall = \v xs -> filterOut ((v `elemVarSet`) . tyVarsOfType) xs })
+
+
+foldDataConArgs :: FFoldType a -> DataCon -> [a]
+-- Fold over the arguments of the datacon
+foldDataConArgs ft con
+  = map (functorLikeTraverse tv ft) (dataConOrigArgTys con)
+  where
+    tv = last (dataConUnivTyVars con) 
+                   -- Argument to derive for, 'a in the above description
+                   -- The validity checks have ensured that con is
+                   -- a vanilla data constructor
+
+-- Make a HsLam using a fresh variable from a State monad
+mkSimpleLam :: (LHsExpr id -> State [id] (LHsExpr id)) -> State [id] (LHsExpr id)
+-- (mkSimpleLam fn) returns (\x. fn(x))
+mkSimpleLam lam = do
+    (n:names) <- get
+    put names
+    body <- lam (nlHsVar n)
+    return (mkHsLam [nlVarPat n] body)
+
+mkSimpleLam2 :: (LHsExpr id -> LHsExpr id -> State [id] (LHsExpr id)) -> State [id] (LHsExpr id)
+mkSimpleLam2 lam = do
+    (n1:n2:names) <- get
+    put names
+    body <- lam (nlHsVar n1) (nlHsVar n2)
+    return (mkHsLam [nlVarPat n1,nlVarPat n2] body)
+
+-- "Con a1 a2 a3 -> fold [x1 a1, x2 a2, x3 a3]"
+mkSimpleConMatch :: Monad m => (RdrName -> [a] -> m (LHsExpr RdrName)) -> [LPat RdrName] -> DataCon -> [LHsExpr RdrName -> a] -> m (LMatch RdrName)
+mkSimpleConMatch fold extra_pats con insides = do
+    let con_name = getRdrName con
+    let vars_needed = takeList insides as_RDRs
+    let pat = nlConVarPat con_name vars_needed
+    rhs <- fold con_name (zipWith ($) insides (map nlHsVar vars_needed))
+    return $ mkMatch (extra_pats ++ [pat]) rhs emptyLocalBinds
+
+-- "case x of (a1,a2,a3) -> fold [x1 a1, x2 a2, x3 a3]"
+mkSimpleTupleCase :: Monad m => ([LPat RdrName] -> DataCon -> [LHsExpr RdrName -> a] -> m (LMatch RdrName))
+                  -> Boxity -> [LHsExpr RdrName -> a] -> LHsExpr RdrName -> m (LHsExpr RdrName)
+mkSimpleTupleCase match_for_con boxity insides x = do
+    let con = tupleCon boxity (length insides)
+    match <- match_for_con [] con insides
+    return $ nlHsCase x [match]
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+                       Foldable instances
+
+ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html
+
+%*                                                                     *
+%************************************************************************
+
+Deriving Foldable instances works the same way as Functor instances,
+only Foldable instances are not possible for function types at all.
+Here the derived instance for the type T above is:
+
+  instance Foldable T where
+      foldr f z (T1 x1 x2 x3) = $(foldr 'a 'b1) x1 ( $(foldr 'a 'a) x2 ( $(foldr 'a 'b2) x3 z ) )
+
+The cases are:
+
+  $(foldr 'a 'b)         x z  =  z     -- when b does not contain a
+  $(foldr 'a 'a)         x z  =  f x z
+  $(foldr 'a '(b1,b2))   x z  =  case x of (x1,x2) -> $(foldr 'a 'b1) x1 ( $(foldr 'a 'b2) x2 z )
+  $(foldr 'a '(T b1 b2)) x z  =  foldr $(foldr 'a 'b2) x z  -- when a only occurs in the last parameter, b2
+
+Note that the arguments to the real foldr function are the wrong way around,
+since (f :: a -> b -> b), while (foldr f :: b -> t a -> b).
+
+\begin{code}
+gen_Foldable_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Foldable_binds loc tycon
+  = (unitBag foldr_bind, [])
+  where
+    data_cons = tyConDataCons tycon
+
+    foldr_bind = L loc $ mkFunBind (L loc foldable_foldr_RDR) eqns
+    eqns | null data_cons = [mkSimpleMatch [nlWildPat, nlWildPat, nlWildPat] 
+                                           (error_Expr "Void foldr")]
+         | otherwise      = map foldr_eqn data_cons
+    foldr_eqn con = evalState (match_for_con z_Expr [f_Pat,z_Pat] con parts) bs_RDRs
+      where 
+        parts = foldDataConArgs ft_foldr con
+
+    ft_foldr :: FFoldType (LHsExpr RdrName -> LHsExpr RdrName -> State [RdrName] (LHsExpr RdrName))
+    ft_foldr = FT { ft_triv = \_ z -> return z                        -- foldr f z x = z
+                 , ft_var  = \x z -> return (nlHsApps f_RDR [x,z])   -- foldr f z x = f x z
+                 , ft_tup = \b gs x z -> mkSimpleTupleCase (match_for_con z) b gs x
+                 , ft_ty_app = \_ g  x z -> do gg <- mkSimpleLam2 g   -- foldr f z x = foldr (\xx zz -> g xx zz) z x
+                                               return $ nlHsApps foldable_foldr_RDR [gg,z,x]
+                 , ft_forall = \_ g  x z -> g x z
+                 , ft_co_var = panic "covariant"
+                 , ft_fun = panic "function"
+                 , ft_bad_app = panic "in other argument" }
+
+    match_for_con z = mkSimpleConMatch (\_con_name -> foldrM ($) z) -- g1 v1 (g2 v2 (.. z))
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+                       Traversable instances
+
+ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html
+%*                                                                     *
+%************************************************************************
+
+Again, Traversable is much like Functor and Foldable.
+
+The cases are:
+
+  $(traverse 'a 'b)         x  =  pure x     -- when b does not contain a
+  $(traverse 'a 'a)         x  =  f x
+  $(traverse 'a '(b1,b2))   x  =  case x of (x1,x2) -> (,) <$> $(traverse 'a 'b1) x1 <*> $(traverse 'a 'b2) x2
+  $(traverse 'a '(T b1 b2)) x  =  traverse $(traverse 'a 'b2) x  -- when a only occurs in the last parameter, b2
+
+Note that the generated code is not as efficient as it could be. For instance:
+
+  data T a = T Int a  deriving Traversable
+
+gives the function: traverse f (T x y) = T <$> pure x <*> f y
+instead of:         traverse f (T x y) = T x <$> f y
+
+\begin{code}
+gen_Traversable_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+gen_Traversable_binds loc tycon
+  = (unitBag traverse_bind, [])
+  where
+    data_cons = tyConDataCons tycon
+
+    traverse_bind = L loc $ mkFunBind (L loc traverse_RDR) eqns
+    eqns | null data_cons = [mkSimpleMatch [nlWildPat, nlWildPat] 
+                                           (error_Expr "Void traverse")]
+         | otherwise      = map traverse_eqn data_cons
+    traverse_eqn con = evalState (match_for_con [f_Pat] con parts) bs_RDRs
+      where 
+        parts = foldDataConArgs ft_trav con
+
+
+    ft_trav :: FFoldType (LHsExpr RdrName -> State [RdrName] (LHsExpr RdrName))
+    ft_trav = FT { ft_triv = \x -> return (nlHsApps pure_RDR [x])   -- traverse f x = pure x
+                , ft_var = \x -> return (nlHsApps f_RDR [x])       -- travese f x = f x
+                , ft_tup = mkSimpleTupleCase match_for_con         -- travese f x z = case x of (a1,a2,..) -> 
+                                                                   --                   (,,) <$> g1 a1 <*> g2 a2 <*> ..
+                , ft_ty_app = \_ g  x -> do gg <- mkSimpleLam g    -- travese f x = travese (\xx -> g xx) x
+                                            return $ nlHsApps traverse_RDR [gg,x]
+                , ft_forall = \_ g  x -> g x
+                , ft_co_var = panic "covariant"
+                , ft_fun = panic "function"
+                , ft_bad_app = panic "in other argument" }
+
+    match_for_con = mkSimpleConMatch $
+        \con_name xsM -> do xs <- sequence xsM
+                            return (mkApCon (nlHsVar con_name) xs)
+
+    -- ((Con <$> x1) <*> x2) <*> ..
+    mkApCon con []     = nlHsApps pure_RDR [con]
+    mkApCon con (x:xs) = foldl appAp (nlHsApps fmap_RDR [con,x]) xs
+       where appAp x y = nlHsApps ap_RDR [x,y]
+\end{code}
+
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{Generating extra binds (@con2tag@ and @tag2con@)}
@@ -1174,61 +1659,97 @@ The `tags' here start at zero, hence the @fIRST_TAG@ (currently one)
 fiddling around.
 
 \begin{code}
-data TagThingWanted
-  = GenCon2Tag | GenTag2Con | GenMaxTag
-
-gen_tag_n_con_monobind
-    :: ( RdrName,          -- (proto)Name for the thing in question
-       TyCon,              -- tycon in question
-       TagThingWanted)
-    -> LHsBind RdrName
-
-gen_tag_n_con_monobind (rdr_name, tycon, GenCon2Tag)
-  | lots_of_constructors
-  = mk_FunBind tycon_loc rdr_name [([], get_tag_rhs)]
-
-  | otherwise
-  = mk_FunBind tycon_loc rdr_name (map mk_stuff (tyConDataCons tycon))
-
+genAuxBind :: SrcSpan -> DerivAuxBind -> (LHsBind RdrName, LSig RdrName)
+genAuxBind loc (GenCon2Tag tycon)
+  = (mk_FunBind loc rdr_name eqns, 
+     L loc (TypeSig (L loc rdr_name) (L loc sig_ty)))
   where
-    tycon_loc = getSrcSpan tycon
+    rdr_name = con2tag_RDR tycon
 
-    tvs = map (mkRdrUnqual . getOccName) (tyConTyVars tycon)
-       -- We can't use gerRdrName because that makes an Exact  RdrName
-       -- and we can't put them in the LocalRdrEnv
+    sig_ty = HsCoreTy $ 
+             mkForAllTys (tyConTyVars tycon) $
+             mkParentType tycon `mkFunTy` intPrimTy
 
-       -- Give a signature to the bound variable, so 
-       -- that the case expression generated by getTag is
-       -- monomorphic.  In the push-enter model we get better code.
-    get_tag_rhs = noLoc $ ExprWithTySig 
-                       (nlHsLam (mkSimpleHsAlt (nlVarPat a_RDR) 
-                                             (nlHsApp (nlHsVar getTag_RDR) a_Expr)))
-                       (noLoc (mkExplicitHsForAllTy (map (noLoc.UserTyVar) tvs) (noLoc []) con2tag_ty))
+    lots_of_constructors = tyConFamilySize tycon > 8
+                        -- was: mAX_FAMILY_SIZE_FOR_VEC_RETURNS
+                        -- but we don't do vectored returns any more.
 
-    con2tag_ty = foldl nlHsAppTy (nlHsTyVar (getRdrName tycon)) 
-                      (map nlHsTyVar tvs)
-               `nlHsFunTy` 
-               nlHsTyVar (getRdrName intPrimTyCon)
+    eqns | lots_of_constructors = [get_tag_eqn]
+         | otherwise = map mk_eqn (tyConDataCons tycon)
 
-    lots_of_constructors = tyConFamilySize tycon > mAX_FAMILY_SIZE_FOR_VEC_RETURNS
+    get_tag_eqn = ([nlVarPat a_RDR], nlHsApp (nlHsVar getTag_RDR) a_Expr)
 
-    mk_stuff :: DataCon -> ([LPat RdrName], LHsExpr RdrName)
-    mk_stuff con = ([nlWildConPat con], 
-                   nlHsLit (HsIntPrim (toInteger ((dataConTag con) - fIRST_TAG))))
+    mk_eqn :: DataCon -> ([LPat RdrName], LHsExpr RdrName)
+    mk_eqn con = ([nlWildConPat con], 
+                 nlHsLit (HsIntPrim (toInteger ((dataConTag con) - fIRST_TAG))))
 
-gen_tag_n_con_monobind (rdr_name, tycon, GenTag2Con)
-  = mk_FunBind (getSrcSpan tycon) rdr_name 
+genAuxBind loc (GenTag2Con tycon)
+  = ASSERT( null (tyConTyVars tycon) )
+    (mk_FunBind loc rdr_name 
        [([nlConVarPat intDataCon_RDR [a_RDR]], 
-          noLoc (ExprWithTySig (nlHsApp (nlHsVar tagToEnum_RDR) a_Expr) 
-                        (nlHsTyVar (getRdrName tycon))))]
+          nlHsApp (nlHsVar tagToEnum_RDR) a_Expr)],
+     L loc (TypeSig (L loc rdr_name) (L loc sig_ty)))
+  where
+    sig_ty = HsCoreTy $ intTy `mkFunTy` mkParentType tycon
+
+    rdr_name = tag2con_RDR tycon
 
-gen_tag_n_con_monobind (rdr_name, tycon, GenMaxTag)
-  = mkVarBind (getSrcSpan tycon) rdr_name 
-                 (nlHsApp (nlHsVar intDataCon_RDR) (nlHsLit (HsIntPrim max_tag)))
+genAuxBind loc (GenMaxTag tycon)
+  = (mkHsVarBind loc rdr_name rhs,
+     L loc (TypeSig (L loc rdr_name) (L loc sig_ty)))
   where
+    rdr_name = maxtag_RDR tycon
+    sig_ty = HsCoreTy intTy
+    rhs = nlHsApp (nlHsVar intDataCon_RDR) (nlHsLit (HsIntPrim max_tag))
     max_tag =  case (tyConDataCons tycon) of
                 data_cons -> toInteger ((length data_cons) - fIRST_TAG)
 
+genAuxBind loc (MkTyCon tycon) --  $dT
+  = (mkHsVarBind loc rdr_name rhs,
+     L loc (TypeSig (L loc rdr_name) sig_ty))
+  where
+    rdr_name = mk_data_type_name tycon
+    sig_ty   = nlHsTyVar dataType_RDR
+    constrs  = [nlHsVar (mk_constr_name con) | con <- tyConDataCons tycon]
+    rhs = nlHsVar mkDataType_RDR 
+          `nlHsApp` nlHsLit (mkHsString (showSDocOneLine (ppr tycon)))
+          `nlHsApp` nlList constrs
+
+genAuxBind loc (MkDataCon dc)  --  $cT1 etc
+  = (mkHsVarBind loc rdr_name rhs,
+     L loc (TypeSig (L loc rdr_name) sig_ty))
+  where
+    rdr_name = mk_constr_name dc
+    sig_ty   = nlHsTyVar constr_RDR
+    rhs      = nlHsApps mkConstr_RDR constr_args
+
+    constr_args 
+       = [ -- nlHsIntLit (toInteger (dataConTag dc)),    -- Tag
+          nlHsVar (mk_data_type_name (dataConTyCon dc)), -- DataType
+          nlHsLit (mkHsString (occNameString dc_occ)),   -- String name
+           nlList  labels,                               -- Field labels
+          nlHsVar fixity]                                -- Fixity
+
+    labels   = map (nlHsLit . mkHsString . getOccString)
+                   (dataConFieldLabels dc)
+    dc_occ   = getOccName dc
+    is_infix = isDataSymOcc dc_occ
+    fixity | is_infix  = infix_RDR
+          | otherwise = prefix_RDR
+
+mk_data_type_name :: TyCon -> RdrName  -- "$tT"
+mk_data_type_name tycon = mkAuxBinderName (tyConName tycon) mkDataTOcc
+
+mk_constr_name :: DataCon -> RdrName   -- "$cC"
+mk_constr_name con = mkAuxBinderName (dataConName con) mkDataCOcc
+
+mkParentType :: TyCon -> Type
+-- Turn the representation tycon of a family into
+-- a use of its family constructor
+mkParentType tc
+  = case tyConFamInst_maybe tc of
+       Nothing  -> mkTyConApp tc (mkTyVarTys (tyConTyVars tc))
+       Just (fam_tc,tys) -> mkTyConApp fam_tc tys
 \end{code}
 
 %************************************************************************
@@ -1241,40 +1762,6 @@ gen_tag_n_con_monobind (rdr_name, tycon, GenMaxTag)
 ToDo: Better SrcLocs.
 
 \begin{code}
-compare_gen_Case ::
-         LHsExpr RdrName       -- What to do for equality
-         -> LHsExpr RdrName -> LHsExpr RdrName
-         -> LHsExpr RdrName
-careful_compare_Case :: -- checks for primitive types...
-         TyCon                 -- The tycon we are deriving for
-         -> Type
-         -> LHsExpr RdrName    -- What to do for equality
-         -> LHsExpr RdrName -> LHsExpr RdrName
-         -> LHsExpr RdrName
-
-cmp_eq_Expr a b = nlHsApp (nlHsApp (nlHsVar cmp_eq_RDR) a) b
-       -- Was: compare_gen_Case cmp_eq_RDR
-
-compare_gen_Case (L _ (HsVar eq_tag)) a b | eq_tag == eqTag_RDR
-  = nlHsApp (nlHsApp (nlHsVar compare_RDR) a) b        -- Simple case 
-compare_gen_Case eq a b                                -- General case
-  = nlHsCase (nlHsPar (nlHsApp (nlHsApp (nlHsVar compare_RDR) a) b)) {-of-}
-      [mkSimpleHsAlt (nlNullaryConPat ltTag_RDR) ltTag_Expr,
-       mkSimpleHsAlt (nlNullaryConPat eqTag_RDR) eq,
-       mkSimpleHsAlt (nlNullaryConPat gtTag_RDR) gtTag_Expr]
-
-careful_compare_Case tycon ty eq a b
-  | not (isUnLiftedType ty)
-  = compare_gen_Case eq a b
-  | otherwise      -- We have to do something special for primitive things...
-  = nlHsIf (genOpApp a relevant_eq_op b)
-        eq
-        (nlHsIf (genOpApp a relevant_lt_op b) ltTag_Expr gtTag_Expr)
-  where
-    relevant_eq_op = primOpRdrName (assoc_ty_id "Ord" tycon eq_op_tbl ty)
-    relevant_lt_op = primOpRdrName (assoc_ty_id "Ord" tycon lt_op_tbl ty)
-
-
 box_if_necy :: String          -- The class involved
            -> TyCon            -- The tycon involved
            -> LHsExpr RdrName  -- The argument
@@ -1286,46 +1773,43 @@ box_if_necy cls_str tycon arg arg_ty
   where
     box_con = assoc_ty_id cls_str tycon box_con_tbl arg_ty
 
+---------------------
+primOrdOps :: String   -- The class involved
+          -> TyCon     -- The tycon involved
+          -> Type      -- The type
+          -> (PrimOp, PrimOp, PrimOp, PrimOp, PrimOp)  -- (lt,le,eq,ge,gt)
+primOrdOps str tycon ty = assoc_ty_id str tycon ord_op_tbl ty
+
+ord_op_tbl :: [(Type, (PrimOp, PrimOp, PrimOp, PrimOp, PrimOp))]
+ord_op_tbl
+ =  [(charPrimTy,      (CharLtOp,   CharLeOp,   CharEqOp,   CharGeOp,   CharGtOp))
+    ,(intPrimTy,       (IntLtOp,    IntLeOp,    IntEqOp,    IntGeOp,    IntGtOp))
+    ,(wordPrimTy,      (WordLtOp,   WordLeOp,   WordEqOp,   WordGeOp,   WordGtOp))
+    ,(addrPrimTy,      (AddrLtOp,   AddrLeOp,   AddrEqOp,   AddrGeOp,   AddrGtOp))
+    ,(floatPrimTy,     (FloatLtOp,  FloatLeOp,  FloatEqOp,  FloatGeOp,  FloatGtOp))
+    ,(doublePrimTy,    (DoubleLtOp, DoubleLeOp, DoubleEqOp, DoubleGeOp, DoubleGtOp)) ]
+
+box_con_tbl :: [(Type, RdrName)]
+box_con_tbl =
+    [(charPrimTy,      getRdrName charDataCon)
+    ,(intPrimTy,       getRdrName intDataCon)
+    ,(wordPrimTy,      wordDataCon_RDR)
+    ,(floatPrimTy,     getRdrName floatDataCon)
+    ,(doublePrimTy,    getRdrName doubleDataCon)
+    ]
+
 assoc_ty_id :: String          -- The class involved
            -> TyCon            -- The tycon involved
            -> [(Type,a)]       -- The table
            -> Type             -- The type
            -> a                -- The result of the lookup
-assoc_ty_id cls_str tycon tbl ty 
+assoc_ty_id cls_str _ tbl ty 
   | null res = pprPanic "Error in deriving:" (text "Can't derive" <+> text cls_str <+> 
                                              text "for primitive type" <+> ppr ty)
   | otherwise = head res
   where
     res = [id | (ty',id) <- tbl, ty `tcEqType` ty']
 
-eq_op_tbl :: [(Type, PrimOp)]
-eq_op_tbl =
-    [(charPrimTy,      CharEqOp)
-    ,(intPrimTy,       IntEqOp)
-    ,(wordPrimTy,      WordEqOp)
-    ,(addrPrimTy,      AddrEqOp)
-    ,(floatPrimTy,     FloatEqOp)
-    ,(doublePrimTy,    DoubleEqOp)
-    ]
-
-lt_op_tbl :: [(Type, PrimOp)]
-lt_op_tbl =
-    [(charPrimTy,      CharLtOp)
-    ,(intPrimTy,       IntLtOp)
-    ,(wordPrimTy,      WordLtOp)
-    ,(addrPrimTy,      AddrLtOp)
-    ,(floatPrimTy,     FloatLtOp)
-    ,(doublePrimTy,    DoubleLtOp)
-    ]
-
-box_con_tbl =
-    [(charPrimTy,      getRdrName charDataCon)
-    ,(intPrimTy,       getRdrName intDataCon)
-    ,(wordPrimTy,      wordDataCon_RDR)
-    ,(floatPrimTy,     getRdrName floatDataCon)
-    ,(doublePrimTy,    getRdrName doubleDataCon)
-    ]
-
 -----------------------------------------------------------------------
 
 and_Expr :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName
@@ -1336,28 +1820,18 @@ and_Expr a b = genOpApp a and_RDR    b
 eq_Expr :: TyCon -> Type -> LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName
 eq_Expr tycon ty a b = genOpApp a eq_op b
  where
-   eq_op
-    | not (isUnLiftedType ty) = eq_RDR
-    | otherwise               = primOpRdrName (assoc_ty_id "Eq" tycon eq_op_tbl ty)
-         -- we have to do something special for primitive things...
+   eq_op | not (isUnLiftedType ty) = eq_RDR
+         | otherwise               = primOpRdrName prim_eq
+   (_, _, prim_eq, _, _) = primOrdOps "Eq" tycon ty
 \end{code}
 
 \begin{code}
 untag_Expr :: TyCon -> [( RdrName,  RdrName)] -> LHsExpr RdrName -> LHsExpr RdrName
-untag_Expr tycon [] expr = expr
+untag_Expr _ [] expr = expr
 untag_Expr tycon ((untag_this, put_tag_here) : more) expr
   = nlHsCase (nlHsPar (nlHsVarApps (con2tag_RDR tycon) [untag_this])) {-of-}
       [mkSimpleHsAlt (nlVarPat put_tag_here) (untag_Expr tycon more expr)]
 
-cmp_tags_Expr ::  RdrName              -- Comparison op
-            ->  RdrName ->  RdrName    -- Things to compare
-            -> LHsExpr RdrName                 -- What to return if true
-            -> LHsExpr RdrName         -- What to return if false
-            -> LHsExpr RdrName
-
-cmp_tags_Expr op a b true_case false_case
-  = nlHsIf (genOpApp (nlHsVar a) op (nlHsVar b)) true_case false_case
-
 enum_from_to_Expr
        :: LHsExpr RdrName -> LHsExpr RdrName
        -> LHsExpr RdrName
@@ -1376,21 +1850,25 @@ showParen_Expr e1 e2 = nlHsApp (nlHsApp (nlHsVar showParen_RDR) e1) e2
 
 nested_compose_Expr :: [LHsExpr RdrName] -> LHsExpr RdrName
 
+nested_compose_Expr []  = panic "nested_compose_expr"  -- Arg is always non-empty
 nested_compose_Expr [e] = parenify e
 nested_compose_Expr (e:es)
   = nlHsApp (nlHsApp (nlHsVar compose_RDR) (parenify e)) (nested_compose_Expr es)
 
 -- impossible_Expr is used in case RHSs that should never happen.
 -- We generate these to keep the desugarer from complaining that they *might* happen!
-impossible_Expr = nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString "Urk! in TcGenDeriv"))
+error_Expr :: String -> LHsExpr RdrName
+error_Expr string = nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString string))
 
 -- illegal_Expr is used when signalling error conditions in the RHS of a derived
 -- method. It is currently only used by Enum.{succ,pred}
+illegal_Expr :: String -> String -> String -> LHsExpr RdrName
 illegal_Expr meth tp msg = 
    nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString (meth ++ '{':tp ++ "}: " ++ msg)))
 
 -- illegal_toEnum_tag is an extended version of illegal_Expr, which also allows you
 -- to include the value of a_RDR in the error string.
+illegal_toEnum_tag :: String -> RdrName -> LHsExpr RdrName
 illegal_toEnum_tag tp maxtag =
    nlHsApp (nlHsVar error_RDR) 
            (nlHsApp (nlHsApp (nlHsVar append_RDR)
@@ -1408,78 +1886,91 @@ illegal_toEnum_tag tp maxtag =
                                        (nlHsVar maxtag))
                                        (nlHsLit (mkHsString ")"))))))
 
+parenify :: LHsExpr RdrName -> LHsExpr RdrName
 parenify e@(L _ (HsVar _)) = e
 parenify e                = mkHsPar e
 
 -- genOpApp wraps brackets round the operator application, so that the
 -- renamer won't subsequently try to re-associate it. 
+genOpApp :: LHsExpr RdrName -> RdrName -> LHsExpr RdrName -> LHsExpr RdrName
 genOpApp e1 op e2 = nlHsPar (nlHsOpApp e1 op e2)
 \end{code}
 
 \begin{code}
-getSrcSpan = srcLocSpan . getSrcLoc
-\end{code}
-
-\begin{code}
-a_RDR          = mkVarUnqual FSLIT("a")
-b_RDR          = mkVarUnqual FSLIT("b")
-c_RDR          = mkVarUnqual FSLIT("c")
-d_RDR          = mkVarUnqual FSLIT("d")
-k_RDR          = mkVarUnqual FSLIT("k")
-z_RDR          = mkVarUnqual FSLIT("z")
-ah_RDR         = mkVarUnqual FSLIT("a#")
-bh_RDR         = mkVarUnqual FSLIT("b#")
-ch_RDR         = mkVarUnqual FSLIT("c#")
-dh_RDR         = mkVarUnqual FSLIT("d#")
-cmp_eq_RDR     = mkVarUnqual FSLIT("cmp_eq")
-
+a_RDR, b_RDR, c_RDR, d_RDR, f_RDR, k_RDR, z_RDR, ah_RDR, bh_RDR, ch_RDR, dh_RDR
+    :: RdrName
+a_RDR          = mkVarUnqual (fsLit "a")
+b_RDR          = mkVarUnqual (fsLit "b")
+c_RDR          = mkVarUnqual (fsLit "c")
+d_RDR          = mkVarUnqual (fsLit "d")
+f_RDR          = mkVarUnqual (fsLit "f")
+k_RDR          = mkVarUnqual (fsLit "k")
+z_RDR          = mkVarUnqual (fsLit "z")
+ah_RDR         = mkVarUnqual (fsLit "a#")
+bh_RDR         = mkVarUnqual (fsLit "b#")
+ch_RDR         = mkVarUnqual (fsLit "c#")
+dh_RDR         = mkVarUnqual (fsLit "d#")
+
+as_RDRs, bs_RDRs, cs_RDRs :: [RdrName]
 as_RDRs                = [ mkVarUnqual (mkFastString ("a"++show i)) | i <- [(1::Int) .. ] ]
 bs_RDRs                = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) .. ] ]
 cs_RDRs                = [ mkVarUnqual (mkFastString ("c"++show i)) | i <- [(1::Int) .. ] ]
 
+a_Expr, c_Expr, f_Expr, z_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr,
+    false_Expr, true_Expr :: LHsExpr RdrName
 a_Expr         = nlHsVar a_RDR
-b_Expr         = nlHsVar b_RDR
+-- b_Expr      = nlHsVar b_RDR
 c_Expr         = nlHsVar c_RDR
+f_Expr         = nlHsVar f_RDR
+z_Expr         = nlHsVar z_RDR
 ltTag_Expr     = nlHsVar ltTag_RDR
 eqTag_Expr     = nlHsVar eqTag_RDR
 gtTag_Expr     = nlHsVar gtTag_RDR
 false_Expr     = nlHsVar false_RDR
 true_Expr      = nlHsVar true_RDR
 
+a_Pat, b_Pat, c_Pat, d_Pat, f_Pat, k_Pat, z_Pat :: LPat RdrName
 a_Pat          = nlVarPat a_RDR
 b_Pat          = nlVarPat b_RDR
 c_Pat          = nlVarPat c_RDR
 d_Pat          = nlVarPat d_RDR
+f_Pat          = nlVarPat f_RDR
 k_Pat          = nlVarPat k_RDR
 z_Pat          = nlVarPat z_RDR
 
-con2tag_RDR, tag2con_RDR, maxtag_RDR :: TyCon ->  RdrName
+con2tag_RDR, tag2con_RDR, maxtag_RDR :: TyCon -> RdrName
 -- Generates Orig s RdrName, for the binding positions
-con2tag_RDR tycon = mk_tc_deriv_name tycon "con2tag_"
-tag2con_RDR tycon = mk_tc_deriv_name tycon "tag2con_"
-maxtag_RDR  tycon = mk_tc_deriv_name tycon "maxtag_"
-
-mk_tc_deriv_name tycon str 
-  = mkDerivedRdrName tc_name mk_occ
-  where
-    tc_name = tyConName tycon
-    mk_occ tc_occ = mkVarOccFS (mkFastString new_str)
-                 where
-                   new_str = str ++ occNameString tc_occ ++ "#"
+con2tag_RDR tycon = mk_tc_deriv_name tycon mkCon2TagOcc
+tag2con_RDR tycon = mk_tc_deriv_name tycon mkTag2ConOcc
+maxtag_RDR  tycon = mk_tc_deriv_name tycon mkMaxTagOcc
+
+mk_tc_deriv_name :: TyCon -> (OccName -> OccName) -> RdrName
+mk_tc_deriv_name tycon occ_fun = mkAuxBinderName (tyConName tycon) occ_fun
+
+mkAuxBinderName :: Name -> (OccName -> OccName) -> RdrName
+mkAuxBinderName parent occ_fun = mkRdrUnqual (occ_fun (nameOccName parent))
+-- Was: mkDerivedRdrName name occ_fun, which made an original name
+-- But:  (a) that does not work well for standalone-deriving
+--      (b) an unqualified name is just fine, provided it can't clash with user code
 \end{code}
 
 s RdrName for PrimOps.  Can't be done in PrelNames, because PrimOp imports
 PrelNames, so PrelNames can't import PrimOp.
 
 \begin{code}
+primOpRdrName :: PrimOp -> RdrName
 primOpRdrName op = getRdrName (primOpId op)
 
+minusInt_RDR, eqInt_RDR, ltInt_RDR, geInt_RDR, gtInt_RDR, leInt_RDR,
+    tagToEnum_RDR :: RdrName
 minusInt_RDR  = primOpRdrName IntSubOp
 eqInt_RDR     = primOpRdrName IntEqOp
 ltInt_RDR     = primOpRdrName IntLtOp
 geInt_RDR     = primOpRdrName IntGeOp
+gtInt_RDR     = primOpRdrName IntGtOp
 leInt_RDR     = primOpRdrName IntLeOp
 tagToEnum_RDR = primOpRdrName TagToEnumOp
 
+error_RDR :: RdrName
 error_RDR = getRdrName eRROR_ID
 \end{code}