collectLocatedMonoBinders )
import RdrHsSyn ( RdrNameMonoBinds )
import RnHsSyn ( RenamedHsBinds, RenamedMonoBinds, RenamedTyClDecl, RenamedHsPred )
-import CmdLineOpts ( DynFlag(..), DynFlags )
+import CmdLineOpts ( DynFlag(..) )
import TcMonad
import TcEnv ( tcSetInstEnv, newDFunName, InstInfo(..), pprInstInfo,
- tcLookupClass, tcLookupTyCon, tcExtendTyVarEnv
+ tcLookupTyCon, tcExtendTyVarEnv
)
import TcGenDeriv -- Deriv stuff
import InstEnv ( InstEnv, simpleDFunClassTyCon, extendInstEnv )
import TcMonoType ( tcHsPred )
-import TcSimplify ( tcSimplifyThetas )
+import TcSimplify ( tcSimplifyDeriv )
import RnBinds ( rnMethodBinds, rnTopMonoBinds )
import RnEnv ( bindLocatedLocalsRn )
import RnMonad ( renameDerivedCode, thenRn, mapRn, returnRn )
-import HscTypes ( DFunId, PersistentRenamerState )
+import HscTypes ( DFunId, PersistentRenamerState, FixityEnv )
-import BasicTypes ( Fixity, NewOrData(..) )
+import BasicTypes ( NewOrData(..) )
import Class ( className, classKey, classTyVars, Class )
-import ErrUtils ( dumpIfSet_dyn, Message )
+import ErrUtils ( dumpIfSet_dyn )
import MkId ( mkDictFunId )
import DataCon ( dataConRepArgTys, isNullaryDataCon, isExistentialDataCon )
import PrelInfo ( needsDataDeclCtxtClassKeys )
import TyCon ( tyConTyVars, tyConDataCons, tyConArity, newTyConRep,
tyConTheta, maybeTyConSingleCon, isDataTyCon,
- isEnumerationTyCon, TyCon
+ isEnumerationTyCon, isRecursiveTyCon, TyCon
)
import TcType ( TcType, ThetaType, mkTyVarTys, mkTyConApp, getClassPredTys_maybe,
isUnLiftedType, mkClassPred, tyVarsOfTypes, tcSplitFunTys,
import Var ( TyVar, tyVarKind )
import VarSet ( mkVarSet, subVarSet )
import PrelNames
-import Util ( zipWithEqual, sortLt )
+import Util ( zipWithEqual, sortLt, notNull )
import ListSetOps ( removeDups, assoc )
import Outputable
import Maybe ( isJust )
-import List ( nub )
-import FastString ( FastString )
\end{code}
%************************************************************************
-- The Name is the name for the DFun we'll build
-- The tyvars bind all the variables in the RHS
+pprDerivEqn (n,c,tc,tvs,rhs)
+ = parens (hsep [ppr n, ppr c, ppr tc, ppr tvs] <+> equals <+> ppr rhs)
+
type DerivRhs = ThetaType
type DerivSoln = DerivRhs
\end{code}
Read, Enum?
+FURTHER NOTE ADDED March 2002. In fact, Haskell98 now requires that
+pattern matching against a constructor from a data type with a context
+gives rise to the constraints for that context -- or at least the thinned
+version. So now all classes are "offending".
+
+
%************************************************************************
%* *
tcDeriving :: PersistentRenamerState
-> Module -- name of module under scrutiny
-> InstEnv -- What we already know about instances
- -> (Name -> Maybe Fixity) -- used in deriving Show and Read
+ -> FixityEnv -- used in deriving Show and Read
-> [RenamedTyClDecl] -- All type constructors
-> TcM ([InstInfo], -- The generated "instance decls".
RenamedHsBinds) -- Extra generated bindings
tcDeriving prs mod inst_env get_fixity tycl_decls
= recoverTc (returnTc ([], EmptyBinds)) $
+ getDOptsTc `thenNF_Tc` \ dflags ->
-- Fish the "deriving"-related information out of the TcEnv
-- and make the necessary "equations".
- makeDerivEqns tycl_decls `thenTc` \ (ordinary_eqns, inst_info2) ->
-
- deriveOrdinaryStuff mod prs inst_env get_fixity
- ordinary_eqns `thenTc` \ (inst_info1, binds) ->
+ makeDerivEqns tycl_decls `thenTc` \ (ordinary_eqns, newtype_inst_info) ->
let
- inst_info = inst_info2 ++ inst_info1 -- info2 usually empty
+ -- 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 mod prs inst_env1 get_fixity
+ ordinary_eqns `thenTc` \ (ordinary_inst_info, binds) ->
+ let
+ inst_info = newtype_inst_info ++ ordinary_inst_info
in
- getDOptsTc `thenNF_Tc` \ dflags ->
ioToTc (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"
(ddump_deriving inst_info binds)) `thenTc_`
where
ddump_deriving :: [InstInfo] -> RenamedHsBinds -> SDoc
ddump_deriving inst_infos extra_binds
- = vcat (map pprInstInfo inst_infos) $$ ppr extra_binds
+ = vcat (map ppr_info inst_infos) $$ ppr extra_binds
+ ppr_info inst_info = pprInstInfo inst_info $$
+ nest 4 (ppr (iBinds inst_info))
+ -- pprInstInfo doesn't print much: only the type
-----------------------------------------
deriveOrdinaryStuff mod prs inst_env_in get_fixity [] -- Short cut
mk_eqn (new_or_data, tycon_name, pred)
= tcLookupTyCon tycon_name `thenNF_Tc` \ tycon ->
tcAddSrcLoc (getSrcLoc tycon) $
- tcAddErrCtxt (derivCtxt tycon) $
+ tcAddErrCtxt (derivCtxt Nothing tycon) $
tcExtendTyVarEnv (tyConTyVars tycon) $ -- Deriving preds may (now) mention
-- the type variables for the type constructor
tcHsPred pred `thenTc` \ pred' ->
not (isUnLiftedType arg_ty) -- No constraints for unlifted types?
]
-
-- "extra_constraints": see notes above about contexts on data decls
- extra_constraints | offensive_class = tyConTheta tycon
- | otherwise = []
-
- offensive_class = classKey clas `elem` needsDataDeclCtxtClassKeys
+ extra_constraints = tyConTheta tycon
+
+ -- | offensive_class = tyConTheta tycon
+ -- | otherwise = []
+ -- offensive_class = classKey clas `elem` needsDataDeclCtxtClassKeys
mk_eqn_help NewType tycon clas tys
&& n_args_to_keep >= 0 -- Well kinded:
-- eg not: newtype T a = T Int deriving( Monad )
&& eta_ok -- Eta reduction works
+ && not (isRecursiveTyCon tycon) -- Does not work for recursive tycons:
+ -- newtype A = MkA [A]
+ -- Don't want
+ -- instance Eq [A] => Eq A !!
-- Check that eta reduction is OK
-- (a) the dropped-off args are identical
&& (tyVarsOfTypes args_to_keep `subVarSet` mkVarSet tyvars_to_keep)
cant_derive_err = derivingThingErr clas tys tycon tyvars_to_keep
- SLIT("too hard for cunning newtype deriving")
-
+ (ptext SLIT("too hard for cunning newtype deriving"))
bale_out err = addErrTc err `thenNF_Tc_` returnNF_Tc (Nothing, Nothing)
------------------------------------------------------------------
- chk_out :: Class -> TyCon -> [TcType] -> Maybe FastString
+ chk_out :: Class -> TyCon -> [TcType] -> Maybe SDoc
chk_out clas tycon tys
- | not (null tys) = Just non_std_why
+ | notNull tys = Just non_std_why
| not (getUnique clas `elem` derivableClassKeys) = Just non_std_why
| clas `hasKey` enumClassKey && not is_enumeration = Just nullary_why
| clas `hasKey` boundedClassKey && 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 = SLIT("one constructor data type or type with all nullary constructors expected")
- nullary_why = SLIT("data type with all nullary constructors expected")
- no_cons_why = SLIT("type has no data constructors")
- non_std_why = SLIT("not a derivable class")
- existential_why = 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 = 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)")
new_dfun_name clas tycon -- Just a simple wrapper
= newDFunName clas [mkTyConApp tycon []] (getSrcLoc tycon)
-- This bunch is Absolutely minimal...
solveDerivEqns inst_env_in orig_eqns
- = iterateDeriv initial_solutions
+ = iterateDeriv 1 initial_solutions
where
-- The initial solutions for the equations claim that each
-- instance has an empty context; this solution is certainly
-- 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 :: [DerivSoln] ->TcM [DFunId]
- iterateDeriv current_solns
- = checkNoErrsTc (iterateOnce current_solns)
- `thenTc` \ (new_dfuns, new_solns) ->
+ iterateDeriv :: Int -> [DerivSoln] ->TcM [DFunId]
+ iterateDeriv 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)
+ | otherwise
+ = getDOptsTc `thenNF_Tc` \ dflags ->
+ let
+ dfuns = zipWithEqual "add_solns" mk_deriv_dfun orig_eqns current_solns
+ inst_env = extend_inst_env dflags inst_env_in dfuns
+ in
+ checkNoErrsTc (
+ -- Extend the inst info from the explicit instance decls
+ -- with the current set of solutions, and simplify each RHS
+ tcSetInstEnv inst_env $
+ mapTc gen_soln orig_eqns
+ ) `thenTc` \ new_solns ->
if (current_solns == new_solns) then
- returnTc new_dfuns
+ returnTc dfuns
else
- iterateDeriv new_solns
+ iterateDeriv (n+1) new_solns
------------------------------------------------------------------
- iterateOnce current_solns
- = -- Extend the inst info from the explicit instance decls
- -- with the current set of solutions, giving a
- getDOptsTc `thenNF_Tc` \ dflags ->
- let (new_dfuns, inst_env) =
- add_solns dflags inst_env_in orig_eqns current_solns
- in
- -- Simplify each RHS
- tcSetInstEnv inst_env (
- listTc [ tcAddSrcLoc (getSrcLoc tc) $
- tcAddErrCtxt (derivCtxt tc) $
- tcSimplifyThetas deriv_rhs
- | (_, _,tc,_,deriv_rhs) <- orig_eqns ]
- ) `thenTc` \ next_solns ->
-
- -- Canonicalise the solutions, so they compare nicely
- let canonicalised_next_solns = [ sortLt (<) next_soln | next_soln <- next_solns ]
- in
- returnTc (new_dfuns, canonicalised_next_solns)
+
+ gen_soln (_, clas, tc,tyvars,deriv_rhs)
+ = tcAddSrcLoc (getSrcLoc tc) $
+ tcAddErrCtxt (derivCtxt (Just clas) tc) $
+ tcSimplifyDeriv tyvars deriv_rhs `thenTc` \ theta ->
+ returnTc (sortLt (<) theta) -- Canonicalise before returning the soluction
\end{code}
\begin{code}
-add_solns :: DynFlags
- -> InstEnv -- The global, non-derived ones
- -> [DerivEqn] -> [DerivSoln]
- -> ([DFunId], InstEnv)
- -- the eqns and solns move "in lockstep"; we have the eqns
- -- because we need the LHS info for addClassInstance.
-
-add_solns dflags inst_env_in eqns solns
- = (new_dfuns, inst_env)
- where
- new_dfuns = zipWithEqual "add_solns" mk_deriv_dfun eqns solns
- (inst_env, _) = extendInstEnv dflags inst_env_in new_dfuns
+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 clas tyvars
- [mkTyConApp tycon (mkTyVarTys tyvars)]
- theta
+mk_deriv_dfun (dfun_name, clas, tycon, tyvars, _) theta
+ = mkDictFunId dfun_name clas tyvars
+ [mkTyConApp tycon (mkTyVarTys tyvars)]
+ theta
\end{code}
%************************************************************************
-- Generate the method bindings for the required instance
-- (paired with class name, as we need that when renaming
-- the method binds)
-gen_bind :: (Name -> Maybe Fixity) -> DFunId -> (Name, RdrNameMonoBinds)
+gen_bind :: FixityEnv -> DFunId -> (Name, RdrNameMonoBinds)
gen_bind get_fixity dfun
= (cls_nm, binds)
where
\begin{code}
derivingThingErr clas tys tycon tyvars why
= sep [hsep [ptext SLIT("Can't make a derived instance of"), quotes (ppr pred)],
- parens (ptext why)]
+ parens why]
where
pred = mkClassPred clas (tys ++ [mkTyConApp tycon (mkTyVarTys tyvars)])
malformedPredErr tycon pred = ptext SLIT("Illegal deriving item") <+> ppr pred
-derivCtxt tycon
- = ptext SLIT("When deriving classes for") <+> quotes (ppr tycon)
+derivCtxt :: Maybe Class -> TyCon -> SDoc
+derivCtxt maybe_cls tycon
+ = ptext SLIT("When deriving") <+> cls <+> ptext SLIT("for type") <+> quotes (ppr tycon)
+ where
+ cls = case maybe_cls of
+ Nothing -> ptext SLIT("instances")
+ Just c -> ptext SLIT("the") <+> quotes (ppr c) <+> ptext SLIT("instance")
\end{code}