This patch does a fairly major clean-up of the code that implements 'deriving.
* The big changes are in TcDeriv, which is dramatically cleaned up.
In particular, there is a clear split into
a) inference of instance contexts for deriving clauses
b) generation of the derived code, given a context
Step (a) is skipped for standalone instance decls, which
have an explicitly provided context.
* The handling of "taggery", which is cooperative between TcDeriv and
TcGenDeriv, is cleaned up a lot
* I have added documentation for standalone deriving (which was
previously wrong).
* The Haskell report is vague on exactly when a deriving clause should
succeed. Prodded by Conal I have loosened the rules slightly, thereyb
making drv015 work again, and documented the rules in the user manual.
I believe this patch validates ok (once I've update the test suite)
and can go into the 6.8 branch.
Handles @deriving@ clauses on @data@ declarations.
\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/Commentary/CodingStyle#Warnings
--- for details
-
module TcDeriv ( tcDeriving ) where
#include "HsVersions.h"
%************************************************************************
%* *
-\subsection[TcDeriv-intro]{Introduction to how we do deriving}
+ Overview
%* *
%************************************************************************
+Overall plan
+~~~~~~~~~~~~
+1. Convert the decls (i.e. data/newtype deriving clauses,
+ plus standalone deriving) to [EarlyDerivSpec]
+
+2. Infer the missing contexts for the Left DerivSpecs
+
+3. Add the derived bindings, generating InstInfos
+
+\begin{code}
+-- DerivSpec is purely local to this module
+data DerivSpec = DS { ds_loc :: SrcSpan
+ , ds_orig :: InstOrigin
+ , ds_name :: Name
+ , ds_tvs :: [TyVar]
+ , ds_theta :: ThetaType
+ , ds_cls :: Class
+ , ds_tys :: [Type]
+ , ds_newtype :: Bool }
+ -- This spec implies a dfun declaration of the form
+ -- df :: forall tvs. theta => C tys
+ -- The Name is the name for the DFun we'll build
+ -- The tyvars bind all the variables in the theta
+ -- For family indexes, the tycon is the *family* tycon
+ -- (not the representation tycon)
+
+ -- ds_newtype = True <=> Newtype deriving
+ -- False <=> Vanilla deriving
+
+type EarlyDerivSpec = Either DerivSpec DerivSpec
+ -- Left ds => the context for the instance should be inferred
+ -- (ds_theta is required)
+ -- Right ds => the context for the instance is supplied by the programmer
+
+pprDerivSpec :: DerivSpec -> SDoc
+pprDerivSpec (DS { ds_loc = l, ds_name = n, ds_tvs = tvs,
+ ds_cls = c, ds_tys = tys, ds_theta = rhs })
+ = parens (hsep [ppr l, ppr n, ppr tvs, ppr c, ppr tys]
+ <+> equals <+> ppr rhs)
+\end{code}
+
+
+Inferring missing contexts
+~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
data T a b = C1 (Foo a) (Bar b)
So, here are the synonyms for the ``equation'' structures:
-\begin{code}
-type DerivRhs = ThetaType
-type DerivSoln = DerivRhs
-type DerivEqn = (SrcSpan, InstOrigin, Name, [TyVar], Class, Type, DerivRhs)
- -- (span, orig, df, tvs, C, ty, rhs)
- -- implies a dfun declaration of the form
- -- df :: forall tvs. rhs => C ty
- -- The Name is the name for the DFun we'll build
- -- The tyvars bind all the variables in the RHS
- -- For family indexes, the tycon is the *family* tycon
- -- (not the representation tycon)
-
-pprDerivEqn :: DerivEqn -> SDoc
-pprDerivEqn (l, _, n, tvs, c, ty, rhs)
- = parens (hsep [ppr l, ppr n, ppr tvs, ppr c, ppr ty]
- <+> equals <+> ppr rhs)
-\end{code}
-
-[Data decl contexts] A note about contexts on data decls
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Data decl contexts]
+~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
data (RealFloat a) => Complex a = !a :+ !a deriving( Read )
gives rise to the constraints for that context -- or at least the thinned
version. So now all classes are "offending".
-[Newtype deriving]
-~~~~~~~~~~~~~~~~~~
+Note [Newtype deriving]
+~~~~~~~~~~~~~~~~~~~~~~~
Consider this:
class C a b
instance C [a] Char
instance C [a] Char => C [a] T where ...
+Note [Newtype deriving superclasses]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The 'tys' here come from the partial application in the deriving
+clause. The last arg is the new instance type.
+
+We must pass the superclasses; the newtype might be an instance
+of them in a different way than the representation type
+E.g. newtype Foo a = Foo a deriving( Show, Num, Eq )
+Then the Show instance is not done via isomorphism; it shows
+ Foo 3 as "Foo 3"
+The Num instance is derived via isomorphism, but the Show superclass
+dictionary must the Show instance for Foo, *not* the Show dictionary
+gotten from the Num dictionary. So we must build a whole new dictionary
+not just use the Num one. The instance we want is something like:
+ instance (Num a, Show (Foo a), Eq (Foo a)) => Num (Foo a) where
+ (+) = ((+)@a)
+ ...etc...
+There may be a coercion needed which we get from the tycon for the newtype
+when the dict is constructed in TcInstDcls.tcInstDecl2
+
+
%************************************************************************
tcDeriving tycl_decls inst_decls deriv_decls
= recoverM (returnM ([], emptyValBindsOut)) $
do { -- Fish the "deriving"-related information out of the TcEnv
- -- and make the necessary "equations".
- ; (ordinary_eqns, newtype_inst_info)
- <- makeDerivEqns tycl_decls inst_decls deriv_decls
-
- ; (ordinary_inst_info, deriv_binds)
- <- extendLocalInstEnv (map iSpec newtype_inst_info) $
- deriveOrdinaryStuff ordinary_eqns
- -- Add the newtype-derived instances to the inst env
- -- before tacking the "ordinary" ones
+ -- And make the necessary "equations".
+ ; early_specs <- makeDerivSpecs tycl_decls inst_decls deriv_decls
- ; let inst_info = newtype_inst_info ++ ordinary_inst_info
+ ; overlap_flag <- getOverlapFlag
+ ; let (infer_specs, given_specs) = splitEithers early_specs
+ ; (insts1, aux_binds1) <- mapAndUnzipM (genInst overlap_flag) given_specs
- -- If we are compiling a hs-boot file,
- -- don't generate any derived bindings
- ; is_boot <- tcIsHsBoot
- ; if is_boot then
- return (inst_info, emptyValBindsOut)
- else do
- {
+ ; final_specs <- extendLocalInstEnv (map iSpec insts1) $
+ inferInstanceContexts overlap_flag infer_specs
- -- Generate the generic to/from functions from each type declaration
- ; gen_binds <- mkGenericBinds tycl_decls
+ ; (insts2, aux_binds2) <- mapAndUnzipM (genInst overlap_flag) final_specs
- -- Rename these extra bindings, discarding warnings about unused bindings etc
- -- Type signatures in patterns are used in the generic binds
- ; rn_binds
- <- discardWarnings $
- setOptM Opt_PatternSignatures $
- do
- { (rn_deriv, _dus1) <- rnTopBinds (ValBindsIn deriv_binds [])
- ; (rn_gen, dus_gen) <- rnTopBinds (ValBindsIn gen_binds [])
- ; keepAliveSetTc (duDefs dus_gen) -- Mark these guys to
- -- be kept alive
- ; return (rn_deriv `plusHsValBinds` rn_gen) }
+ ; is_boot <- tcIsHsBoot
+ ; rn_binds <- makeAuxBinds is_boot tycl_decls
+ (concat aux_binds1 ++ concat aux_binds2)
+ ; let inst_info = insts1 ++ insts2
; dflags <- getDOpts
; ioToTcRn (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"
(ddump_deriving inst_info rn_binds))
- ; returnM (inst_info, rn_binds)
- }}
+ ; return (inst_info, rn_binds) }
where
ddump_deriving :: [InstInfo] -> HsValBinds Name -> SDoc
ddump_deriving inst_infos extra_binds
= vcat (map pprInstInfoDetails inst_infos) $$ ppr extra_binds
------------------------------------------
-deriveOrdinaryStuff [] -- Short cut
- = returnM ([], emptyLHsBinds)
+makeAuxBinds :: Bool -> [LTyClDecl Name] -> DerivAuxBinds -> TcM (HsValBinds Name)
+makeAuxBinds is_boot tycl_decls deriv_aux_binds
+ | is_boot -- If we are compiling a hs-boot file,
+ -- don't generate any derived bindings
+ = return emptyValBindsOut
-deriveOrdinaryStuff eqns
- = do { -- Take the equation list and solve it, to deliver a list of
- -- solutions, a.k.a. the contexts for the instance decls
- -- required for the corresponding equations.
- overlap_flag <- getOverlapFlag
- ; inst_specs <- solveDerivEqns overlap_flag eqns
-
- -- Generate the InstInfo for each dfun,
- -- plus any auxiliary bindings it needs
- ; (inst_infos, aux_binds_s) <- mapAndUnzipM genInst inst_specs
+ | otherwise
+ = do { let aux_binds = listToBag (map genAuxBind (rm_dups [] deriv_aux_binds))
+ -- Generate any extra not-one-inst-decl-specific binds,
+ -- notably "con2tag" and/or "tag2con" functions.
- -- Generate any extra not-one-inst-decl-specific binds,
- -- notably "con2tag" and/or "tag2con" functions.
- ; extra_binds <- genTaggeryBinds inst_infos
+ -- Generate the generic to/from functions from each type declaration
+ ; gen_binds <- mkGenericBinds tycl_decls
- -- Done
- ; returnM (map fst inst_infos,
- unionManyBags (extra_binds : aux_binds_s))
- }
+ -- Rename these extra bindings, discarding warnings about unused bindings etc
+ -- Type signatures in patterns are used in the generic binds
+ ; discardWarnings $
+ setOptM Opt_PatternSignatures $
+ do { (rn_deriv, _dus1) <- rnTopBinds (ValBindsIn aux_binds [])
+ ; (rn_gen, dus_gen) <- rnTopBinds (ValBindsIn gen_binds [])
+ ; keepAliveSetTc (duDefs dus_gen) -- Mark these guys to
+ -- be kept alive
+ ; return (rn_deriv `plusHsValBinds` rn_gen) } }
+ where
+ -- Remove duplicate requests for auxilliary bindings
+ rm_dups acc [] = acc
+ rm_dups acc (b:bs) | any (isDupAux b) acc = rm_dups acc bs
+ | otherwise = rm_dups (b:acc) bs
-----------------------------------------
+mkGenericBinds :: [LTyClDecl Name] -> TcM (LHsBinds RdrName)
mkGenericBinds tycl_decls
= do { tcs <- mapM tcLookupTyCon
[ tc_name |
%************************************************************************
%* *
-\subsection[TcDeriv-eqns]{Forming the equations}
+ From HsSyn to DerivSpec
%* *
%************************************************************************
-@makeDerivEqns@ fishes around to find the info about needed derived
+@makeDerivSpecs@ fishes around to find the info about needed derived
instances. Complicating factors:
\begin{itemize}
\item
[See Appendix~E in the Haskell~1.2 report.] This code here deals w/
all those.
-Note [Newtype deriving superclasses]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The 'tys' here come from the partial application in the deriving
-clause. The last arg is the new instance type.
-
-We must pass the superclasses; the newtype might be an instance
-of them in a different way than the representation type
-E.g. newtype Foo a = Foo a deriving( Show, Num, Eq )
-Then the Show instance is not done via isomorphism; it shows
- Foo 3 as "Foo 3"
-The Num instance is derived via isomorphism, but the Show superclass
-dictionary must the Show instance for Foo, *not* the Show dictionary
-gotten from the Num dictionary. So we must build a whole new dictionary
-not just use the Num one. The instance we want is something like:
- instance (Num a, Show (Foo a), Eq (Foo a)) => Num (Foo a) where
- (+) = ((+)@a)
- ...etc...
-There may be a coercion needed which we get from the tycon for the newtype
-when the dict is constructed in TcInstDcls.tcInstDecl2
-
-
\begin{code}
-makeDerivEqns :: [LTyClDecl Name]
- -> [LInstDecl Name]
- -> [LDerivDecl Name]
- -> TcM ([DerivEqn], -- Ordinary derivings
- [InstInfo]) -- Special newtype derivings
+makeDerivSpecs :: [LTyClDecl Name]
+ -> [LInstDecl Name]
+ -> [LDerivDecl Name]
+ -> TcM [EarlyDerivSpec]
-makeDerivEqns tycl_decls inst_decls deriv_decls
+makeDerivSpecs tycl_decls inst_decls deriv_decls
= do { eqns1 <- mapM deriveTyData $
extractTyDataPreds tycl_decls ++
[ pd -- traverse assoc data families
| L _ (InstDecl _ _ _ ats) <- inst_decls
, pd <- extractTyDataPreds ats ]
; eqns2 <- mapM deriveStandalone deriv_decls
- ; return ([eqn | (Just eqn, _) <- eqns1 ++ eqns2],
- [inst | (_, Just inst) <- eqns1 ++ eqns2]) }
+ ; return (catMaybes (eqns1 ++ eqns2)) }
where
extractTyDataPreds decls =
[(p, d) | d@(L _ (TyData {tcdDerivs = Just preds})) <- decls, p <- preds]
------------------------------------------------------------------
-deriveStandalone :: LDerivDecl Name -> TcM (Maybe DerivEqn, Maybe InstInfo)
+deriveStandalone :: LDerivDecl Name -> TcM (Maybe EarlyDerivSpec)
-- Standalone deriving declarations
-- e.g. deriving instance show a => Show (T a)
-- Rather like tcLocalInstDecl
(Just theta) }
------------------------------------------------------------------
-deriveTyData :: (LHsType Name, LTyClDecl Name) -> TcM (Maybe DerivEqn, Maybe InstInfo)
+deriveTyData :: (LHsType Name, LTyClDecl Name) -> TcM (Maybe EarlyDerivSpec)
deriveTyData (deriv_pred, L loc decl@(TyData { tcdLName = L _ tycon_name,
tcdTyVars = tv_names,
tcdTyPats = ty_pats }))
-- The "deriv_pred" is a LHsType to take account of the fact that for
-- newtype deriving we allow deriving (forall a. C [a]).
; mkEqnHelp DerivOrigin (tvs++deriv_tvs) cls cls_tys tc_app Nothing } }
-deriveTyData (deriv_pred, other_decl)
+
+deriveTyData _other
= panic "derivTyData" -- Caller ensures that only TyData can happen
------------------------------------------------------------------
mkEqnHelp :: InstOrigin -> [TyVar] -> Class -> [Type] -> Type
- -> Maybe DerivRhs
- -> TcRn (Maybe DerivEqn, Maybe InstInfo)
+ -> Maybe ThetaType -- Just => context supplied
+ -- Nothing => context inferred
+ -> TcRn (Maybe EarlyDerivSpec)
mkEqnHelp orig tvs cls cls_tys tc_app mtheta
| Just (tycon, tc_args) <- tcSplitTyConApp_maybe tc_app
= do { -- Make tc_app saturated, because that's what the
; mayDeriveDataTypeable <- doptM Opt_DeriveDataTypeable
; newtype_deriving <- doptM Opt_GeneralizedNewtypeDeriving
- ; overlap_flag <- getOverlapFlag
-- Be careful to test rep_tc here: in the case of families, we want
-- to check the instance tycon, not the family tycon
mkDataTypeEqn orig mayDeriveDataTypeable full_tvs cls cls_tys
tycon full_tc_args rep_tc rep_tc_args mtheta
else
- mkNewTypeEqn orig mayDeriveDataTypeable newtype_deriving overlap_flag
- full_tvs cls cls_tys
- tycon full_tc_args rep_tc rep_tc_args mtheta }
+ mkNewTypeEqn orig mayDeriveDataTypeable newtype_deriving
+ full_tvs cls cls_tys
+ tycon full_tc_args rep_tc rep_tc_args mtheta }
| otherwise
= baleOut (derivingThingErr cls cls_tys tc_app
(ptext SLIT("Last argument of the instance must be a type application")))
-baleOut err = addErrTc err >> returnM (Nothing, Nothing)
+baleOut :: Message -> TcM (Maybe a)
+baleOut err = do { addErrTc err; return Nothing }
\end{code}
Auxiliary lookup wrapper which requires that looked up family instances are
\begin{code}
mkDataTypeEqn :: InstOrigin -> Bool -> [Var] -> Class -> [Type]
- -> TyCon -> [Type] -> TyCon -> [Type] -> Maybe DerivRhs
- -> TcRn (Maybe DerivEqn, Maybe InstInfo)
+ -> TyCon -> [Type] -> TyCon -> [Type] -> Maybe ThetaType
+ -> TcRn (Maybe EarlyDerivSpec) -- Return 'Nothing' if error
+
mkDataTypeEqn orig mayDeriveDataTypeable tvs cls cls_tys
tycon tc_args rep_tc rep_tc_args mtheta
| Just err <- checkSideConditions mayDeriveDataTypeable cls cls_tys rep_tc
| otherwise
= ASSERT( null cls_tys )
- do { loc <- getSrcSpanM
- ; eqn <- mk_data_eqn loc orig tvs cls tycon tc_args rep_tc
- rep_tc_args mtheta
- ; return (Just eqn, Nothing) }
-
-mk_data_eqn :: SrcSpan -> InstOrigin -> [TyVar] -> Class
- -> TyCon -> [TcType] -> TyCon -> [TcType] -> Maybe DerivRhs
- -> TcM DerivEqn
-mk_data_eqn loc orig tvs cls tycon tc_args rep_tc rep_tc_args mtheta
+ mk_data_eqn orig tvs cls tycon tc_args rep_tc rep_tc_args mtheta
+
+mk_data_eqn :: InstOrigin -> [TyVar] -> Class
+ -> TyCon -> [TcType] -> TyCon -> [TcType] -> Maybe ThetaType
+ -> TcM (Maybe EarlyDerivSpec)
+mk_data_eqn orig tvs cls tycon tc_args rep_tc rep_tc_args mtheta
| cls `hasKey` typeableClassKey
= -- The Typeable class is special in several ways
-- data T a b = ... deriving( Typeable )
-- Typeable; it depends on the arity of the type
do { real_clas <- tcLookupClass (typeableClassNames !! tyConArity tycon)
; dfun_name <- new_dfun_name real_clas tycon
- ; let theta = fromMaybe [] mtheta
- ; return (loc, orig, dfun_name, [], real_clas, mkTyConApp tycon [], theta)
- }
+ ; loc <- getSrcSpanM
+ ; return (Just $ Right $
+ DS { ds_loc = loc, ds_orig = orig, ds_name = dfun_name, ds_tvs = []
+ , ds_cls = real_clas, ds_tys = [mkTyConApp tycon []]
+ , ds_theta = mtheta `orElse` [], ds_newtype = False }) }
| otherwise
= do { dfun_name <- new_dfun_name cls tycon
+ ; loc <- getSrcSpanM
; let ordinary_constraints
= [ mkClassPred cls [arg_ty]
| data_con <- tyConDataCons rep_tc,
arg_ty <- ASSERT( isVanillaDataCon data_con )
dataConInstOrigArgTys data_con rep_tc_args,
not (isUnLiftedType arg_ty) ] -- No constraints for unlifted types?
- theta = fromMaybe ordinary_constraints mtheta
- tiresome_subst = zipTopTvSubst (tyConTyVars rep_tc) rep_tc_args
- stupid_constraints = substTheta tiresome_subst (tyConStupidTheta rep_tc)
- -- see note [Data decl contexts] above
+ stupid_subst = zipTopTvSubst (tyConTyVars rep_tc) rep_tc_args
+ stupid_constraints = substTheta stupid_subst (tyConStupidTheta rep_tc)
+ all_constraints = stupid_constraints ++ ordinary_constraints
+ -- see Note [Data decl contexts] above
- ; return (loc, orig, dfun_name, tvs, cls, mkTyConApp tycon tc_args,
- stupid_constraints ++ theta)
- }
+ spec = DS { ds_loc = loc, ds_orig = orig
+ , ds_name = dfun_name, ds_tvs = tvs
+ , ds_cls = cls, ds_tys = [mkTyConApp tycon tc_args]
+ , ds_theta = mtheta `orElse` all_constraints
+ , ds_newtype = False }
+
+ ; return (if isJust mtheta then Just (Right spec) -- Specified context
+ else Just (Left spec)) } -- Infer context
------------------------------------------------------------------
-- Check side conditions that dis-allow derivability for particular classes
= case [cond | (key,cond) <- sideConditions, key == getUnique cls] of
[] -> Just (non_std_why cls)
[cond] -> cond (mayDeriveDataTypeable, rep_tc)
- other -> pprPanic "checkSideConditions" (ppr cls)
+ _other -> pprPanic "checkSideConditions" (ppr cls)
where
ty_args_why = quotes (ppr (mkClassPred cls cls_tys)) <+> ptext SLIT("is not a class")
+non_std_why :: Class -> SDoc
non_std_why cls = quotes (ppr cls) <+> ptext SLIT("is not a derivable class")
sideConditions :: [(Unique, Condition)]
Just y -> Just (x $$ ptext SLIT(" and") $$ y)
-- Both fail
+andCond :: Condition -> Condition -> Condition
andCond c1 c2 tc = case c1 tc of
Nothing -> c2 tc -- c1 succeeds
Just x -> Just x -- c1 fails
where
why = ptext SLIT("You need -fglasgow-exts to derive an instance for this class")
+std_class_via_iso :: Class -> Bool
std_class_via_iso clas -- These standard classes can be derived for a newtype
-- using the isomorphism trick *even if no -fglasgow-exts*
= classKey clas `elem` [eqClassKey, ordClassKey, ixClassKey, boundedClassKey]
-- Not Enum, because newtypes are never in Enum
+new_dfun_name :: Class -> TyCon -> TcM Name
new_dfun_name clas tycon -- Just a simple wrapper
= newDFunName clas [mkTyConApp tycon []] (getSrcSpan tycon)
-- The type passed to newDFunName is only used to generate
%************************************************************************
\begin{code}
-mkNewTypeEqn :: InstOrigin -> Bool -> Bool -> OverlapFlag -> [Var] -> Class
+mkNewTypeEqn :: InstOrigin -> Bool -> Bool -> [Var] -> Class
-> [Type] -> TyCon -> [Type] -> TyCon -> [Type]
- -> Maybe DerivRhs
- -> TcRn (Maybe DerivEqn, Maybe InstInfo)
-mkNewTypeEqn orig mayDeriveDataTypeable newtype_deriving overlap_flag tvs
+ -> Maybe ThetaType
+ -> TcRn (Maybe EarlyDerivSpec)
+mkNewTypeEqn orig mayDeriveDataTypeable newtype_deriving tvs
cls cls_tys tycon tc_args rep_tycon rep_tc_args mtheta
| can_derive_via_isomorphism && (newtype_deriving || std_class_via_iso cls)
= do { traceTc (text "newtype deriving:" <+> ppr tycon <+> ppr rep_tys)
- ; -- Go ahead and use the isomorphism
- dfun_name <- new_dfun_name cls tycon
- ; return (Nothing, Just (InstInfo { iSpec = mk_inst_spec dfun_name,
- iBinds = NewTypeDerived ntd_info })) }
+ ; dfun_name <- new_dfun_name cls tycon
+ ; loc <- getSrcSpanM
+ ; let spec = DS { ds_loc = loc, ds_orig = orig
+ , ds_name = dfun_name, ds_tvs = dict_tvs
+ , ds_cls = cls, ds_tys = inst_tys
+ , ds_theta = mtheta `orElse` all_preds
+ , ds_newtype = True }
+ ; return (if isJust mtheta then Just (Right spec)
+ else Just (Left spec)) }
| isNothing mb_std_err -- Use the standard H98 method
- = do { loc <- getSrcSpanM
- ; eqn <- mk_data_eqn loc orig tvs cls tycon tc_args rep_tycon
- rep_tc_args mtheta
- ; return (Just eqn, Nothing) }
+ = mk_data_eqn orig tvs cls tycon tc_args rep_tycon rep_tc_args mtheta
-- Otherwise we can't derive
| newtype_deriving = baleOut cant_derive_err -- Too hard
- | otherwise = baleOut std_err -- Just complain about being a non-std instance
+ | otherwise = baleOut std_err -- Just complain about being a non-std instance
where
mb_std_err = checkSideConditions mayDeriveDataTypeable cls cls_tys rep_tycon
std_err = derivingThingErr cls cls_tys tc_app $
-- instance C Int => C T
dict_tvs = filterOut (`elemVarSet` dropped_tvs) tvs
all_preds = rep_pred : sc_theta -- NB: rep_pred comes first
- (dict_args, ntd_info) | null dict_tvs = ([], Just all_preds)
- | otherwise = (all_preds, Nothing)
-
- -- Finally! Here's where we build the dictionary Id
- mk_inst_spec dfun_name = mkLocalInstance dfun overlap_flag
- where
- dfun = mkDictFunId dfun_name dict_tvs dict_args cls inst_tys
-------------------------------------------------------------------
-- Figuring out whether we can only do this newtype-deriving thing
\end{itemize}
\begin{code}
-solveDerivEqns :: OverlapFlag
- -> [DerivEqn]
- -> TcM [Instance]-- Solns in same order as eqns.
- -- This bunch is Absolutely minimal...
-
-solveDerivEqns overlap_flag orig_eqns
- = do { traceTc (text "solveDerivEqns" <+> vcat (map pprDerivEqn orig_eqns))
- ; iterateDeriv 1 initial_solutions }
+inferInstanceContexts :: OverlapFlag -> [DerivSpec] -> TcM [DerivSpec]
+
+inferInstanceContexts _ [] = return []
+
+inferInstanceContexts oflag infer_specs
+ = do { traceTc (text "inferInstanceContexts" <+> vcat (map pprDerivSpec infer_specs))
+ ; iterate_deriv 1 initial_solutions }
where
+ ------------------------------------------------------------------
-- The initial solutions for the equations claim that each
-- instance has an empty context; this solution is certainly
-- in canonical form.
- initial_solutions :: [DerivSoln]
- initial_solutions = [ [] | _ <- orig_eqns ]
+ initial_solutions :: [ThetaType]
+ initial_solutions = [ [] | _ <- infer_specs ]
------------------------------------------------------------------
- -- iterateDeriv calculates the next batch of solutions,
+ -- iterate_deriv calculates the next batch of solutions,
-- compares it with the current one; finishes if they are the
-- same, otherwise recurses with the new solutions.
-- It fails if any iteration fails
- iterateDeriv :: Int -> [DerivSoln] -> TcM [Instance]
- iterateDeriv n current_solns
+ iterate_deriv :: Int -> [ThetaType] -> TcM [DerivSpec]
+ iterate_deriv n current_solns
| n > 20 -- Looks as if we are in an infinite loop
-- This can happen if we have -fallow-undecidable-instances
-- (See TcSimplify.tcSimplifyDeriv.)
= pprPanic "solveDerivEqns: probable loop"
- (vcat (map pprDerivEqn orig_eqns) $$ ppr current_solns)
+ (vcat (map pprDerivSpec infer_specs) $$ ppr current_solns)
| otherwise
- = let
- inst_specs = zipWithEqual "add_solns" mk_inst_spec
- orig_eqns current_solns
- in
- checkNoErrs (
- -- Extend the inst info from the explicit instance decls
+ = do { -- Extend the inst info from the explicit instance decls
-- with the current set of solutions, and simplify each RHS
- extendLocalInstEnv inst_specs $
- mappM gen_soln orig_eqns
- ) `thenM` \ new_solns ->
- if (current_solns == new_solns) then
- returnM inst_specs
- else
- iterateDeriv (n+1) new_solns
+ let inst_specs = zipWithEqual "add_solns" (mkInstance2 oflag)
+ current_solns infer_specs
+ ; new_solns <- checkNoErrs $
+ extendLocalInstEnv inst_specs $
+ mapM gen_soln infer_specs
+
+ ; if (current_solns == new_solns) then
+ return [ spec { ds_theta = soln }
+ | (spec, soln) <- zip infer_specs current_solns ]
+ else
+ iterate_deriv (n+1) new_solns }
------------------------------------------------------------------
- gen_soln :: DerivEqn -> TcM [PredType]
- gen_soln (loc, orig, _, tyvars, clas, inst_ty, deriv_rhs)
+ gen_soln :: DerivSpec -> TcM [PredType]
+ gen_soln (DS { ds_loc = loc, ds_orig = orig, ds_tvs = tyvars
+ , ds_cls = clas, ds_tys = inst_tys, ds_theta = deriv_rhs })
= setSrcSpan loc $
- addErrCtxt (derivInstCtxt clas [inst_ty]) $
+ addErrCtxt (derivInstCtxt clas inst_tys) $
do { theta <- tcSimplifyDeriv orig tyvars deriv_rhs
- -- checkValidInstance tyvars theta clas [inst_ty]
+ -- checkValidInstance tyvars theta clas inst_tys
-- Not necessary; see Note [Exotic derived instance contexts]
-- in TcSimplify
-- checkValidInstance tyvars theta clas inst_tys
; return (sortLe (<=) theta) } -- Canonicalise before returning the solution
- ------------------------------------------------------------------
- mk_inst_spec :: DerivEqn -> DerivSoln -> Instance
- mk_inst_spec (loc, orig, dfun_name, tyvars, clas, inst_ty, _) theta
- = mkLocalInstance dfun overlap_flag
- where
- dfun = mkDictFunId dfun_name tyvars theta clas [inst_ty]
+------------------------------------------------------------------
+mkInstance1 :: OverlapFlag -> DerivSpec -> Instance
+mkInstance1 overlap_flag spec = mkInstance2 overlap_flag (ds_theta spec) spec
+
+mkInstance2 :: OverlapFlag -> ThetaType -> DerivSpec -> Instance
+mkInstance2 overlap_flag theta
+ (DS { ds_name = dfun_name
+ , ds_tvs = tyvars, ds_cls = clas, ds_tys = tys })
+ = mkLocalInstance dfun overlap_flag
+ where
+ dfun = mkDictFunId dfun_name tyvars theta clas tys
+
extendLocalInstEnv :: [Instance] -> TcM a -> TcM a
-- Add new locally-defined instances; don't bother to check
-- Representation tycons differ from the tycon in the instance signature in
-- case of instances for indexed families.
--
-genInst :: Instance -> TcM ((InstInfo, TyCon), LHsBinds RdrName)
-genInst spec
+genInst :: OverlapFlag -> DerivSpec -> TcM (InstInfo, DerivAuxBinds)
+genInst oflag spec
+ | ds_newtype spec
+ = return (InstInfo { iSpec = mkInstance1 oflag spec
+ , iBinds = NewTypeDerived }, [])
+
+ | otherwise
= do { fix_env <- getFixityEnv
; let
- (tyvars,_,clas,[ty]) = instanceHead spec
+ inst = mkInstance1 oflag spec
+ (tyvars,_,clas,[ty]) = instanceHead inst
clas_nm = className clas
(visible_tycon, tyArgs) = tcSplitTyConApp ty
-- *non-renamed* auxiliary bindings
; (rn_meth_binds, _fvs) <- discardWarnings $
bindLocalNames (map Var.varName tyvars) $
- rnMethodBinds clas_nm (\n -> []) [] meth_binds
+ rnMethodBinds clas_nm (\_ -> []) [] meth_binds
-- Build the InstInfo
- ; return ((InstInfo { iSpec = spec,
- iBinds = VanillaInst rn_meth_binds [] }, tycon),
+ ; return (InstInfo { iSpec = inst,
+ iBinds = VanillaInst rn_meth_binds [] },
aux_binds)
}
+genDerivBinds :: Class -> FixityEnv -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
genDerivBinds clas fix_env tycon
| className clas `elem` typeableClassNames
- = (gen_Typeable_binds tycon, emptyLHsBinds)
+ = (gen_Typeable_binds tycon, [])
| otherwise
= case assocMaybe gen_list (getUnique clas) of
- Just gen_fn -> gen_fn fix_env tycon
+ Just gen_fn -> gen_fn tycon
Nothing -> pprPanic "genDerivBinds: bad derived class" (ppr clas)
where
- gen_list :: [(Unique, FixityEnv -> TyCon -> (LHsBinds RdrName, LHsBinds RdrName))]
- gen_list = [(eqClassKey, no_aux_binds (ignore_fix_env gen_Eq_binds))
- ,(ordClassKey, no_aux_binds (ignore_fix_env gen_Ord_binds))
- ,(enumClassKey, no_aux_binds (ignore_fix_env gen_Enum_binds))
- ,(boundedClassKey, no_aux_binds (ignore_fix_env gen_Bounded_binds))
- ,(ixClassKey, no_aux_binds (ignore_fix_env gen_Ix_binds))
- ,(typeableClassKey,no_aux_binds (ignore_fix_env gen_Typeable_binds))
- ,(showClassKey, no_aux_binds gen_Show_binds)
- ,(readClassKey, no_aux_binds gen_Read_binds)
- ,(dataClassKey, gen_Data_binds)
+ gen_list :: [(Unique, TyCon -> (LHsBinds RdrName, DerivAuxBinds))]
+ gen_list = [(eqClassKey, gen_Eq_binds)
+ ,(ordClassKey, gen_Ord_binds)
+ ,(enumClassKey, gen_Enum_binds)
+ ,(boundedClassKey, gen_Bounded_binds)
+ ,(ixClassKey, gen_Ix_binds)
+ ,(showClassKey, gen_Show_binds fix_env)
+ ,(readClassKey, gen_Read_binds fix_env)
+ ,(dataClassKey, gen_Data_binds fix_env)
]
-
- -- no_aux_binds is used for generators that don't
- -- need to produce any auxiliary bindings
- no_aux_binds f fix_env tc = (f fix_env tc, emptyLHsBinds)
- ignore_fix_env f fix_env tc = f tc
\end{code}
%* *
%************************************************************************
-
-data Foo ... = ...
-
-con2tag_Foo :: Foo ... -> Int#
-tag2con_Foo :: Int -> Foo ... -- easier if Int, not Int#
-maxtag_Foo :: Int -- ditto (NB: not unlifted)
-
-
-We have a @con2tag@ function for a tycon if:
-\begin{itemize}
-\item
-We're deriving @Eq@ and the tycon has nullary data constructors.
-
-\item
-Or: we're deriving @Ord@ (unless single-constructor), @Enum@, @Ix@
-(enum type only????)
-\end{itemize}
-
-We have a @tag2con@ function for a tycon if:
-\begin{itemize}
-\item
-We're deriving @Enum@, or @Ix@ (enum type only???)
-\end{itemize}
-
-If we have a @tag2con@ function, we also generate a @maxtag@ constant.
-
-\begin{code}
-genTaggeryBinds :: [(InstInfo, TyCon)] -> TcM (LHsBinds RdrName)
-genTaggeryBinds infos
- = do { names_so_far <- foldlM do_con2tag [] tycons_of_interest
- ; nm_alist_etc <- foldlM do_tag2con names_so_far tycons_of_interest
- ; return (listToBag (map gen_tag_n_con_monobind nm_alist_etc)) }
- where
- all_CTs = [ (fst (simpleInstInfoClsTy info), tc)
- | (info, tc) <- infos]
- all_tycons = map snd all_CTs
- (tycons_of_interest, _) = removeDups compare all_tycons
-
- do_con2tag acc_Names tycon
- | isDataTyCon tycon &&
- ((we_are_deriving eqClassKey tycon
- && any isNullarySrcDataCon (tyConDataCons tycon))
- || (we_are_deriving ordClassKey tycon
- && not (isProductTyCon tycon))
- || (we_are_deriving enumClassKey tycon)
- || (we_are_deriving ixClassKey tycon))
-
- = returnM ((con2tag_RDR tycon, tycon, GenCon2Tag)
- : acc_Names)
- | otherwise
- = returnM acc_Names
-
- do_tag2con acc_Names tycon
- | isDataTyCon tycon &&
- (we_are_deriving enumClassKey tycon ||
- we_are_deriving ixClassKey tycon
- && isEnumerationTyCon tycon)
- = returnM ( (tag2con_RDR tycon, tycon, GenTag2Con)
- : (maxtag_RDR tycon, tycon, GenMaxTag)
- : acc_Names)
- | otherwise
- = returnM acc_Names
-
- we_are_deriving clas_key tycon
- = is_in_eqns clas_key tycon all_CTs
- where
- is_in_eqns clas_key tycon [] = False
- is_in_eqns clas_key tycon ((c,t):cts)
- = (clas_key == classKey c && tycon == t)
- || is_in_eqns clas_key tycon cts
-\end{code}
-
\begin{code}
+derivingThingErr :: Class -> [Type] -> Type -> Message -> Message
derivingThingErr clas tys ty why
= sep [hsep [ptext SLIT("Can't make a derived instance of"),
quotes (ppr pred)],
standaloneCtxt :: LHsType Name -> SDoc
standaloneCtxt ty = ptext SLIT("In the stand-alone deriving instance for") <+> quotes (ppr ty)
+derivInstCtxt :: Class -> [Type] -> Message
derivInstCtxt clas inst_tys
= ptext SLIT("When deriving the instance for") <+> parens (pprClassPred clas inst_tys)
+badDerivedPred :: PredType -> Message
badDerivedPred pred
= vcat [ptext SLIT("Can't derive instances where the instance context mentions"),
ptext SLIT("type variables that are not data type parameters"),
nest 2 (ptext SLIT("Offending constraint:") <+> ppr pred)]
+famInstNotFound :: TyCon -> [Type] -> Bool -> TcM a
famInstNotFound tycon tys notExact
= failWithTc (msg <+> quotes (pprTypeApp tycon (ppr tycon) tys))
where
data InstBindings
= VanillaInst -- The normal case
- (LHsBinds Name) -- Bindings
+ (LHsBinds Name) -- Bindings for the instance methods
[LSig Name] -- User pragmas recorded for generating
-- specialised instances
| NewTypeDerived -- Used for deriving instances of newtypes, where the
-- witness dictionary is identical to the argument
-- dictionary. Hence no bindings, no pragmas.
- (Maybe [PredType])
- -- Nothing => The newtype-derived instance involves type variables,
- -- and the dfun has a type like df :: forall a. Eq a => Eq (T a)
- -- Just (r:scs) => The newtype-defined instance has no type variables
- -- so the dfun is just a constant, df :: Eq T
- -- In this case we need to know waht the rep dict, r, and the
- -- superclasses, scs, are. (In the Nothing case these are in the
- -- dict fun's type.)
- -- Invariant: these PredTypes have no free variables
- -- NB: In both cases, the representation dict is the *first* dict.
pprInstInfo info = vcat [ptext SLIT("InstInfo:") <+> ppr (idType (iDFunId info))]
pprInstInfoDetails info = pprInstInfo info $$ nest 2 (details (iBinds info))
where
- details (VanillaInst b _) = pprLHsBinds b
- details (NewTypeDerived _) = text "Derived from the representation type"
+ details (VanillaInst b _) = pprLHsBinds b
+ details NewTypeDerived = text "Derived from the representation type"
simpleInstInfoClsTy :: InstInfo -> (Class, Type)
simpleInstInfoClsTy info = case instanceHead (iSpec info) of
-- for details
module TcGenDeriv (
+ DerivAuxBind(..), 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,
+ genAuxBind,
- TagThingWanted(..)
+ con2tag_RDR, tag2con_RDR, maxtag_RDR
) 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
+ = DerivAuxBind (LHsBind RdrName)
+ | GenCon2Tag TyCon -- The con2Tag for given TyCon
+ | GenTag2Con TyCon -- ...ditto tag2Con
+ | GenMaxTag TyCon -- ...and maxTag
+
+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 b1 b2 = False
+\end{code}
+
%************************************************************************
%* *
-\subsubsection{Generating @Eq@ instance declarations}
+ Eq instances
%* *
%************************************************************************
\begin{code}
-gen_Eq_binds :: TyCon -> LHsBinds RdrName
-
+gen_Eq_binds :: TyCon -> (LHsBinds RdrName, DerivAuxBinds)
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])))
- ]
+ = (method_binds, aux_binds)
where
+ tycon_loc = getSrcSpan tycon
+
+ (nullary_cons, nonnullary_cons)
+ | isNewTyCon tycon = ([], tyConDataCons tycon)
+ | otherwise = partition isNullarySrcDataCon (tyConDataCons tycon)
+
+ no_nullary_cons = null nullary_cons
+
+ rest | no_nullary_cons
+ = case maybeTyConSingleCon 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 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])))]
+
------------------------------------------------------------------
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 :: TyCon -> (LHsBinds RdrName, DerivAuxBinds)
gen_Ord_binds tycon
- = unitBag compare -- `AndMonoBinds` compare
- -- The default declaration in PrelBase handles this
+ = (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_matches = [mkMatch [a_Pat, b_Pat] compare_rhs cmp_eq_binds]
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
- 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
\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 -> (LHsBinds RdrName, DerivAuxBinds)
gen_Enum_binds tycon
- = listToBag [
- succ_enum,
- pred_enum,
- to_enum,
- enum_from,
- enum_from_then,
- from_enum
- ]
+ = (method_binds, aux_binds)
where
+ method_binds = listToBag [
+ succ_enum,
+ pred_enum,
+ to_enum,
+ enum_from,
+ enum_from_then,
+ from_enum
+ ]
+ aux_binds = [GenCon2Tag tycon, GenTag2Con tycon, GenMaxTag tycon]
+
tycon_loc = getSrcSpan tycon
occ_nm = getOccString tycon
%************************************************************************
%* *
-\subsubsection{Generating @Bounded@ instance declarations}
+ Bounded instances
%* *
%************************************************************************
\begin{code}
+gen_Bounded_binds :: TyCon -> (LHsBinds RdrName, DerivAuxBinds)
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 ]
+ | 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
%************************************************************************
%* *
-\subsubsection{Generating @Ix@ instance declarations}
+ Ix instances
%* *
%************************************************************************
(p.~147).
\begin{code}
-gen_Ix_binds :: TyCon -> LHsBinds RdrName
+gen_Ix_binds :: TyCon -> (LHsBinds RdrName, DerivAuxBinds)
gen_Ix_binds tycon
- = if isEnumerationTyCon tycon
- then enum_ixes
- else single_con_ixes
+ | isEnumerationTyCon tycon
+ = (enum_ixes, [GenCon2Tag tycon, GenTag2Con tycon, GenMaxTag tycon])
+ | otherwise
+ = (single_con_ixes, [GenCon2Tag tycon])
where
tycon_loc = getSrcSpan tycon
%************************************************************************
%* *
-\subsubsection{Generating @Read@ instance declarations}
+ Read instances
%* *
%************************************************************************
\begin{code}
-gen_Read_binds :: FixityEnv -> TyCon -> LHsBinds RdrName
+gen_Read_binds :: FixityEnv -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
gen_Read_binds get_fixity tycon
- = listToBag [read_prec, default_readlist, default_readlistprec]
+ = (listToBag [read_prec, default_readlist, default_readlistprec], [])
where
-----------------------------------------------------------------------
default_readlist
%************************************************************************
%* *
-\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 -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
gen_Show_binds get_fixity tycon
- = listToBag [shows_prec, show_list]
+ = (listToBag [shows_prec, show_list], [])
where
tycon_loc = getSrcSpan tycon
-----------------------------------------------------------------------
%************************************************************************
%* *
-\subsection{Data}
+ Data instances
%* *
%************************************************************************
gen_Data_binds :: FixityEnv
-> TyCon
-> (LHsBinds RdrName, -- The method bindings
- LHsBinds RdrName) -- Auxiliary bindings
+ DerivAuxBinds) -- Auxiliary bindings
gen_Data_binds fix_env 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))
+ DerivAuxBind datatype_bind : map mk_con_bind data_cons)
where
tycon_loc = getSrcSpan tycon
tycon_name = tyConName tycon
------------ $cT1 etc
mk_constr_name con = mkDerivedRdrName (dataConName con) mkDataCOcc
- mk_con_bind dc = mkVarBind
+ mk_con_bind dc = DerivAuxBind $
+ mkVarBind
tycon_loc
(mk_constr_name dc)
(nlHsApps mkConstr_RDR (constr_args dc))
fiddling around.
\begin{code}
-data TagThingWanted
- = GenCon2Tag | GenTag2Con | GenMaxTag
+genAuxBind :: DerivAuxBind -> LHsBind RdrName
-gen_tag_n_con_monobind
- :: ( RdrName, -- (proto)Name for the thing in question
- TyCon, -- tycon in question
- TagThingWanted)
- -> LHsBind RdrName
+genAuxBind (DerivAuxBind bind)
+ = bind
-gen_tag_n_con_monobind (rdr_name, tycon, GenCon2Tag)
+genAuxBind (GenCon2Tag tycon)
| lots_of_constructors
= mk_FunBind tycon_loc rdr_name [([], get_tag_rhs)]
= mk_FunBind tycon_loc rdr_name (map mk_stuff (tyConDataCons tycon))
where
+ rdr_name = con2tag_RDR tycon
tycon_loc = getSrcSpan tycon
tvs = map (mkRdrUnqual . getOccName) (tyConTyVars tycon)
mk_stuff con = ([nlWildConPat con],
nlHsLit (HsIntPrim (toInteger ((dataConTag con) - fIRST_TAG))))
-gen_tag_n_con_monobind (rdr_name, tycon, GenTag2Con)
+genAuxBind (GenTag2Con tycon)
= mk_FunBind (getSrcSpan tycon) 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)
+genAuxBind (GenMaxTag tycon)
= mkVarBind (getSrcSpan tycon) 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)
-
\end{code}
%************************************************************************
The main purpose of @tcInstDecl2@ is to return a @HsBinds@ which defines
the dictionary function for this instance declaration. For example
-\begin{verbatim}
+
instance Foo a => Foo [a] where
op1 x = ...
op2 y = ...
-\end{verbatim}
+
might generate something like
-\begin{verbatim}
+
dfun.Foo.List dFoo_a = let op1 x = ...
op2 y = ...
in
Dict [op1, op2]
-\end{verbatim}
HOWEVER, if the instance decl has no context, then it returns a
bigger @HsBinds@ with declarations for each method. For example
-\begin{verbatim}
+
instance Foo [a] where
op1 x = ...
op2 y = ...
-\end{verbatim}
+
might produce
-\begin{verbatim}
+
dfun.Foo.List a = Dict [Foo.op1.List a, Foo.op2.List a]
const.Foo.op1.List a x = ...
const.Foo.op2.List a y = ...
-\end{verbatim}
+
This group may be mutually recursive, because (for example) there may
be no method supplied for op2 in which case we'll get
-\begin{verbatim}
+
const.Foo.op2.List a = default.Foo.op2 (dfun.Foo.List a)
-\end{verbatim}
-that is, the default method applied to the dictionary at this type.
+that is, the default method applied to the dictionary at this type.
What we actually produce in either case is:
AbsBinds [a] [dfun_theta_dicts]
The "maybe" says that we only ask AbsBinds to make global constant methods
if the dfun_theta is empty.
-
For an instance declaration, say,
is the ``Mark Jones optimisation''. The stuff before the "=>" here
is the @dfun_theta@ below.
-First comes the easy case of a non-local instance decl.
-
\begin{code}
tcInstDecl2 :: InstInfo -> TcM (LHsBinds Id)
------------------------
-- Derived newtype instances; surprisingly tricky!
--
--- In the case of a newtype, things are rather easy
-- class Show a => Foo a b where ...
--- newtype T a = MkT (Tree [a]) deriving( Foo Int )
+-- newtype N a = MkN (Tree [a]) deriving( Foo Int )
+--
-- The newtype gives an FC axiom looking like
--- axiom CoT a :: T a :=: Tree [a]
+-- axiom CoN a :: N a :=: Tree [a]
-- (see Note [Newtype coercions] in TyCon for this unusual form of axiom)
--
-- So all need is to generate a binding looking like:
--- dfunFooT :: forall a. (Foo Int (Tree [a], Show (T a)) => Foo Int (T a)
--- dfunFooT = /\a. \(ds:Show (T a)) (df:Foo (Tree [a])).
--- case df `cast` (Foo Int (sym (CoT a))) of
+-- dfunFooT :: forall a. (Foo Int (Tree [a], Show (N a)) => Foo Int (N a)
+-- dfunFooT = /\a. \(ds:Show (N a)) (df:Foo (Tree [a])).
+-- case df `cast` (Foo Int (sym (CoN a))) of
-- Foo _ op1 .. opn -> Foo ds op1 .. opn
--
-- If there are no superclasses, matters are simpler, because we don't need the case
-- see Note [Newtype deriving superclasses] in TcDeriv.lhs
-tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = NewTypeDerived mb_preds })
+tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = NewTypeDerived })
= do { let dfun_id = instanceDFunId ispec
rigid_info = InstSkol
origin = SigOrigin rigid_info
; (tvs, theta, inst_head_ty) <- tcSkolSigType rigid_info inst_ty
-- inst_head_ty is a PredType
- ; inst_loc <- getInstLoc origin
- ; (rep_dict_id : sc_dict_ids, wrap_fn, sc_binds)
- <- make_wrapper inst_loc tvs theta mb_preds
- -- Here, we are relying on the order of dictionary
- -- arguments built by NewTypeDerived in TcDeriv;
- -- namely, that the rep_dict_id comes first
-
; let (cls, cls_inst_tys) = tcSplitDFunHead inst_head_ty
- cls_tycon = classTyCon cls
- the_coercion = make_coercion cls_tycon cls_inst_tys
- coerced_rep_dict = mkHsWrap the_coercion (HsVar rep_dict_id)
-
- ; body <- make_body cls_tycon cls_inst_tys sc_dict_ids coerced_rep_dict
+ (class_tyvars, sc_theta, _, op_items) = classBigSig cls
+ cls_tycon = classTyCon cls
+ sc_theta' = substTheta (zipOpenTvSubst class_tyvars cls_inst_tys) sc_theta
+
+ Just (initial_cls_inst_tys, last_ty) = snocView cls_inst_tys
+ (nt_tycon, tc_args) = tcSplitTyConApp last_ty -- Can't fail
+ rep_ty = newTyConInstRhs nt_tycon tc_args
+
+ rep_pred = mkClassPred cls (initial_cls_inst_tys ++ [rep_ty])
+ -- In our example, rep_pred is (Foo Int (Tree [a]))
+ the_coercion = make_coercion cls_tycon initial_cls_inst_tys nt_tycon tc_args
+ -- Coercion of kind (Foo Int (Tree [a]) ~ Foo Int (N a)
- ; return (sc_binds `snocBag` (noLoc $ VarBind dfun_id $ noLoc $ mkHsWrap wrap_fn body)) }
+ ; inst_loc <- getInstLoc origin
+ ; sc_loc <- getInstLoc InstScOrigin
+ ; dfun_dicts <- newDictBndrs inst_loc theta
+ ; sc_dicts <- newDictBndrs sc_loc sc_theta'
+ ; this_dict <- newDictBndr inst_loc (mkClassPred cls cls_inst_tys)
+ ; rep_dict <- newDictBndr inst_loc rep_pred
+
+ -- Figure out bindings for the superclass context from dfun_dicts
+ -- Don't include this_dict in the 'givens', else
+ -- wanted_sc_insts get bound by just selecting from this_dict!!
+ ; sc_binds <- addErrCtxt superClassCtxt $
+ tcSimplifySuperClasses inst_loc dfun_dicts (rep_dict:sc_dicts)
+
+ ; let coerced_rep_dict = mkHsWrap the_coercion (HsVar (instToId rep_dict))
+
+ ; body <- make_body cls_tycon cls_inst_tys sc_dicts coerced_rep_dict
+ ; let dict_bind = noLoc $ VarBind (instToId this_dict) (noLoc body)
+
+ ; return (unitBag $ noLoc $
+ AbsBinds tvs (map instToId dfun_dicts)
+ [(tvs, dfun_id, instToId this_dict, [])]
+ (dict_bind `consBag` sc_binds)) }
where
-
- -----------------------
- -- make_wrapper
- -- We distinguish two cases:
- -- (a) there is no tyvar abstraction in the dfun, so all dicts are constant,
- -- and the new dict can just be a constant
- -- (mb_preds = Just preds)
- -- (b) there are tyvars, so we must make a dict *fun*
- -- (mb_preds = Nothing)
- -- See the defn of NewTypeDerived for the meaning of mb_preds
- make_wrapper inst_loc tvs theta (Just preds) -- Case (a)
- = ASSERT( null tvs && null theta )
- do { dicts <- newDictBndrs inst_loc preds
- ; sc_binds <- addErrCtxt superClassCtxt $
- tcSimplifySuperClasses inst_loc [] dicts
- -- Use tcSimplifySuperClasses to avoid creating loops, for the
- -- same reason as Note [SUPERCLASS-LOOP 1] in TcSimplify
- ; return (map instToId dicts, idHsWrapper, sc_binds) }
-
- make_wrapper inst_loc tvs theta Nothing -- Case (b)
- = do { dicts <- newDictBndrs inst_loc theta
- ; let dict_ids = map instToId dicts
- ; return (dict_ids, mkWpTyLams tvs <.> mkWpLams dict_ids, emptyBag) }
-
-----------------------
-- make_coercion
-- The inst_head looks like (C s1 .. sm (T a1 .. ak))
-- So we just replace T with CoT, and insert a 'sym'
-- NB: we know that k will be >= arity of CoT, because the latter fully eta-reduced
- make_coercion cls_tycon cls_inst_tys
- | Just (all_tys_but_last, last_ty) <- snocView cls_inst_tys
- , (tycon, tc_args) <- tcSplitTyConApp last_ty -- Should not fail
- , Just co_con <- newTyConCo_maybe tycon
+ make_coercion cls_tycon initial_cls_inst_tys nt_tycon tc_args
+ | Just co_con <- newTyConCo_maybe nt_tycon
, let co = mkSymCoercion (mkTyConApp co_con tc_args)
- = WpCo (mkTyConApp cls_tycon (all_tys_but_last ++ [co]))
+ = WpCo (mkTyConApp cls_tycon (initial_cls_inst_tys ++ [co]))
| otherwise -- The newtype is transparent; no need for a cast
= idHsWrapper
-----------------------
- -- make_body
- -- Two cases; see Note [Newtype deriving superclasses] in TcDeriv.lhs
- -- (a) no superclasses; then we can just use the coerced dict
- -- (b) one or more superclasses; then new need to do the unpack/repack
+ -- (make_body C tys scs coreced_rep_dict)
+ -- returns
+ -- (case coerced_rep_dict of { C _ ops -> C scs ops })
+ -- But if there are no superclasses, it returns just coerced_rep_dict
+ -- See Note [Newtype deriving superclasses] in TcDeriv.lhs
- make_body cls_tycon cls_inst_tys sc_dict_ids coerced_rep_dict
- | null sc_dict_ids -- Case (a)
+ make_body cls_tycon cls_inst_tys sc_dicts coerced_rep_dict
+ | null sc_dicts -- Case (a)
= return coerced_rep_dict
- | otherwise -- Case (b)
+ | otherwise -- Case (b)
= do { op_ids <- newSysLocalIds FSLIT("op") op_tys
; dummy_sc_dict_ids <- newSysLocalIds FSLIT("sc") (map idType sc_dict_ids)
; let the_pat = ConPatOut { pat_con = noLoc cls_data_con, pat_tvs = [],
; return (HsCase (noLoc coerced_rep_dict) $
MatchGroup [the_match] (mkFunTy pat_ty pat_ty)) }
where
+ sc_dict_ids = map instToId sc_dicts
pat_ty = mkTyConApp cls_tycon cls_inst_tys
cls_data_con = head (tyConDataCons cls_tycon)
cls_arg_tys = dataConInstArgTys cls_data_con cls_inst_tys
SourceTyCtxt(..), checkValidTheta, checkFreeness,
checkValidInstHead, checkValidInstance, checkAmbiguity,
checkInstTermination, checkValidTypeInst, checkTyFamFreeness,
- arityErr,
+ validDerivPred, arityErr,
--------------------------------
-- Zonking
(_,dups) = removeDups tcCmpPred theta
-------------------------
+check_pred_ty :: DynFlags -> SourceTyCtxt -> PredType -> TcM ()
check_pred_ty dflags ctxt pred@(ClassP cls tys)
= do { -- Class predicates are valid in all contexts
; checkTc (arity == n_tys) arity_err
check_pred_ty dflags ctxt sty = failWithTc (badPredTyErr sty)
-------------------------
+check_class_pred_tys :: DynFlags -> SourceTyCtxt -> [Type] -> Bool
check_class_pred_tys dflags ctxt tys
= case ctxt of
TypeCtxt -> True -- {-# SPECIALISE instance Eq (T Int) #-} is fine
%************************************************************************
%* *
-\subsection{Checking type instance well-formedness and termination}
+ Checking the context of a derived instance declaration
+%* *
+%************************************************************************
+
+Note [Exotic derived instance contexts]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In a 'derived' instance declaration, we *infer* the context. It's a
+bit unclear what rules we should apply for this; the Haskell report is
+silent. Obviously, constraints like (Eq a) are fine, but what about
+ data T f a = MkT (f a) deriving( Eq )
+where we'd get an Eq (f a) constraint. That's probably fine too.
+
+One could go further: consider
+ data T a b c = MkT (Foo a b c) deriving( Eq )
+ instance (C Int a, Eq b, Eq c) => Eq (Foo a b c)
+
+Notice that this instance (just) satisfies the Paterson termination
+conditions. Then we *could* derive an instance decl like this:
+
+ instance (C Int a, Eq b, Eq c) => Eq (T a b c)
+
+even though there is no instance for (C Int a), because there just
+*might* be an instance for, say, (C Int Bool) at a site where we
+need the equality instance for T's.
+
+However, this seems pretty exotic, and it's quite tricky to allow
+this, and yet give sensible error messages in the (much more common)
+case where we really want that instance decl for C.
+
+So for now we simply require that the derived instance context
+should have only type-variable constraints.
+
+Here is another example:
+ data Fix f = In (f (Fix f)) deriving( Eq )
+Here, if we are prepared to allow -fallow-undecidable-instances we
+could derive the instance
+ instance Eq (f (Fix f)) => Eq (Fix f)
+but this is so delicate that I don't think it should happen inside
+'deriving'. If you want this, write it yourself!
+
+NB: if you want to lift this condition, make sure you still meet the
+termination conditions! If not, the deriving mechanism generates
+larger and larger constraints. Example:
+ data Succ a = S a
+ data Seq a = Cons a (Seq (Succ a)) | Nil deriving Show
+
+Note the lack of a Show instance for Succ. First we'll generate
+ instance (Show (Succ a), Show a) => Show (Seq a)
+and then
+ instance (Show (Succ (Succ a)), Show (Succ a), Show a) => Show (Seq a)
+and so on. Instead we want to complain of no instance for (Show (Succ a)).
+
+The bottom line
+~~~~~~~~~~~~~~~
+Allow constraints which consist only of type variables, with no repeats.
+
+\begin{code}
+validDerivPred :: PredType -> Bool
+validDerivPred (ClassP cls tys) = hasNoDups fvs && sizeTypes tys == length fvs
+ where fvs = fvTypes tys
+validDerivPred otehr = False
+\end{code}
+
+%************************************************************************
+%* *
+ Checking type instance well-formedness and termination
%* *
%************************************************************************
-> TcM ThetaType -- Needed
-- Given instance (wanted) => C inst_ty
-- Simplify 'wanted' as much as possible
--- The inst_ty is needed only for the termination check
tcSimplifyDeriv orig tyvars theta
= do { (tvs, _, tenv) <- tcInstTyVars tyvars
; wanteds <- newDictBndrsO orig (substTheta tenv theta)
; (irreds, _) <- tryHardCheckLoop doc wanteds
- ; let (tv_dicts, others) = partition isTyVarDict irreds
+ ; let (tv_dicts, others) = partition ok irreds
; addNoInstanceErrs others
+ -- See Note [Exotic derived instance contexts] in TcMType
; let rev_env = zipTopTvSubst tvs (mkTyVarTys tyvars)
simpl_theta = substTheta rev_env (map dictPred tv_dicts)
; return simpl_theta }
where
doc = ptext SLIT("deriving classes for a data type")
-\end{code}
-
-Note [Exotic derived instance contexts]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Consider
- data T a b c = MkT (Foo a b c) deriving( Eq )
- instance (C Int a, Eq b, Eq c) => Eq (Foo a b c)
-
-Notice that this instance (just) satisfies the Paterson termination
-conditions. Then we *could* derive an instance decl like this:
-
- instance (C Int a, Eq b, Eq c) => Eq (T a b c)
-even though there is no instance for (C Int a), because there just
-*might* be an instance for, say, (C Int Bool) at a site where we
-need the equality instance for T's.
-
-However, this seems pretty exotic, and it's quite tricky to allow
-this, and yet give sensible error messages in the (much more common)
-case where we really want that instance decl for C.
-
-So for now we simply require that the derived instance context
-should have only type-variable constraints.
-
-Here is another example:
- data Fix f = In (f (Fix f)) deriving( Eq )
-Here, if we are prepared to allow -fallow-undecidable-instances we
-could derive the instance
- instance Eq (f (Fix f)) => Eq (Fix f)
-but this is so delicate that I don't think it should happen inside
-'deriving'. If you want this, write it yourself!
-
-NB: if you want to lift this condition, make sure you still meet the
-termination conditions! If not, the deriving mechanism generates
-larger and larger constraints. Example:
- data Succ a = S a
- data Seq a = Cons a (Seq (Succ a)) | Nil deriving Show
-
-Note the lack of a Show instance for Succ. First we'll generate
- instance (Show (Succ a), Show a) => Show (Seq a)
-and then
- instance (Show (Succ (Succ a)), Show (Succ a), Show a) => Show (Seq a)
-and so on. Instead we want to complain of no instance for (Show (Succ a)).
+ ok dict | isDict dict = validDerivPred (dictPred dict)
+ | otherwise = False
+\end{code}
@tcSimplifyDefault@ just checks class-type constraints, essentially;
isEnumerationTyCon, isGadtSyntaxTyCon, isOpenTyCon,
assocTyConArgPoss_maybe, isTyConAssoc, setTyConArgPoss,
isTupleTyCon, isUnboxedTupleTyCon, isBoxedTupleTyCon, tupleTyConBoxity,
- isRecursiveTyCon, newTyConRep, newTyConRhs, newTyConCo_maybe,
+ isRecursiveTyCon, newTyConRep, newTyConRhs, newTyConEtadRhs, newTyConCo_maybe,
isHiBootTyCon, isSuperKindTyCon,
isCoercionTyCon_maybe, isCoercionTyCon,
isImplicitTyCon,
-- = the representation type of the tycon
-- The free tyvars of this type are the tyConTyVars
- nt_co :: Maybe TyCon, -- The coercion used to create the newtype
+ nt_co :: Maybe TyCon, -- A CoercionTyCon used to create the newtype
-- from the representation
- -- optional for non-recursive newtypes
+ -- Optional for non-recursive newtypes
-- See Note [Newtype coercions]
+ -- Invariant: arity = #tvs in nt_etad_rhs;
+ -- See Note [Newtype eta]
nt_etad_rhs :: ([TyVar], Type) ,
-- The same again, but this time eta-reduced
Note [Newtype coercions]
~~~~~~~~~~~~~~~~~~~~~~~~
-
The NewTyCon field nt_co is a a TyCon (a coercion constructor in fact)
which is used for coercing from the representation type of the
newtype, to the newtype itself. For example,
w2 = w1
And now Lint complains unless Foo T == Foo [], and that requires T==[]
+This point carries over to the newtype coercion, because we need to
+say
+ w2 = w1 `cast` Foo CoT
+
+so the coercion tycon CoT must have
+ kind: T ~ []
+ and arity: 0
+
Note [Indexed data types] (aka data type families)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
newTyConRhs (AlgTyCon {tyConTyVars = tvs, algTcRhs = NewTyCon { nt_rhs = rhs }}) = (tvs, rhs)
newTyConRhs tycon = pprPanic "newTyConRhs" (ppr tycon)
+newTyConEtadRhs :: TyCon -> ([TyVar], Type)
+newTyConEtadRhs (AlgTyCon {algTcRhs = NewTyCon { nt_etad_rhs = tvs_rhs }}) = tvs_rhs
+newTyConEtadRhs tycon = pprPanic "newTyConEtadRhs" (ppr tycon)
+
newTyConRep :: TyCon -> ([TyVar], Type)
newTyConRep (AlgTyCon {tyConTyVars = tvs, algTcRhs = NewTyCon { nt_rep = rep }}) = (tvs, rep)
newTyConRep tycon = pprPanic "newTyConRep" (ppr tycon)
splitNewTyConApp_maybe other = Nothing
newTyConInstRhs :: TyCon -> [Type] -> Type
-newTyConInstRhs tycon tys =
- let (tvs, ty) = newTyConRhs tycon in substTyWith tvs tys ty
+-- Unwrap one 'layer' of newtype
+-- Use the eta'd version if possible
+newTyConInstRhs tycon tys
+ = ASSERT2( equalLength tvs tys1, ppr tycon $$ ppr tys $$ ppr tvs )
+ mkAppTys (substTyWith tvs tys1 ty) tys2
+ where
+ (tvs, ty) = newTyConEtadRhs tycon
+ (tys1, tys2) = splitAtList tvs tys
\end{code}
</row>
<row>
<entry><option>-XStandaloneDeriving</option></entry>
- <entry>Enable standalone deriving.</entry>
+ <entry>Enable <link linkend="stand-alone-deriving">standalone deriving</link>.</entry>
<entry>dynamic</entry>
<entry><option>-XNoStandaloneDeriving</option></entry>
</row>
<row>
<entry><option>-XDeriveDataTypeable</option></entry>
- <entry>Enable deriving for the Data and Typeable classes.</entry>
+ <entry>Enable <link linkend="deriving-typeable">deriving for the Data and Typeable classes</link>.</entry>
<entry>dynamic</entry>
<entry><option>-XNoDeriveDataTypeable</option></entry>
</row>
<row>
+ <entry><option>-XGeneralizedNewtypeDeriving</option></entry>
+ <entry>Enable <link linkend="newtype-deriving">newtype deriving</link>.</entry>
+ <entry>dynamic</entry>
+ <entry><option>-XNoGeneralizedNewtypeDeriving</option></entry>
+ </row>
+ <row>
<entry><option>-XTypeSynonymInstances</option></entry>
<entry>Enable <link linkend="type-synonyms">type synonyms</link>.</entry>
<entry>dynamic</entry>
<entry>dynamic</entry>
<entry><option>-XNoFunctionalDependencies</option></entry>
</row>
- <row>
- <entry><option>-XGeneralizedNewtypeDeriving</option></entry>
- <entry>Enable <link linkend="newtype-deriving">newtype deriving</link>.</entry>
- <entry>dynamic</entry>
- <entry><option>-XNoGeneralizedNewtypeDeriving</option></entry>
- </row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
+</sect1>
<!-- ====================== End of Generalised algebraic data types ======================= -->
+<sect1 id="deriving">
+<title>Extensions to the "deriving" mechanism</title>
+
+<sect2 id="deriving-inferred">
+<title>Inferred context for deriving clauses</title>
+
+<para>
+The Haskell Report is vague about exactly when a <literal>deriving</literal> clause is
+legal. For example:
+<programlisting>
+ data T0 f a = MkT0 a deriving( Eq )
+ data T1 f a = MkT1 (f a) deriving( Eq )
+ data T2 f a = MkT2 (f (f a)) deriving( Eq )
+</programlisting>
+The natural generated <literal>Eq</literal> code would result in these instance declarations:
+<programlisting>
+ instance Eq a => Eq (T0 f a) where ...
+ instance Eq (f a) => Eq (T1 f a) where ...
+ instance Eq (f (f a)) => Eq (T2 f a) where ...
+</programlisting>
+The first of these is obviously fine. The second is still fine, although less obviously.
+The third is not Haskell 98, and risks losing termination of instances.
+</para>
+<para>
+GHC takes a conservative position: it accepts the first two, but not the third. The rule is this:
+each constraint in the inferred instance context must consist only of type variables,
+with no repititions.
+</para>
+<para>
+This rule is applied regardless of flags. If you want a more exotic context, you can write
+it yourself, using the <link linkend="stand-alone-deriving">standalone deriving mechanism</link>.
+</para>
+</sect2>
+
+<sect2 id="stand-alone-deriving">
+<title>Stand-alone deriving declarations</title>
+
+<para>
+GHC now allows stand-alone <literal>deriving</literal> declarations, enabled by <literal>-XStandaloneDeriving</literal>:
+<programlisting>
+ data Foo a = Bar a | Baz String
+
+ deriving instance Eq a => Eq (Foo a)
+</programlisting>
+The syntax is identical to that of an ordinary instance declaration apart from (a) the keyword
+<literal>deriving</literal>, and (b) the absence of the <literal>where</literal> part.
+You must supply a context (in the example the context is <literal>(Eq a)</literal>),
+exactly as you would in an ordinary instance declaration.
+(In contrast the context is inferred in a <literal>deriving</literal> clause
+attached to a data type declaration.) These <literal>deriving instance</literal>
+rules obey the same rules concerning form and termination as ordinary instance declarations,
+controlled by the same flags; see <link linkend="instance-decls"/>. </para>
+
+<para>The stand-alone syntax is generalised for newtypes in exactly the same
+way that ordinary <literal>deriving</literal> clauses are generalised (<xref linkend="newtype-deriving"/>).
+For example:
+<programlisting>
+ newtype Foo a = MkFoo (State Int a)
+
+ deriving instance MonadState Int Foo
+</programlisting>
+GHC always treats the <emphasis>last</emphasis> parameter of the instance
+(<literal>Foo</literal> in this exmample) as the type whose instance is being derived.
+</para>
+
+</sect2>
+
<sect2 id="deriving-typeable">
<title>Deriving clause for classes <literal>Typeable</literal> and <literal>Data</literal></title>
</para>
<para>
GHC extends this list with two more classes that may be automatically derived
-(provided the <option>-fglasgow-exts</option> flag is specified):
+(provided the <option>-XDeriveDataTypeable</option> flag is specified):
<literal>Typeable</literal>, and <literal>Data</literal>. These classes are defined in the library
modules <literal>Data.Typeable</literal> and <literal>Data.Generics</literal> respectively, and the
appropriate class must be in scope before it can be mentioned in the <literal>deriving</literal> clause.
<sect3> <title> Generalising the deriving clause </title>
<para>
-GHC now permits such instances to be derived instead, so one can write
+GHC now permits such instances to be derived instead,
+using the flag <option>-XGeneralizedNewtypeDeriving</option>,
+so one can write
<programlisting>
newtype Dollars = Dollars Int deriving (Eq,Show,Num)
</programlisting>
Notice that, since <literal>Monad</literal> is a constructor class, the
instance is a <emphasis>partial application</emphasis> of the new type, not the
entire left hand side. We can imagine that the type declaration is
-``eta-converted'' to generate the context of the instance
+"eta-converted" to generate the context of the instance
declaration.
</para>
<para>
the standard method is used or the one described here.)
</para>
</sect3>
-
</sect2>
-
-<sect2 id="stand-alone-deriving">
-<title>Stand-alone deriving declarations</title>
-
-<para>
-GHC now allows stand-alone <literal>deriving</literal> declarations, enabled by <literal>-fglasgow-exts</literal>:
-<programlisting>
- data Foo a = Bar a | Baz String
-
- derive instance Eq (Foo a)
-</programlisting>
-The token "<literal>derive</literal>" is a keyword only when followed by "<literal>instance</literal>";
-you can use it as a variable name elsewhere.</para>
-<para>The stand-alone syntax is generalised for newtypes in exactly the same
-way that ordinary <literal>deriving</literal> clauses are generalised (<xref linkend="newtype-deriving"/>).
-For example:
-<programlisting>
- newtype Foo a = MkFoo (State Int a)
-
- derive instance MonadState Int Foo
-</programlisting>
-GHC always treats the <emphasis>last</emphasis> parameter of the instance
-(<literal>Foo</literal> in this exmample) as the type whose instance is being derived.
-</para>
-
-</sect2>
-
</sect1>
<!-- TYPE SYSTEM EXTENSIONS -->
-<sect1 id="other-type-extensions">
-<title>Other type system extensions</title>
+<sect1 id="type-class-extensions">
+<title>Class and instances declarations</title>
<sect2 id="multi-param-type-classes">
<title>Class declarations</title>
</sect2>
+<sect2 id="overloaded-strings">
+<title>Overloaded string literals
+</title>
+
+<para>
+GHC supports <emphasis>overloaded string literals</emphasis>. Normally a
+string literal has type <literal>String</literal>, but with overloaded string
+literals enabled (with <literal>-XOverloadedStrings</literal>)
+ a string literal has type <literal>(IsString a) => a</literal>.
+</para>
+<para>
+This means that the usual string syntax can be used, e.g., for packed strings
+and other variations of string like types. String literals behave very much
+like integer literals, i.e., they can be used in both expressions and patterns.
+If used in a pattern the literal with be replaced by an equality test, in the same
+way as an integer literal is.
+</para>
+<para>
+The class <literal>IsString</literal> is defined as:
+<programlisting>
+class IsString a where
+ fromString :: String -> a
+</programlisting>
+The only predefined instance is the obvious one to make strings work as usual:
+<programlisting>
+instance IsString [Char] where
+ fromString cs = cs
+</programlisting>
+The class <literal>IsString</literal> is not in scope by default. If you want to mention
+it explicitly (for exmaple, to give an instance declaration for it), you can import it
+from module <literal>GHC.Exts</literal>.
+</para>
+<para>
+Haskell's defaulting mechanism is extended to cover string literals, when <option>-XOverloadedStrings</option> is specified.
+Specifically:
+<itemizedlist>
+<listitem><para>
+Each type in a default declaration must be an
+instance of <literal>Num</literal> <emphasis>or</emphasis> of <literal>IsString</literal>.
+</para></listitem>
+
+<listitem><para>
+The standard defaulting rule (<ulink url="http://haskell.org/onlinereport/decls.html#sect4.3.4">Haskell Report, Section 4.3.4</ulink>)
+is extended thus: defaulting applies when all the unresolved constraints involve standard classes
+<emphasis>or</emphasis> <literal>IsString</literal>; and at least one is a numeric class
+<emphasis>or</emphasis> <literal>IsString</literal>.
+</para></listitem>
+</itemizedlist>
+</para>
+<para>
+A small example:
+<programlisting>
+module Main where
+
+import GHC.Exts( IsString(..) )
+
+newtype MyString = MyString String deriving (Eq, Show)
+instance IsString MyString where
+ fromString = MyString
+
+greet :: MyString -> MyString
+greet "hello" = "world"
+greet other = other
+
+main = do
+ print $ greet "hello"
+ print $ greet "fool"
+</programlisting>
+</para>
+<para>
+Note that deriving <literal>Eq</literal> is necessary for the pattern matching
+to work since it gets translated into an equality comparison.
+</para>
+</sect2>
+
+</sect1>
+
+<sect1 id="other-type-extensions">
+<title>Other type system extensions</title>
+
<sect2 id="type-restrictions">
<title>Type signatures</title>
</para>
</sect2>
-<sect2 id="overloaded-strings">
-<title>Overloaded string literals
-</title>
-
-<para>
-GHC supports <emphasis>overloaded string literals</emphasis>. Normally a
-string literal has type <literal>String</literal>, but with overloaded string
-literals enabled (with <literal>-XOverloadedStrings</literal>)
- a string literal has type <literal>(IsString a) => a</literal>.
-</para>
-<para>
-This means that the usual string syntax can be used, e.g., for packed strings
-and other variations of string like types. String literals behave very much
-like integer literals, i.e., they can be used in both expressions and patterns.
-If used in a pattern the literal with be replaced by an equality test, in the same
-way as an integer literal is.
-</para>
-<para>
-The class <literal>IsString</literal> is defined as:
-<programlisting>
-class IsString a where
- fromString :: String -> a
-</programlisting>
-The only predefined instance is the obvious one to make strings work as usual:
-<programlisting>
-instance IsString [Char] where
- fromString cs = cs
-</programlisting>
-The class <literal>IsString</literal> is not in scope by default. If you want to mention
-it explicitly (for exmaple, to give an instance declaration for it), you can import it
-from module <literal>GHC.Exts</literal>.
-</para>
-<para>
-Haskell's defaulting mechanism is extended to cover string literals, when <option>-XOverloadedStrings</option> is specified.
-Specifically:
-<itemizedlist>
-<listitem><para>
-Each type in a default declaration must be an
-instance of <literal>Num</literal> <emphasis>or</emphasis> of <literal>IsString</literal>.
-</para></listitem>
-
-<listitem><para>
-The standard defaulting rule (<ulink url="http://haskell.org/onlinereport/decls.html#sect4.3.4">Haskell Report, Section 4.3.4</ulink>)
-is extended thus: defaulting applies when all the unresolved constraints involve standard classes
-<emphasis>or</emphasis> <literal>IsString</literal>; and at least one is a numeric class
-<emphasis>or</emphasis> <literal>IsString</literal>.
-</para></listitem>
-</itemizedlist>
-</para>
-<para>
-A small example:
-<programlisting>
-module Main where
-
-import GHC.Exts( IsString(..) )
-
-newtype MyString = MyString String deriving (Eq, Show)
-instance IsString MyString where
- fromString = MyString
-
-greet :: MyString -> MyString
-greet "hello" = "world"
-greet other = other
-
-main = do
- print $ greet "hello"
- print $ greet "fool"
-</programlisting>
-</para>
-<para>
-Note that deriving <literal>Eq</literal> is necessary for the pattern matching
-to work since it gets translated into an equality comparison.
-</para>
-</sect2>
-
<sect2 id="type-families">
<title>Type families
</title>