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 Subst ( mkTyVarSubst, substTheta )
import ErrUtils ( dumpIfSet_dyn )
import MkId ( mkDictFunId )
-import DataCon ( dataConRepArgTys, dataConOrigArgTys, isNullaryDataCon, isExistentialDataCon )
+import DataCon ( dataConOrigArgTys, isNullaryDataCon, isExistentialDataCon )
import Maybes ( maybeToBool, catMaybes )
import Name ( Name, getSrcLoc, nameUnique )
import NameSet
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, -- dataConOrigArgTys???
+ arg_ty <- dataConOrigArgTys data_con,
-- Use the same type variables
-- as the type constructor,
-- hence no need to instantiate
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, ...)
-- 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)
- && length tys + 1 == classArity clas -- Well kinded;
+ && right_arity -- Well kinded;
-- eg not: newtype T ... deriving( ST )
-- because ST needs *2* type params
&& n_tyvars_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"),
- ptext SLIT("debug info:") <+> 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 ty_args_why
- | not (getUnique clas `elem` derivableClassKeys) = Just non_std_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
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")
- non_std_why = quotes (ppr clas) <+> ptext SLIT("is not a derivable 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)
-- The type passed to newDFunName is only used to generate
\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