This is where we do all the grimy bindings' generation.
\begin{code}
-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
--- http://hackage.haskell.org/trac/ghc/wiki/CodingStyle#Warnings
--- for details
-
module TcGenDeriv (
+ DerivAuxBinds, isDupAux,
+
gen_Bounded_binds,
gen_Enum_binds,
gen_Eq_binds,
gen_Show_binds,
gen_Data_binds,
gen_Typeable_binds,
- gen_tag_n_con_monobind,
-
- con2tag_RDR, tag2con_RDR, maxtag_RDR,
-
- TagThingWanted(..)
+ genAuxBind
) where
#include "HsVersions.h"
import Data.List ( partition, intersperse )
\end{code}
-%************************************************************************
-%* *
-\subsection{Generating code, by derivable class}
-%* *
-%************************************************************************
+\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
+
+ -- 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}
+
%************************************************************************
%* *
-\subsubsection{Generating @Eq@ instance declarations}
+ Eq instances
%* *
%************************************************************************
\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
%************************************************************************
%* *
-\subsubsection{Generating @Ord@ instance declarations}
+ Ord instances
%* *
%************************************************************************
JJQC-30-Nov-1997
\begin{code}
-gen_Ord_binds :: TyCon -> LHsBinds RdrName
+gen_Ord_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
-gen_Ord_binds tycon
- = unitBag compare -- `AndMonoBinds` compare
- -- The default declaration in PrelBase handles this
+gen_Ord_binds loc tycon
+ | Just (con, prim_tc) <- primWrapperType_maybe tycon
+ = gen_PrimOrd_binds con prim_tc
+
+ | otherwise
+ = (unitBag compare, aux_binds)
+ -- `AndMonoBinds` compare
+ -- The default declaration in PrelBase handles this
where
- tycon_loc = getSrcSpan tycon
- --------------------------------------------------------------------
+ aux_binds | single_con_type = []
+ | otherwise = [GenCon2Tag tycon]
- compare = L tycon_loc (mkFunBind (L tycon_loc compare_RDR) compare_matches)
+ compare = L loc (mkFunBind (L 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) [])
| isNewTyCon tycon = ([], tyConDataCons tycon)
| otherwise = partition isNullarySrcDataCon tycon_data_cons
- cmp_eq = mk_FunBind tycon_loc cmp_eq_RDR cmp_eq_match
+ cmp_eq = mk_FunBind 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,
else
[([nlWildPat, nlWildPat], default_rhs)])
- 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
+ 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
+ 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
+ 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] [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
+ 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)
- nested_compare_expr _ _ _ = panic "nested_compare_expr" -- Args always equal length
+ nested_compare_expr _ _ _ = panic "nested_compare_expr" -- Args always equal length
+\end{code}
+
+Note [Comparision of primitive types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The general plan does not work well for data types like
+ data T = MkT Int# deriving( Ord )
+The general plan defines the 'compare' method, gets (<) etc from it. But
+that means we get silly code like:
+ instance Ord T where
+ (>) (I# x) (I# y) = case <# x y of
+ True -> False
+ False -> case ==# x y of
+ True -> False
+ False -> True
+We would prefer to use the (>#) primop. See also Trac #2130
+
- 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
+\begin{code}
+gen_PrimOrd_binds :: DataCon -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+-- See Note [Comparison of primitive types]
+gen_PrimOrd_binds data_con prim_tc
+ = (listToBag [mk_op lt_RDR lt_op, mk_op le_RDR le_op,
+ mk_op ge_RDR ge_op, mk_op gt_RDR gt_op], [])
+ where
+ mk_op op_RDR op = mk_FunBind (getSrcSpan data_con) op_RDR
+ [([apat, bpat], genOpApp a_Expr (primOpRdrName op) b_Expr)]
+ con_RDR = getRdrName data_con
+ apat = nlConVarPat con_RDR [a_RDR]
+ bpat = nlConVarPat con_RDR [b_RDR]
+
+ (lt_op, le_op, ge_op, gt_op)
+ | prim_tc == charPrimTyCon = (CharLtOp, CharLeOp, CharGeOp, CharGtOp)
+ | prim_tc == intPrimTyCon = (IntLtOp, IntLeOp, IntGeOp, IntGtOp)
+ | prim_tc == wordPrimTyCon = (WordLtOp, WordLeOp, WordGeOp, WordGtOp)
+ | prim_tc == addrPrimTyCon = (AddrLtOp, AddrLeOp, AddrGeOp, AddrGtOp)
+ | prim_tc == floatPrimTyCon = (FloatLtOp, FloatLeOp, FloatGeOp, FloatGtOp)
+ | prim_tc == doublePrimTyCon = (DoubleLtOp, DoubleLeOp, DoubleGeOp, DoubleGtOp)
+ | otherwise = pprPanic "Unexpected primitive tycon" (ppr prim_tc)
+
+
+primWrapperType_maybe :: TyCon -> Maybe (DataCon, TyCon)
+-- True of data types that are wrappers around prmitive types
+-- data T = MkT Word#
+-- For these we want to generate all the (<), (<=) etc operations individually
+primWrapperType_maybe tc
+ | [con] <- tyConDataCons tc
+ , [ty] <- dataConOrigArgTys con
+ , Just (prim_tc, []) <- tcSplitTyConApp_maybe ty
+ , isPrimTyCon prim_tc
+ = Just (con, prim_tc)
+ | otherwise
+ = Nothing
\end{code}
%************************************************************************
%* *
-\subsubsection{Generating @Enum@ instance declarations}
+ Enum instances
%* *
%************************************************************************
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]])
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]])
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)]])
(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),
(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
))
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 = mkVarBind loc minBound_RDR (nlHsVar data_con_1_RDR)
+ max_bound_enum = mkVarBind loc maxBound_RDR (nlHsVar data_con_N_RDR)
data_con_1 = head data_cons
data_con_N = last data_cons
----- single-constructor-flavored: -------------
arity = dataConSourceArity data_con_1
- min_bound_1con = mkVarBind tycon_loc minBound_RDR $
+ min_bound_1con = mkVarBind loc minBound_RDR $
nlHsVarApps data_con_1_RDR (nOfThem arity minBound_RDR)
- max_bound_1con = mkVarBind tycon_loc maxBound_RDR $
+ max_bound_1con = mkVarBind loc maxBound_RDR $
nlHsVarApps data_con_1_RDR (nOfThem arity maxBound_RDR)
\end{code}
%************************************************************************
%* *
-\subsubsection{Generating @Ix@ instance declarations}
+ Ix instances
%* *
%************************************************************************
(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]) $
(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] (
)
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)] (
= 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
--------------------------------------------------------------
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
----------------
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
------------------
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)
%************************************************************************
%* *
-\subsubsection{Generating @Read@ instance declarations}
+ Read instances
%* *
%************************************************************************
\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 readListPrec_RDR (nlHsVar readListPrecDefault_RDR)
-----------------------------------------------------------------------
- loc = getSrcSpan tycon
data_cons = tyConDataCons tycon
(nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon data_cons
con_str = data_con_str data_con
prefix_parser = mk_parser prefix_prec prefix_stmts body
- prefix_stmts -- T a b c
- = (if not (isSym con_str) then
- [bindLex (ident_pat con_str)]
- else [read_punc "(", bindLex (symbol_pat con_str), read_punc ")"])
- ++ read_args
+
+ 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]
record_stmts -- T { f1 = a, f2 = b }
- = [bindLex (ident_pat (wrapOpParens con_str)),
- read_punc "{"]
+ = read_prefix_con
+ ++ [read_punc "{"]
++ concat (intersperse [read_punc ","] field_stmts)
++ [read_punc "}"]
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 "=",
%************************************************************************
%* *
-\subsubsection{Generating @Show@ instance declarations}
+ Show instances
%* *
%************************************************************************
-- 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 = mkVarBind 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...
| 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}
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}
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)))
mk_typeOf_RDR :: TyCon -> RdrName
%************************************************************************
%* *
-\subsection{Data}
+ Data instances
%* *
%************************************************************************
dataTypeOf _ = $dT
\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
+ DerivAuxBinds) -- Auxiliary bindings
+gen_Data_binds loc tycon
= (listToBag [gfoldl_bind, gunfold_bind, toCon_bind, dataTypeOf_bind],
-- 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
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)]
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))
+
+
+gfoldl_RDR, gunfold_RDR, toConstr_RDR, dataTypeOf_RDR, mkConstr_RDR,
+ mkDataType_RDR, conIndex_RDR, prefix_RDR, infix_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")
+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")
\end{code}
%************************************************************************
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)
+genAuxBind :: SrcSpan -> DerivAuxBind -> LHsBind RdrName
+genAuxBind loc (GenCon2Tag tycon)
| lots_of_constructors
- = mk_FunBind tycon_loc rdr_name [([], get_tag_rhs)]
+ = mk_FunBind loc rdr_name [([], get_tag_rhs)]
| otherwise
- = mk_FunBind tycon_loc rdr_name (map mk_stuff (tyConDataCons tycon))
+ = mk_FunBind loc rdr_name (map mk_stuff (tyConDataCons tycon))
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
-- 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
+ get_tag_rhs = L loc $ ExprWithTySig
(nlHsLam (mkSimpleHsAlt (nlVarPat a_RDR)
(nlHsApp (nlHsVar getTag_RDR) a_Expr)))
(noLoc (mkExplicitHsForAllTy (map (noLoc.UserTyVar) tvs) (noLoc []) con2tag_ty))
mk_stuff 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)
+ = mk_FunBind loc rdr_name
[([nlConVarPat intDataCon_RDR [a_RDR]],
noLoc (ExprWithTySig (nlHsApp (nlHsVar tagToEnum_RDR) a_Expr)
(nlHsTyVar (getRdrName tycon))))]
+ where
+ rdr_name = tag2con_RDR tycon
-gen_tag_n_con_monobind (rdr_name, tycon, GenMaxTag)
- = mkVarBind (getSrcSpan tycon) rdr_name
+genAuxBind loc (GenMaxTag tycon)
+ = mkVarBind loc rdr_name
(nlHsApp (nlHsVar intDataCon_RDR) (nlHsLit (HsIntPrim max_tag)))
where
+ rdr_name = maxtag_RDR tycon
max_tag = case (tyConDataCons tycon) of
data_cons -> toInteger ((length data_cons) - fIRST_TAG)
+genAuxBind loc (MkTyCon tycon) -- $dT
+ = mkVarBind loc (mk_data_type_name tycon)
+ ( nlHsVar mkDataType_RDR
+ `nlHsApp` nlHsLit (mkHsString (showSDoc (ppr tycon)))
+ `nlHsApp` nlList constrs )
+ where
+ constrs = [nlHsVar (mk_constr_name con) | con <- tyConDataCons tycon]
+
+genAuxBind loc (MkDataCon dc) -- $cT1 etc
+ = mkVarBind loc (mk_constr_name dc)
+ (nlHsApps mkConstr_RDR constr_args)
+ where
+ 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
\end{code}
%************************************************************************
-> LHsExpr RdrName -> LHsExpr RdrName
-> LHsExpr RdrName
+cmp_eq_Expr :: 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
| 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)
+ = nlHsIf (genOpApp a relevant_lt_op b) -- Test (<) first, not (==), becuase the latter
+ ltTag_Expr -- is true less often, so putting it first would
+ -- mean more tests (dynamically)
+ (nlHsIf (genOpApp a relevant_eq_op b) eq 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)
-> [(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
,(doublePrimTy, DoubleLtOp)
]
+box_con_tbl :: [(Type, RdrName)]
box_con_tbl =
[(charPrimTy, getRdrName charDataCon)
,(intPrimTy, getRdrName intDataCon)
\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)]
-- 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 :: LHsExpr RdrName
impossible_Expr = nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString "Urk! in TcGenDeriv"))
-- 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)
(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}
-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, k_RDR, z_RDR, ah_RDR, bh_RDR, ch_RDR, dh_RDR,
+ cmp_eq_RDR :: RdrName
+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")
+
+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, b_Expr, c_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr,
+ false_Expr, true_Expr :: LHsExpr RdrName
a_Expr = nlHsVar a_RDR
b_Expr = nlHsVar b_RDR
c_Expr = nlHsVar c_RDR
false_Expr = nlHsVar false_RDR
true_Expr = nlHsVar true_RDR
+a_Pat, b_Pat, c_Pat, d_Pat, k_Pat, z_Pat :: LPat RdrName
a_Pat = nlVarPat a_RDR
b_Pat = nlVarPat b_RDR
c_Pat = nlVarPat c_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, leInt_RDR,
+ tagToEnum_RDR :: RdrName
minusInt_RDR = primOpRdrName IntSubOp
eqInt_RDR = primOpRdrName IntEqOp
ltInt_RDR = primOpRdrName IntLtOp
leInt_RDR = primOpRdrName IntLeOp
tagToEnum_RDR = primOpRdrName TagToEnumOp
+error_RDR :: RdrName
error_RDR = getRdrName eRROR_ID
\end{code}