import Util
import ListSetOps
import Outputable
+import FastString
import Bag
\end{code}
%************************************************************************
%* *
-\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
+ -- In this case ds_theta is the list of all the
+ -- constraints needed, such as (Eq [a], Eq a)
+ -- The inference process is to reduce this to a
+ -- simpler form (e.g. Eq a)
+ --
+ -- Right ds => the exact context for the instance is supplied
+ -- by the programmer; it is ds_theta
+
+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]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(See also Trac #1220 for an interesting exchange on newtype
+deriving and 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}
-tcDeriving :: [LTyClDecl Name] -- All type constructors
+tcDeriving :: [LTyClDecl Name] -- All type constructors
+ -> [LInstDecl Name] -- All instance declarations
-> [LDerivDecl Name] -- All stand-alone deriving declarations
- -> TcM ([InstInfo], -- The generated "instance decls"
+ -> TcM ([InstInfo Name], -- The generated "instance decls"
HsValBinds Name) -- Extra generated top-level bindings
-tcDeriving tycl_decls deriv_decls
- = recoverM (returnM ([], emptyValBindsOut)) $
+tcDeriving tycl_decls inst_decls deriv_decls
+ = recoverM (return ([], emptyValBindsOut)) $
do { -- Fish the "deriving"-related information out of the TcEnv
- -- and make the necessary "equations".
- ; (ordinary_eqns, newtype_inst_info) <- makeDerivEqns tycl_decls deriv_decls
+ -- And make the necessary "equations".
+ ; early_specs <- makeDerivSpecs 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
+ ; overlap_flag <- getOverlapFlag
+ ; let (infer_specs, given_specs) = splitEithers early_specs
+ ; insts1 <- mapM (genInst overlap_flag) given_specs
- ; let inst_info = newtype_inst_info ++ ordinary_inst_info
+ ; final_specs <- extendLocalInstEnv (map (iSpec . fst) insts1) $
+ inferInstanceContexts overlap_flag infer_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
- {
-
- -- Generate the generic to/from functions from each type declaration
- ; gen_binds <- mkGenericBinds tycl_decls
-
- -- Rename these extra bindings, discarding warnings about unused bindings etc
- -- Set -fglasgow exts so that we can have type signatures in patterns,
- -- which is used in the generic binds
- ; rn_binds
- <- discardWarnings $ setOptM Opt_GlasgowExts $ 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) }
+ ; insts2 <- mapM (genInst overlap_flag) final_specs
+ ; is_boot <- tcIsHsBoot
+ -- Generate the generic to/from functions from each type declaration
+ ; gen_binds <- mkGenericBinds is_boot
+ ; (inst_info, rn_binds) <- renameDeriv is_boot gen_binds (insts1 ++ insts2)
; dflags <- getDOpts
- ; ioToTcRn (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"
- (ddump_deriving inst_info rn_binds))
+ ; liftIO (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 :: [InstInfo Name] -> HsValBinds Name -> SDoc
ddump_deriving inst_infos extra_binds
= vcat (map pprInstInfoDetails inst_infos) $$ ppr extra_binds
------------------------------------------
-deriveOrdinaryStuff [] -- Short cut
- = returnM ([], emptyLHsBinds)
-
-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
+renameDeriv :: Bool -> LHsBinds RdrName
+ -> [(InstInfo RdrName, DerivAuxBinds)]
+ -> TcM ([InstInfo Name], HsValBinds Name)
+renameDeriv is_boot gen_binds insts
+ | is_boot -- If we are compiling a hs-boot file, don't generate any derived bindings
+ -- The inst-info bindings will all be empty, but it's easier to
+ -- just use rn_inst_info to change the type appropriately
+ = do { rn_inst_infos <- mapM rn_inst_info inst_infos
+ ; return (rn_inst_infos, emptyValBindsOut) }
- -- Generate any extra not-one-inst-decl-specific binds,
- -- notably "con2tag" and/or "tag2con" functions.
- ; extra_binds <- genTaggeryBinds inst_infos
+ | otherwise
+ = discardWarnings $ -- Discard warnings about unused bindings etc
+ do { (rn_gen, dus_gen) <- setOptM Opt_PatternSignatures $ -- Type signatures in patterns
+ -- are used in the generic binds
+ rnTopBinds (ValBindsIn gen_binds [])
+ ; keepAliveSetTc (duDefs dus_gen) -- Mark these guys to be kept alive
+
+ -- Generate and rename any extra not-one-inst-decl-specific binds,
+ -- notably "con2tag" and/or "tag2con" functions.
+ -- Bring those names into scope before renaming the instances themselves
+ ; loc <- getSrcSpanM -- Generic loc for shared bindings
+ ; let aux_binds = listToBag $ map (genAuxBind loc) $
+ rm_dups [] $ concat deriv_aux_binds
+ ; rn_aux_lhs <- rnTopBindsLHS emptyFsEnv (ValBindsIn aux_binds [])
+ ; let aux_names = map unLoc (collectHsValBinders rn_aux_lhs)
+
+ ; bindLocalNames aux_names $
+ do { (rn_aux, _dus) <- rnTopBindsRHS aux_names rn_aux_lhs
+ ; rn_inst_infos <- mapM rn_inst_info inst_infos
+ ; return (rn_inst_infos, rn_aux `plusHsValBinds` rn_gen) } }
- -- Done
- ; returnM (map fst inst_infos,
- unionManyBags (extra_binds : aux_binds_s))
- }
+ where
+ (inst_infos, deriv_aux_binds) = unzip insts
+
+ -- 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
+
+
+ rn_inst_info (InstInfo { iSpec = inst, iBinds = NewTypeDerived })
+ = return (InstInfo { iSpec = inst, iBinds = NewTypeDerived })
+
+ rn_inst_info (InstInfo { iSpec = inst, iBinds = VanillaInst binds sigs })
+ = -- Bring the right type variables into
+ -- scope (yuk), and rename the method binds
+ ASSERT( null sigs )
+ bindLocalNames (map Var.varName tyvars) $
+ do { (rn_binds, _fvs) <- rnMethodBinds clas_nm (\_ -> []) [] binds
+ ; return (InstInfo { iSpec = inst, iBinds = VanillaInst rn_binds [] }) }
+ where
+ (tyvars,_,clas,_) = instanceHead inst
+ clas_nm = className clas
-----------------------------------------
-mkGenericBinds tycl_decls
- = do { tcs <- mapM tcLookupTyCon
- [ tc_name |
- L _ (TyData { tcdLName = L _ tc_name }) <- tycl_decls]
- -- We are only interested in the data type declarations
+mkGenericBinds :: Bool -> TcM (LHsBinds RdrName)
+mkGenericBinds is_boot
+ | is_boot
+ = return emptyBag
+ | otherwise
+ = do { gbl_env <- getGblEnv
+ ; let tcs = typeEnvTyCons (tcg_type_env gbl_env)
; return (unionManyBags [ mkTyConGenericBinds tc |
tc <- tcs, tyConHasGenerics tc ]) }
- -- And then only in the ones whose 'has-generics' flag is on
+ -- We are only interested in the data type declarations,
+ -- and then only in the ones whose 'has-generics' flag is on
+ -- The predicate tyConHasGenerics finds both of these
\end{code}
%************************************************************************
%* *
-\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]
- -> [LDerivDecl Name]
- -> TcM ([DerivEqn], -- Ordinary derivings
- [InstInfo]) -- Special newtype derivings
-
-makeDerivEqns tycl_decls deriv_decls
- = do { eqns1 <- mapM deriveTyData $
- [ (p,d) | d@(L _ (TyData {tcdDerivs = Just preds})) <- tycl_decls
- , p <- preds ]
- ; eqns2 <- mapM deriveStandalone deriv_decls
- ; return ([eqn | (Just eqn, _) <- eqns1 ++ eqns2],
- [inst | (_, Just inst) <- eqns1 ++ eqns2]) }
+makeDerivSpecs :: [LTyClDecl Name]
+ -> [LInstDecl Name]
+ -> [LDerivDecl Name]
+ -> TcM [EarlyDerivSpec]
+
+makeDerivSpecs tycl_decls inst_decls deriv_decls
+ = do { eqns1 <- mapAndRecoverM deriveTyData $
+ extractTyDataPreds tycl_decls ++
+ [ pd -- traverse assoc data families
+ | L _ (InstDecl _ _ _ ats) <- inst_decls
+ , pd <- extractTyDataPreds ats ]
+ ; eqns2 <- mapAndRecoverM deriveStandalone deriv_decls
+ ; 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. derive instance Show T
+-- e.g. deriving instance show a => Show (T a)
-- Rather like tcLocalInstDecl
deriveStandalone (L loc (DerivDecl deriv_ty))
= setSrcSpan loc $
addErrCtxt (standaloneCtxt deriv_ty) $
- do { (tvs, theta, tau) <- tcHsInstHead deriv_ty
- ; (cls, inst_tys) <- checkValidInstHead tau
- ; let cls_tys = take (length inst_tys - 1) inst_tys
- inst_ty = last inst_tys
-
- ; mkEqnHelp StandAloneDerivOrigin tvs cls cls_tys inst_ty }
+ do { traceTc (text "standalone deriving decl for" <+> ppr deriv_ty)
+ ; (tvs, theta, tau) <- tcHsInstHead deriv_ty
+ ; traceTc (text "standalone deriving;"
+ <+> text "tvs:" <+> ppr tvs
+ <+> text "theta:" <+> ppr theta
+ <+> text "tau:" <+> ppr tau)
+ ; (cls, inst_tys) <- checkValidInstHead tau
+ ; checkValidInstance tvs theta cls inst_tys
+ -- C.f. TcInstDcls.tcLocalInstDecl1
+
+ ; let cls_tys = take (length inst_tys - 1) inst_tys
+ inst_ty = last inst_tys
+ ; traceTc (text "standalone deriving;"
+ <+> text "class:" <+> ppr cls
+ <+> text "class types:" <+> ppr cls_tys
+ <+> text "type:" <+> ppr inst_ty)
+ ; mkEqnHelp StandAloneDerivOrigin tvs cls cls_tys inst_ty
+ (Just theta) }
------------------------------------------------------------------
-deriveTyData :: (LHsType Name, LTyClDecl Name) -> TcM (Maybe DerivEqn, Maybe InstInfo)
-deriveTyData (deriv_pred, L loc decl@(TyData { tcdLName = L _ tycon_name,
- tcdTyVars = tv_names,
- tcdTyPats = ty_pats }))
- = setSrcSpan loc $
- tcAddDeclCtxt decl $
+deriveTyData :: (LHsType Name, LTyClDecl Name) -> TcM (Maybe EarlyDerivSpec)
+deriveTyData (L loc deriv_pred, L _ decl@(TyData { tcdLName = L _ tycon_name,
+ tcdTyVars = tv_names,
+ tcdTyPats = ty_pats }))
+ = setSrcSpan loc $ -- Use the location of the 'deriving' item
+ tcAddDeclCtxt decl $
do { let hs_ty_args = ty_pats `orElse` map (nlHsTyVar . hsLTyVarName) tv_names
hs_app = nlHsTyConApp tycon_name hs_ty_args
-- We get kinding info for the tyvars by typechecking (T a b)
do { (deriv_tvs, cls, cls_tys) <- tcHsDeriv deriv_pred
-- 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 } }
+ ; mkEqnHelp DerivOrigin (tvs++deriv_tvs) cls cls_tys tc_app Nothing } }
+
+deriveTyData _other
+ = panic "derivTyData" -- Caller ensures that only TyData can happen
------------------------------------------------------------------
-mkEqnHelp orig tvs cls cls_tys tc_app
+mkEqnHelp :: InstOrigin -> [TyVar] -> Class -> [Type] -> Type
+ -> Maybe ThetaType -- Just => context supplied (standalone deriving)
+ -- Nothing => context inferred (deriving on data decl)
+ -> 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
- -- mkDataTypeEqn things expect
- -- It might not be saturated in the standalone deriving case
- -- derive instance Monad (T a)
- let extra_tvs = dropList tc_args (tyConTyVars tycon)
- full_tc_args = tc_args ++ mkTyVarTys extra_tvs
- full_tvs = tvs ++ extra_tvs
-
- ; (rep_tc, rep_tc_args) <- tcLookupFamInst tycon full_tc_args
-
- ; gla_exts <- doptM Opt_GlasgowExts
- ; overlap_flag <- getOverlapFlag
- ; if isDataTyCon tycon then
- mkDataTypeEqn orig gla_exts full_tvs cls cls_tys
- tycon full_tc_args rep_tc rep_tc_args
+ , isAlgTyCon tycon -- Check for functions, primitive types etc
+ = do { (rep_tc, rep_tc_args) <- tcLookupFamInstExact tycon tc_args
+ -- Be careful to test rep_tc here: in the case of families,
+ -- we want to check the instance tycon, not the family tycon
+
+ -- For standalone deriving (mtheta /= Nothing),
+ -- check that all the data constructors are in scope
+ -- By this time we know that the thing is algebraic
+ -- because we've called checkInstHead in derivingStandalone
+ ; rdr_env <- getGlobalRdrEnv
+ ; let hidden_data_cons = isAbstractTyCon rep_tc || any not_in_scope (tyConDataCons rep_tc)
+ not_in_scope dc = null (lookupGRE_Name rdr_env (dataConName dc))
+ ; checkTc (isNothing mtheta || not hidden_data_cons)
+ (derivingHiddenErr tycon)
+
+ ; mayDeriveDataTypeable <- doptM Opt_DeriveDataTypeable
+ ; newtype_deriving <- doptM Opt_GeneralizedNewtypeDeriving
+
+ ; if isDataTyCon rep_tc then
+ mkDataTypeEqn orig mayDeriveDataTypeable tvs cls cls_tys
+ tycon tc_args rep_tc rep_tc_args mtheta
else
- mkNewTypeEqn orig gla_exts overlap_flag full_tvs cls cls_tys
- tycon full_tc_args rep_tc rep_tc_args }
+ mkNewTypeEqn orig mayDeriveDataTypeable newtype_deriving
+ tvs cls cls_tys
+ tycon 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")))
+ (ptext (sLit "The last argument of the instance must be a data or newtype application")))
+
+baleOut :: Message -> TcM (Maybe a)
+baleOut err = do { addErrTc err; return Nothing }
+\end{code}
-baleOut err = addErrTc err >> returnM (Nothing, Nothing)
+Note [Looking up family instances for deriving]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+tcLookupFamInstExact is an auxiliary lookup wrapper which requires
+that looked-up family instances exist. If called with a vanilla
+tycon, the old type application is simply returned.
+
+If we have
+ data instance F () = ... deriving Eq
+ data instance F () = ... deriving Eq
+then tcLookupFamInstExact will be confused by the two matches;
+but that can't happen because tcInstDecls1 doesn't call tcDeriving
+if there are any overlaps.
+
+There are two other things that might go wrong with the lookup.
+First, we might see a standalone deriving clause
+ deriving Eq (F ())
+when there is no data instance F () in scope.
+
+Note that it's OK to have
+ data instance F [a] = ...
+ deriving Eq (F [(a,b)])
+where the match is not exact; the same holds for ordinary data types
+with standalone deriving declrations.
+
+\begin{code}
+tcLookupFamInstExact :: TyCon -> [Type] -> TcM (TyCon, [Type])
+tcLookupFamInstExact tycon tys
+ | not (isOpenTyCon tycon)
+ = return (tycon, tys)
+ | otherwise
+ = do { maybeFamInst <- tcLookupFamInst tycon tys
+ ; case maybeFamInst of
+ Nothing -> famInstNotFound tycon tys
+ Just famInst -> return famInst
+ }
+
+famInstNotFound :: TyCon -> [Type] -> TcM a
+famInstNotFound tycon tys
+ = failWithTc (ptext (sLit "No family instance for")
+ <+> quotes (pprTypeApp tycon (ppr tycon) tys))
\end{code}
%************************************************************************
\begin{code}
-mkDataTypeEqn orig gla_exts tvs cls cls_tys tycon tc_args rep_tc rep_tc_args
- | Just err <- checkSideConditions gla_exts cls cls_tys rep_tc
+mkDataTypeEqn :: InstOrigin -> Bool -> [Var] -> Class -> [Type]
+ -> 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
-- NB: pass the *representation* tycon to checkSideConditions
= baleOut (derivingThingErr cls cls_tys (mkTyConApp tycon tc_args) err)
| otherwise
= ASSERT( null cls_tys )
- do { loc <- getSrcSpanM
- ; eqn <- mk_data_eqn loc orig tvs cls tycon tc_args rep_tc rep_tc_args
- ; return (Just eqn, Nothing) }
-
-mk_data_eqn :: SrcSpan -> InstOrigin -> [TyVar] -> Class
- -> TyCon -> [TcType] -> TyCon -> [TcType] -> TcM DerivEqn
-mk_data_eqn loc orig tvs cls tycon tc_args rep_tc rep_tc_args
- | cls `hasKey` typeableClassKey
- = -- The Typeable class is special in several ways
- -- data T a b = ... deriving( Typeable )
- -- gives
- -- instance Typeable2 T where ...
- -- Notice that:
- -- 1. There are no constraints in the instance
- -- 2. There are no type variables either
- -- 3. The actual class we want to generate isn't necessarily
- -- Typeable; it depends on the arity of the type
- do { real_clas <- tcLookupClass (typeableClassNames !! tyConArity tycon)
- ; dfun_name <- new_dfun_name real_clas tycon
- ; return (loc, orig, dfun_name, [], real_clas, mkTyConApp tycon [], []) }
+ mk_data_eqn orig tvs cls tycon tc_args rep_tc rep_tc_args mtheta
+
+mk_data_eqn, mk_typeable_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
+ | getName cls `elem` typeableClassNames
+ = mk_typeable_eqn orig tvs cls tycon tc_args rep_tc rep_tc_args mtheta
| 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 <- dataConInstOrigArgTys data_con rep_tc_args,
+ arg_ty <- ASSERT( isVanillaDataCon data_con )
+ dataConInstOrigArgTys data_con rep_tc_args,
not (isUnLiftedType arg_ty) ] -- No constraints for unlifted types?
- tiresome_subst = zipTopTvSubst (tyConTyVars rep_tc) rep_tc_args
- stupid_constraints = substTheta tiresome_subst (tyConStupidTheta rep_tc)
- -- see note [Data decl contexts] above
+ -- See Note [Superclasses of derived instance]
+ sc_constraints = substTheta (zipOpenTvSubst (classTyVars cls) inst_tys)
+ (classSCTheta cls)
+ inst_tys = [mkTyConApp tycon tc_args]
+
+ stupid_subst = zipTopTvSubst (tyConTyVars rep_tc) rep_tc_args
+ stupid_constraints = substTheta stupid_subst (tyConStupidTheta rep_tc)
+ all_constraints = stupid_constraints ++ sc_constraints ++ ordinary_constraints
+
+ spec = DS { ds_loc = loc, ds_orig = orig
+ , ds_name = dfun_name, ds_tvs = tvs
+ , ds_cls = cls, ds_tys = inst_tys
+ , ds_theta = mtheta `orElse` all_constraints
+ , ds_newtype = False }
- ; return (loc, orig, dfun_name, tvs, cls, mkTyConApp tycon tc_args,
- stupid_constraints ++ ordinary_constraints)
- }
+ ; return (if isJust mtheta then Just (Right spec) -- Specified context
+ else Just (Left spec)) } -- Infer context
+
+mk_typeable_eqn orig tvs cls tycon tc_args rep_tc _rep_tc_args mtheta
+ -- The Typeable class is special in several ways
+ -- data T a b = ... deriving( Typeable )
+ -- gives
+ -- instance Typeable2 T where ...
+ -- Notice that:
+ -- 1. There are no constraints in the instance
+ -- 2. There are no type variables either
+ -- 3. The actual class we want to generate isn't necessarily
+ -- Typeable; it depends on the arity of the type
+ | isNothing mtheta -- deriving on a data type decl
+ = do { checkTc (cls `hasKey` typeableClassKey)
+ (ptext (sLit "Use deriving( Typeable ) on a data type declaration"))
+ ; real_cls <- tcLookupClass (typeableClassNames !! tyConArity tycon)
+ ; mk_typeable_eqn orig tvs real_cls tycon [] rep_tc [] (Just []) }
+
+ | otherwise -- standaone deriving
+ = do { checkTc (null tc_args)
+ (ptext (sLit "Derived typeable instance must be of form (Typeable")
+ <> int (tyConArity tycon) <+> ppr tycon <> rparen)
+ ; dfun_name <- new_dfun_name cls tycon
+ ; loc <- getSrcSpanM
+ ; return (Just $ Right $
+ DS { ds_loc = loc, ds_orig = orig, ds_name = dfun_name, ds_tvs = []
+ , ds_cls = cls, ds_tys = [mkTyConApp tycon []]
+ , ds_theta = mtheta `orElse` [], ds_newtype = False }) }
------------------------------------------------------------------
-- Check side conditions that dis-allow derivability for particular classes
-- family tycon (with indexes) in error messages.
checkSideConditions :: Bool -> Class -> [TcType] -> TyCon -> Maybe SDoc
-checkSideConditions gla_exts cls cls_tys rep_tc
+checkSideConditions mayDeriveDataTypeable cls cls_tys rep_tc
| notNull cls_tys
= Just ty_args_why -- e.g. deriving( Foo s )
| otherwise
- = case [cond | (key,cond) <- sideConditions, key == getUnique cls] of
- [] -> Just (non_std_why cls)
- [cond] -> cond (gla_exts, rep_tc)
- other -> pprPanic "checkSideConditions" (ppr cls)
+ = case sideConditions cls of
+ Just cond -> cond (mayDeriveDataTypeable, rep_tc)
+ Nothing -> Just non_std_why
+ where
+ ty_args_why = quotes (ppr (mkClassPred cls cls_tys)) <+> ptext (sLit "is not a class")
+ non_std_why = quotes (ppr cls) <+> ptext (sLit "is not a derivable class")
+
+sideConditions :: Class -> Maybe Condition
+sideConditions cls
+ | cls_key == eqClassKey = Just cond_std
+ | cls_key == ordClassKey = Just cond_std
+ | cls_key == readClassKey = Just cond_std
+ | cls_key == showClassKey = Just cond_std
+ | cls_key == enumClassKey = Just (cond_std `andCond` cond_isEnumeration)
+ | cls_key == ixClassKey = Just (cond_std `andCond` (cond_isEnumeration `orCond` cond_isProduct))
+ | cls_key == boundedClassKey = Just (cond_std `andCond` (cond_isEnumeration `orCond` cond_isProduct))
+ | cls_key == dataClassKey = Just (cond_mayDeriveDataTypeable `andCond` cond_std)
+ | getName cls `elem` typeableClassNames = Just (cond_mayDeriveDataTypeable `andCond` cond_typeableOK)
+ | otherwise = Nothing
where
- ty_args_why = quotes (ppr (mkClassPred cls cls_tys)) <+> ptext SLIT("is not a class")
-
-non_std_why cls = quotes (ppr cls) <+> ptext SLIT("is not a derivable class")
-
-sideConditions :: [(Unique, Condition)]
-sideConditions
- = [ (eqClassKey, cond_std),
- (ordClassKey, cond_std),
- (readClassKey, cond_std),
- (showClassKey, cond_std),
- (enumClassKey, cond_std `andCond` cond_isEnumeration),
- (ixClassKey, cond_std `andCond` (cond_isEnumeration `orCond` cond_isProduct)),
- (boundedClassKey, cond_std `andCond` (cond_isEnumeration `orCond` cond_isProduct)),
- (typeableClassKey, cond_glaExts `andCond` cond_typeableOK),
- (dataClassKey, cond_glaExts `andCond` cond_std)
- ]
+ cls_key = getUnique cls
type Condition = (Bool, TyCon) -> Maybe SDoc
- -- Bool is gla-exts flag
+ -- Bool is whether or not we are allowed to derive Data and Typeable
-- TyCon is the *representation* tycon if the
-- data type is an indexed one
-- Nothing => OK
Nothing -> Nothing -- c1 succeeds
Just x -> case c2 tc of -- c1 fails
Nothing -> Nothing
- Just y -> Just (x $$ ptext SLIT(" and") $$ y)
+ 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
cond_std :: Condition
-cond_std (gla_exts, rep_tc)
+cond_std (_, rep_tc)
| any (not . isVanillaDataCon) data_cons = Just existential_why
| null data_cons = Just no_cons_why
| otherwise = Nothing
where
data_cons = tyConDataCons rep_tc
no_cons_why = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has no data constructors")
+ ptext (sLit "has no data constructors")
existential_why = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has non-Haskell-98 constructor(s)")
+ ptext (sLit "has non-Haskell-98 constructor(s)")
cond_isEnumeration :: Condition
-cond_isEnumeration (gla_exts, rep_tc)
+cond_isEnumeration (_, rep_tc)
| isEnumerationTyCon rep_tc = Nothing
| otherwise = Just why
where
why = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has non-nullary constructors")
+ ptext (sLit "has non-nullary constructors")
cond_isProduct :: Condition
-cond_isProduct (gla_exts, rep_tc)
+cond_isProduct (_, rep_tc)
| isProductTyCon rep_tc = Nothing
| otherwise = Just why
where
- why = (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has more than one constructor")
+ why = quotes (pprSourceTyCon rep_tc) <+>
+ ptext (sLit "has more than one constructor")
cond_typeableOK :: Condition
-- OK for Typeable class
-- Currently: (a) args all of kind *
-- (b) 7 or fewer args
-cond_typeableOK (gla_exts, rep_tc)
+cond_typeableOK (_, rep_tc)
| tyConArity rep_tc > 7 = Just too_many
| not (all (isSubArgTypeKind . tyVarKind) (tyConTyVars rep_tc))
= Just bad_kind
| otherwise = Nothing
where
too_many = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has too many arguments")
+ ptext (sLit "has too many arguments")
bad_kind = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("has arguments of kind other than `*'")
+ ptext (sLit "has arguments of kind other than `*'")
fam_inst = quotes (pprSourceTyCon rep_tc) <+>
- ptext SLIT("is a type family")
+ ptext (sLit "is a type family")
-cond_glaExts :: Condition
-cond_glaExts (gla_exts, _rep_tc) | gla_exts = Nothing
- | otherwise = Just why
+cond_mayDeriveDataTypeable :: Condition
+cond_mayDeriveDataTypeable (mayDeriveDataTypeable, _)
+ | mayDeriveDataTypeable = Nothing
+ | otherwise = Just why
where
- why = ptext SLIT("You need -fglasgow-exts to derive an instance for this class")
+ why = ptext (sLit "You need -XDeriveDataTypeable to derive an instance for this class")
-std_class gla_exts clas
- = key `elem` derivableClassKeys
- || (gla_exts && (key == typeableClassKey || key == dataClassKey))
- where
- key = classKey clas
-
+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 Read/Show because they respect the type
- -- Not Enum, becuase newtypes are never in Enum
+ -- 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 []] (getSrcLoc tycon)
+ = do { loc <- getSrcSpanM -- The location of the instance decl, not of the tycon
+ ; newDFunName clas [mkTyConApp tycon []] loc }
-- The type passed to newDFunName is only used to generate
-- a suitable string; hence the empty type arg list
\end{code}
+Note [Superclasses of derived instance]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In general, a derived instance decl needs the superclasses of the derived
+class too. So if we have
+ data T a = ...deriving( Ord )
+then the initial context for Ord (T a) should include Eq (T a). Often this is
+redundant; we'll also generate an Ord constraint for each constructor argument,
+and that will probably generate enough constraints to make the Eq (T a) constraint
+be satisfied too. But not always; consider:
+
+ data S a = S
+ instance Eq (S a)
+ instance Ord (S a)
+
+ data T a = MkT (S a) deriving( Ord )
+ instance Num a => Eq (T a)
+
+The derived instance for (Ord (T a)) must have a (Num a) constraint!
+Similarly consider:
+ data T a = MkT deriving( Data, Typeable )
+Here there *is* no argument field, but we must nevertheless generate
+a context for the Data instances:
+ instance Typable a => Data (T a) where ...
+
%************************************************************************
%* *
%************************************************************************
\begin{code}
-mkNewTypeEqn orig gla_exts overlap_flag tvs cls cls_tys
- tycon tc_args
- rep_tycon rep_tc_args
- | can_derive_via_isomorphism && (gla_exts || 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 })) }
- | std_class gla_exts cls
- = mkDataTypeEqn orig gla_exts tvs cls cls_tys tycon tc_args rep_tycon rep_tc_args -- Go via bale-out route
-
- -- Otherwise its a non-standard instance
- | gla_exts = baleOut cant_derive_err -- Too hard
- | otherwise = baleOut non_std_err -- Just complain about being a non-std instance
+mkNewTypeEqn :: InstOrigin -> Bool -> Bool -> [Var] -> Class
+ -> [Type] -> TyCon -> [Type] -> TyCon -> [Type]
+ -> 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)
+ ; 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
+ = 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
where
+ mb_std_err = checkSideConditions mayDeriveDataTypeable cls cls_tys rep_tycon
+ std_err = derivingThingErr cls cls_tys tc_app $
+ vcat [fromJust mb_std_err,
+ ptext (sLit "Try -XGeneralizedNewtypeDeriving for GHC's newtype-deriving extension")]
+
-- Here is the plan for newtype derivings. We see
-- newtype T a1...an = MkT (t ak+1...an) deriving (.., C s1 .. sm, ...)
-- where t is a type,
-- Want to drop 1 arg from (T s a) and (ST s a)
-- to get instance Monad (ST s) => Monad (T s)
- -- Note [newtype representation]
- -- Need newTyConRhs *not* newTyConRep to get the representation
- -- type, because the latter looks through all intermediate newtypes
- -- For example
+ -- Note [Newtype representation]
+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ -- Need newTyConRhs (*not* a recursive representation finder)
+ -- to get the representation type. For example
-- newtype B = MkB Int
-- newtype A = MkA B deriving( Num )
-- We want the Num instance of B, *not* the Num instance of Int,
-- 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
right_arity = length cls_tys + 1 == classArity cls
-- Never derive Read,Show,Typeable,Data this way
- non_iso_classes = [readClassKey, showClassKey, typeableClassKey, dataClassKey]
+ non_iso_class cls = className cls `elem` ([readClassName, showClassName, dataClassName] ++
+ typeableClassNames)
can_derive_via_isomorphism
- = not (getUnique cls `elem` non_iso_classes)
+ = not (non_iso_class cls)
&& right_arity -- Well kinded;
-- eg not: newtype T ... deriving( ST )
-- because ST needs *2* type params
-- arguments must be type variables (not more complex indexes)
cant_derive_err = derivingThingErr cls cls_tys tc_app
- (vcat [ptext SLIT("even with cunning newtype deriving:"),
+ (vcat [ptext (sLit "even with cunning newtype deriving:"),
if isRecursiveTyCon tycon then
- ptext SLIT("the newtype is recursive")
+ ptext (sLit "the newtype may be recursive")
else empty,
if not right_arity then
- quotes (ppr (mkClassPred cls cls_tys)) <+> ptext SLIT("does not have arity 1")
+ quotes (ppr (mkClassPred cls cls_tys)) <+> ptext (sLit "does not have arity 1")
else empty,
if not (n_tyargs_to_keep >= 0) then
- ptext SLIT("the type constructor has wrong kind")
+ ptext (sLit "the type constructor has wrong kind")
else if not (n_args_to_keep >= 0) then
- ptext SLIT("the representation type has wrong kind")
+ ptext (sLit "the representation type has wrong kind")
else if not eta_ok then
- ptext SLIT("the eta-reduction property does not hold")
+ ptext (sLit "the eta-reduction property does not hold")
else empty
])
-
- non_std_err = derivingThingErr cls cls_tys tc_app
- (vcat [non_std_why cls,
- ptext SLIT("Try -fglasgow-exts for GHC's newtype-deriving extension")])
\end{code}
\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
+ -- This can happen if we have -XUndecidableInstances
-- (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_tys) $
do { theta <- tcSimplifyDeriv orig tyvars deriv_rhs
- ; addErrCtxt (derivInstCtxt theta clas [inst_ty]) $
- do { checkNoErrs (checkValidInstance tyvars theta clas [inst_ty])
- -- See Note [Deriving context]
- -- If this fails, don't continue
+ -- checkValidInstance tyvars theta clas inst_tys
+ -- Not necessary; see Note [Exotic derived instance contexts]
+ -- in TcSimplify
-- Check for a bizarre corner case, when the derived instance decl should
-- have form instance C a b => D (T a) where ...
-- Claim: the result instance declaration is guaranteed valid
-- Hence no need to call:
-- checkValidInstance tyvars theta clas inst_tys
- ; return (sortLe (<=) theta) } } -- Canonicalise before returning the solution
+ ; return (sortLe (<=) theta) } -- Canonicalise before returning the solution
+
+------------------------------------------------------------------
+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
- ------------------------------------------------------------------
- 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]
extendLocalInstEnv :: [Instance] -> TcM a -> TcM a
-- Add new locally-defined instances; don't bother to check
; setGblEnv env' thing_inside }
\end{code}
+
%************************************************************************
%* *
\subsection[TcDeriv-normal-binds]{Bindings for the various classes}
-- 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
- = do { fix_env <- getFixityEnv
- ; let
- (tyvars,_,clas,[ty]) = instanceHead spec
- clas_nm = className clas
- (visible_tycon, tyArgs) = tcSplitTyConApp ty
+genInst :: OverlapFlag -> DerivSpec -> TcM (InstInfo RdrName, DerivAuxBinds)
+genInst oflag spec
+ | ds_newtype spec
+ = return (InstInfo { iSpec = mkInstance1 oflag spec
+ , iBinds = NewTypeDerived }, [])
+
+ | otherwise
+ = do { let loc = getSrcSpan (ds_name spec)
+ inst = mkInstance1 oflag spec
+ (_,_,clas,[ty]) = instanceHead inst
+ (visible_tycon, tyArgs) = tcSplitTyConApp ty
-- In case of a family instance, we need to use the representation
-- tycon (after all, it has the data constructors)
- ; (tycon, _) <- tcLookupFamInst visible_tycon tyArgs
- ; let (meth_binds, aux_binds) = genDerivBinds clas fix_env tycon
-
- -- Bring the right type variables into
- -- scope, and rename the method binds
- -- It's a bit yukky that we return *renamed* InstInfo, but
- -- *non-renamed* auxiliary bindings
- ; (rn_meth_binds, _fvs) <- discardWarnings $
- bindLocalNames (map Var.varName tyvars) $
- rnMethodBinds clas_nm (\n -> []) [] meth_binds
+ ; (tycon, _) <- tcLookupFamInstExact visible_tycon tyArgs
+ ; fix_env <- getFixityEnv
+ ; let (meth_binds, aux_binds) = genDerivBinds loc fix_env clas tycon
-- Build the InstInfo
- ; return ((InstInfo { iSpec = spec,
- iBinds = VanillaInst rn_meth_binds [] }, tycon),
+ ; return (InstInfo { iSpec = inst,
+ iBinds = VanillaInst meth_binds [] },
aux_binds)
}
-genDerivBinds clas fix_env tycon
+genDerivBinds :: SrcSpan -> FixityEnv -> Class -> TyCon -> (LHsBinds RdrName, DerivAuxBinds)
+genDerivBinds loc fix_env clas tycon
| className clas `elem` typeableClassNames
- = (gen_Typeable_binds tycon, emptyLHsBinds)
+ = (gen_Typeable_binds loc tycon, [])
| otherwise
= case assocMaybe gen_list (getUnique clas) of
- Just gen_fn -> gen_fn fix_env tycon
+ Just gen_fn -> gen_fn loc 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, SrcSpan -> 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)
]
-
- -- 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"),
+ = sep [hsep [ptext (sLit "Can't make a derived instance of"),
quotes (ppr pred)],
nest 2 (parens why)]
where
pred = mkClassPred clas (tys ++ [ty])
+derivingHiddenErr :: TyCon -> SDoc
+derivingHiddenErr tc
+ = hang (ptext (sLit "The data constructors of") <+> quotes (ppr tc) <+> ptext (sLit "are not all in scope"))
+ 2 (ptext (sLit "so you cannot derive an instance for it"))
+
standaloneCtxt :: LHsType Name -> SDoc
-standaloneCtxt ty = ptext SLIT("In the stand-alone deriving instance for") <+> quotes (ppr ty)
+standaloneCtxt ty = hang (ptext (sLit "In the stand-alone deriving instance for"))
+ 2 (quotes (ppr ty))
-derivInstCtxt theta clas inst_tys
- = hang (ptext SLIT("In the derived instance:"))
- 2 (pprThetaArrow theta <+> pprClassPred clas inst_tys)
--- Used for the ...Thetas variants; all top level
+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)]
+ = 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)]
\end{code}
-