import CmdLineOpts ( DynFlag(..) )
import TcRnMonad
-import TcEnv ( tcGetInstEnv, tcSetInstEnv, newDFunName,
+import TcEnv ( tcExtendTempInstEnv, newDFunName,
InstInfo(..), pprInstInfo, InstBindings(..),
pprInstInfoDetails, tcLookupTyCon, tcExtendTyVarEnv
)
import TcGenDeriv -- Deriv stuff
-import InstEnv ( InstEnv, simpleDFunClassTyCon, extendInstEnv )
+import InstEnv ( simpleDFunClassTyCon )
import TcMonoType ( tcHsPred )
import TcSimplify ( tcSimplifyDeriv )
import RnBinds ( rnMethodBinds, rnTopMonoBinds )
-import RnEnv ( bindLocalsFVRn )
-import TcRnMonad ( thenM, returnM, mapAndUnzipM )
+import RnEnv ( bindLocalsFV )
+import TcRnMonad ( thenM, returnM, mapAndUnzipM )
import HscTypes ( DFunId )
import BasicTypes ( NewOrData(..) )
-import Class ( className, classKey, classTyVars, classSCTheta, Class )
+import Class ( className, classArity, classKey, classTyVars, classSCTheta, Class )
import Subst ( mkTyVarSubst, substTheta )
import ErrUtils ( dumpIfSet_dyn )
import MkId ( mkDictFunId )
-import DataCon ( dataConRepArgTys, isNullaryDataCon, isExistentialDataCon )
+import DataCon ( dataConOrigArgTys, isNullaryDataCon, isExistentialDataCon )
import Maybes ( maybeToBool, catMaybes )
import Name ( Name, getSrcLoc, nameUnique )
import NameSet
import RdrName ( RdrName )
-import TyCon ( tyConTyVars, tyConDataCons, tyConArity, newTyConRep,
+import TyCon ( tyConTyVars, tyConDataCons, tyConArity,
tyConTheta, maybeTyConSingleCon, isDataTyCon,
isEnumerationTyCon, isRecursiveTyCon, TyCon
)
import TcType ( TcType, ThetaType, mkTyVarTys, mkTyConApp, getClassPredTys_maybe,
isUnLiftedType, mkClassPred, tyVarsOfTypes, tcSplitFunTys,
- tcEqTypes, mkAppTys )
-import Type ( splitAppTys )
+ tcEqTypes, tcSplitAppTys, mkAppTys )
import Var ( TyVar, tyVarKind )
import VarSet ( mkVarSet, subVarSet )
import PrelNames
tcDeriving tycl_decls
= recoverM (returnM ([], EmptyBinds, emptyFVs)) $
getDOpts `thenM` \ dflags ->
- tcGetInstEnv `thenM` \ inst_env ->
-- Fish the "deriving"-related information out of the TcEnv
-- and make the necessary "equations".
makeDerivEqns tycl_decls `thenM` \ (ordinary_eqns, newtype_inst_info) ->
- let
+ tcExtendTempInstEnv (map iDFunId newtype_inst_info) $
-- Add the newtype-derived instances to the inst env
-- before tacking the "ordinary" ones
- inst_env1 = extend_inst_env dflags inst_env
- (map iDFunId newtype_inst_info)
- in
- deriveOrdinaryStuff inst_env1 ordinary_eqns `thenM` \ (ordinary_inst_info, binds, fvs) ->
+
+ deriveOrdinaryStuff ordinary_eqns `thenM` \ (ordinary_inst_info, binds, fvs) ->
let
inst_info = newtype_inst_info ++ ordinary_inst_info
in
-- pprInstInfo doesn't print much: only the type
-----------------------------------------
-deriveOrdinaryStuff inst_env_in [] -- Short cut
+deriveOrdinaryStuff [] -- Short cut
= returnM ([], EmptyBinds, emptyFVs)
-deriveOrdinaryStuff inst_env_in eqns
+deriveOrdinaryStuff eqns
= -- 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.
- solveDerivEqns inst_env_in eqns `thenM` \ new_dfuns ->
+ solveDerivEqns eqns `thenM` \ new_dfuns ->
-- Now augment the InstInfos, adding in the rather boring
-- actual-code-to-do-the-methods binds. We may also need to
-- Rename to get RenamedBinds.
-- The only tricky bit is that the extra_binds must scope
-- over the method bindings for the instances.
- bindLocalsFVRn (ptext (SLIT("deriving"))) mbinders $ \ _ ->
- rnTopMonoBinds extra_mbinds [] `thenM` \ (rn_extra_binds, fvs) ->
+ bindLocalsFV (ptext (SLIT("deriving"))) mbinders $ \ _ ->
+ rnTopMonoBinds extra_mbinds [] `thenM` \ (rn_extra_binds, dus) ->
mapAndUnzipM rn_meths method_binds_s `thenM` \ (rn_method_binds_s, fvs_s) ->
returnM ((rn_method_binds_s, rn_extra_binds),
- fvs `plusFV` plusFVs fvs_s)
+ duUses dus `plusFV` plusFVs fvs_s)
) `thenM` \ ((rn_method_binds_s, rn_extra_binds), fvs) ->
let
new_inst_infos = zipWith gen_inst_info new_dfuns rn_method_binds_s
constraints = extra_constraints ++
[ mkClassPred clas [arg_ty]
| data_con <- tyConDataCons tycon,
- arg_ty <- dataConRepArgTys data_con,
+ arg_ty <- dataConOrigArgTys data_con,
-- Use the same type variables
-- as the type constructor,
-- hence no need to instantiate
= doptM Opt_GlasgowExts `thenM` \ gla_exts ->
if can_derive_via_isomorphism && (gla_exts || standard_instance) then
-- Go ahead and use the isomorphism
+ traceTc (text "newtype deriving:" <+> ppr tycon <+> ppr rep_tys) `thenM_`
new_dfun_name clas tycon `thenM` \ dfun_name ->
returnM (Nothing, Just (InstInfo { iDFunId = mk_dfun dfun_name,
iBinds = NewTypeDerived rep_tys }))
else
- if standard_instance then
+ if standard_instance then
mk_eqn_help DataType tycon clas [] -- Go via bale-out route
- else
+ else
+ -- Non-standard instance
+ if gla_exts then
+ -- Too hard
bale_out cant_derive_err
+ else
+ -- Just complain about being a non-std instance
+ bale_out non_std_err
where
-- Here is the plan for newtype derivings. We see
-- newtype T a1...an = T (t ak...an) deriving (.., C s1 .. sm, ...)
-- Want to drop 1 arg from (T s a) and (ST s a)
-- to get instance Monad (ST s) => Monad (T s)
- (tyvars, rep_ty) = newTyConRep tycon
- (rep_fn, rep_ty_args) = splitAppTys rep_ty
+ -- Note [newtype representation]
+ -- We must not use newTyConRep to get the representation
+ -- type, because that looks through all intermediate newtypes
+ -- To get the RHS of *this* newtype, just look at the data
+ -- constructor. 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,
+ -- when making the Num instance of A!
+ tyvars = tyConTyVars tycon
+ rep_ty = head (dataConOrigArgTys (head (tyConDataCons tycon)))
+ (rep_fn, rep_ty_args) = tcSplitAppTys rep_ty
n_tyvars_to_keep = tyConArity tycon - n_args_to_drop
tyvars_to_drop = drop n_tyvars_to_keep tyvars
-- Figuring out whether we can only do this newtype-deriving thing
standard_instance = null tys && classKey clas `elem` derivableClassKeys
+ right_arity = length tys + 1 == classArity clas
can_derive_via_isomorphism
= not (clas `hasKey` readClassKey) -- Never derive Read,Show this way
&& not (clas `hasKey` showClassKey)
+ && right_arity -- Well kinded;
+ -- eg not: newtype T ... deriving( ST )
+ -- because ST needs *2* type params
&& n_tyvars_to_keep >= 0 -- Well kinded;
-- eg not: newtype T = T Int deriving( Monad )
&& n_args_to_keep >= 0 -- Well kinded:
&& (tyVarsOfTypes args_to_keep `subVarSet` mkVarSet tyvars_to_keep)
cant_derive_err = derivingThingErr clas tys tycon tyvars_to_keep
- (vcat [ptext SLIT("too hard for cunning newtype deriving"),
- ppr n_tyvars_to_keep,
- ppr n_args_to_keep,
- ppr eta_ok,
- ppr (isRecursiveTyCon tycon)
+ (vcat [ptext SLIT("even with cunning newtype deriving:"),
+ if right_arity then empty else
+ quotes (ppr (mkClassPred clas tys)) <+> ptext SLIT("does not have arity 1"),
+ if n_tyvars_to_keep >= 0 && n_args_to_keep >= 0 then empty else
+ ptext SLIT("the type constructor has wrong kind"),
+ if n_args_to_keep >= 0 then empty else
+ ptext SLIT("representation type has wrong kind"),
+ if eta_ok then empty else
+ ptext SLIT("the eta-reduction property does not hold"),
+ if not (isRecursiveTyCon tycon) then empty else
+ ptext SLIT("the newtype is recursive")
])
+ non_std_err = derivingThingErr clas tys tycon tyvars_to_keep
+ (vcat [non_std_why clas,
+ ptext SLIT("Try -fglasgow-exts for GHC's newtype-deriving extension")])
+
bale_out err = addErrTc err `thenM_` returnM (Nothing, Nothing)
------------------------------------------------------------------
chk_out :: Class -> TyCon -> [TcType] -> Maybe SDoc
chk_out clas tycon tys
- | notNull tys = Just non_std_why
- | not (getUnique clas `elem` derivableClassKeys) = Just non_std_why
+ | notNull tys = Just ty_args_why
+ | not (getUnique clas `elem` derivableClassKeys) = Just (non_std_why clas)
| clas `hasKey` enumClassKey && not is_enumeration = Just nullary_why
| clas `hasKey` boundedClassKey && not is_enumeration_or_single = Just single_nullary_why
| clas `hasKey` ixClassKey && not is_enumeration_or_single = Just single_nullary_why
is_single_con = maybeToBool (maybeTyConSingleCon tycon)
is_enumeration_or_single = is_enumeration || is_single_con
- single_nullary_why = ptext SLIT("one constructor data type or type with all nullary constructors expected")
- nullary_why = ptext SLIT("data type with all nullary constructors expected")
- no_cons_why = ptext SLIT("type has no data constructors")
- non_std_why = ptext SLIT("not a derivable class")
- existential_why = ptext SLIT("it has existentially-quantified constructor(s)")
+ single_nullary_why = ptext SLIT("one constructor data type or type with all nullary constructors expected")
+ nullary_why = quotes (ppr tycon) <+> ptext SLIT("has non-nullary constructors")
+ no_cons_why = quotes (ppr tycon) <+> ptext SLIT("has no data constructors")
+ ty_args_why = quotes (ppr pred) <+> ptext SLIT("is not a class")
+ existential_why = quotes (ppr tycon) <+> ptext SLIT("has existentially-quantified constructor(s)")
+
+ pred = mkClassPred clas tys
+
+non_std_why clas = quotes (ppr clas) <+> ptext SLIT("is not a derivable class")
new_dfun_name clas tycon -- Just a simple wrapper
= newDFunName clas [mkTyConApp tycon []] (getSrcLoc tycon)
\end{itemize}
\begin{code}
-solveDerivEqns :: InstEnv
- -> [DerivEqn]
+solveDerivEqns :: [DerivEqn]
-> TcM [DFunId] -- Solns in same order as eqns.
-- This bunch is Absolutely minimal...
-solveDerivEqns inst_env_in orig_eqns
+solveDerivEqns orig_eqns
= iterateDeriv 1 initial_solutions
where
-- The initial solutions for the equations claim that each
= pprPanic "solveDerivEqns: probable loop"
(vcat (map pprDerivEqn orig_eqns) $$ ppr current_solns)
| otherwise
- = getDOpts `thenM` \ dflags ->
- let
- dfuns = zipWithEqual "add_solns" mk_deriv_dfun orig_eqns current_solns
- inst_env = extend_inst_env dflags inst_env_in dfuns
+ = let
+ dfuns = zipWithEqual "add_solns" mk_deriv_dfun orig_eqns current_solns
in
checkNoErrs (
-- Extend the inst info from the explicit instance decls
-- with the current set of solutions, and simplify each RHS
- tcSetInstEnv inst_env $
+ tcExtendTempInstEnv dfuns $
mappM gen_soln orig_eqns
) `thenM` \ new_solns ->
if (current_solns == new_solns) then
addErrCtxt (derivCtxt (Just clas) tc) $
tcSimplifyDeriv tyvars deriv_rhs `thenM` \ theta ->
returnM (sortLt (<) theta) -- Canonicalise before returning the soluction
-\end{code}
-
-\begin{code}
-extend_inst_env dflags inst_env new_dfuns
- = new_inst_env
- where
- (new_inst_env, _errs) = extendInstEnv dflags inst_env new_dfuns
- -- Ignore the errors about duplicate instances.
- -- We don't want repeated error messages
- -- They'll appear later, when we do the top-level extendInstEnvs
mk_deriv_dfun (dfun_name, clas, tycon, tyvars, _) theta
= mkDictFunId dfun_name tyvars theta