%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 19921998
%
\begin{code}
module BuildTyCl (
buildSynTyCon,
buildAlgTyCon,
buildDataCon,
TcMethInfo, buildClass,
mkAbstractTyConRhs,
mkNewTyConRhs, mkDataTyConRhs
) where
#include "HsVersions.h"
import IfaceEnv
import DataCon
import Var
import VarSet
import BasicTypes
import Name
import MkId
import Class
import TyCon
import Type
import Coercion
import TcRnMonad
import Data.List ( partition )
import Outputable
\end{code}
\begin{code}
buildSynTyCon :: Name -> [TyVar]
-> SynTyConRhs
-> Kind
-> TyConParent
-> Maybe (TyCon, [Type])
-> TcRnIf m n TyCon
buildSynTyCon tc_name tvs rhs rhs_kind parent mb_family
| Just fam_inst_info <- mb_family
= ASSERT( isNoParent parent )
fixM $ \ tycon_rec -> do
{ fam_parent <- mkFamInstParentInfo tc_name tvs fam_inst_info tycon_rec
; return (mkSynTyCon tc_name kind tvs rhs fam_parent) }
| otherwise
= return (mkSynTyCon tc_name kind tvs rhs parent)
where
kind = mkArrowKinds (map tyVarKind tvs) rhs_kind
buildAlgTyCon :: Name -> [TyVar]
-> ThetaType
-> AlgTyConRhs
-> RecFlag
-> Bool
-> Bool
-> TyConParent
-> Maybe (TyCon, [Type])
-> TcRnIf m n TyCon
buildAlgTyCon tc_name tvs stupid_theta rhs is_rec want_generics gadt_syn
parent mb_family
| Just fam_inst_info <- mb_family
=
ASSERT( isNoParent parent )
fixM $ \ tycon_rec -> do
{ fam_parent <- mkFamInstParentInfo tc_name tvs fam_inst_info tycon_rec
; return (mkAlgTyCon tc_name kind tvs stupid_theta rhs
fam_parent is_rec want_generics gadt_syn) }
| otherwise
= return (mkAlgTyCon tc_name kind tvs stupid_theta rhs
parent is_rec want_generics gadt_syn)
where
kind = mkArrowKinds (map tyVarKind tvs) liftedTypeKind
mkFamInstParentInfo :: Name -> [TyVar]
-> (TyCon, [Type])
-> TyCon
-> TcRnIf m n TyConParent
mkFamInstParentInfo tc_name tvs (family, instTys) rep_tycon
= do {
; co_tycon_name <- newImplicitBinder tc_name mkInstTyCoOcc
; let co_tycon = mkFamInstCoercion co_tycon_name tvs
family instTys rep_tycon
; return $ FamInstTyCon family instTys co_tycon }
mkAbstractTyConRhs :: AlgTyConRhs
mkAbstractTyConRhs = AbstractTyCon
mkDataTyConRhs :: [DataCon] -> AlgTyConRhs
mkDataTyConRhs cons
= DataTyCon {
data_cons = cons,
is_enum = not (null cons) &&
all isNullarySrcDataCon cons
}
mkNewTyConRhs :: Name -> TyCon -> DataCon -> TcRnIf m n AlgTyConRhs
mkNewTyConRhs tycon_name tycon con
= do { co_tycon_name <- newImplicitBinder tycon_name mkNewTyCoOcc
; let co_tycon = mkNewTypeCoercion co_tycon_name tycon etad_tvs etad_rhs
cocon_maybe | all_coercions || isRecursiveTyCon tycon
= Just co_tycon
| otherwise
= Nothing
; traceIf (text "mkNewTyConRhs" <+> ppr cocon_maybe)
; return (NewTyCon { data_con = con,
nt_rhs = rhs_ty,
nt_etad_rhs = (etad_tvs, etad_rhs),
nt_co = cocon_maybe } ) }
where
all_coercions = True
tvs = tyConTyVars tycon
inst_con_ty = applyTys (dataConUserType con) (mkTyVarTys tvs)
rhs_ty = ASSERT( isFunTy inst_con_ty ) funArgTy inst_con_ty
etad_tvs :: [TyVar]
etad_rhs :: Type
(etad_tvs, etad_rhs) = eta_reduce (reverse tvs) rhs_ty
eta_reduce :: [TyVar]
-> Type
-> ([TyVar], Type)
eta_reduce (a:as) ty | Just (fun, arg) <- splitAppTy_maybe ty,
Just tv <- getTyVar_maybe arg,
tv == a,
not (a `elemVarSet` tyVarsOfType fun)
= eta_reduce as fun
eta_reduce tvs ty = (reverse tvs, ty)
buildDataCon :: Name -> Bool
-> [HsBang]
-> [Name]
-> [TyVar] -> [TyVar]
-> [(TyVar,Type)]
-> ThetaType
-> [Type] -> Type
-> TyCon
-> TcRnIf m n DataCon
buildDataCon src_name declared_infix arg_stricts field_lbls
univ_tvs ex_tvs eq_spec ctxt arg_tys res_ty rep_tycon
= do { wrap_name <- newImplicitBinder src_name mkDataConWrapperOcc
; work_name <- newImplicitBinder src_name mkDataConWorkerOcc
; let
stupid_ctxt = mkDataConStupidTheta rep_tycon arg_tys univ_tvs
data_con = mkDataCon src_name declared_infix
arg_stricts field_lbls
univ_tvs ex_tvs eq_spec ctxt
arg_tys res_ty rep_tycon
stupid_ctxt dc_ids
dc_ids = mkDataConIds wrap_name work_name data_con
; return data_con }
mkDataConStupidTheta :: TyCon -> [Type] -> [TyVar] -> [PredType]
mkDataConStupidTheta tycon arg_tys univ_tvs
| null stupid_theta = []
| otherwise = filter in_arg_tys stupid_theta
where
tc_subst = zipTopTvSubst (tyConTyVars tycon) (mkTyVarTys univ_tvs)
stupid_theta = substTheta tc_subst (tyConStupidTheta tycon)
arg_tyvars = tyVarsOfTypes arg_tys
in_arg_tys pred = not $ isEmptyVarSet $
tyVarsOfPred pred `intersectVarSet` arg_tyvars
\end{code}
\begin{code}
type TcMethInfo = (Name, DefMethSpec, Type)
buildClass :: Bool
-> Name -> [TyVar] -> ThetaType
-> [FunDep TyVar]
-> [TyThing]
-> [TcMethInfo]
-> RecFlag
-> TcRnIf m n Class
buildClass no_unf class_name tvs sc_theta fds ats sig_stuff tc_isrec
= do { traceIf (text "buildClass")
; tycon_name <- newImplicitBinder class_name mkClassTyConOcc
; datacon_name <- newImplicitBinder class_name mkClassDataConOcc
; fixM (\ rec_clas -> do {
; op_items <- mapM (mk_op_item rec_clas) sig_stuff
; let (eq_theta, dict_theta) = partition isEqPred sc_theta
; sc_sel_names <- mapM (newImplicitBinder class_name . mkSuperDictSelOcc)
[1..length dict_theta]
; let sc_sel_ids = [ mkDictSelId no_unf sc_name rec_clas
| sc_name <- sc_sel_names]
; let use_newtype = null eq_theta && (length dict_theta + length sig_stuff == 1)
args = sc_sel_names ++ op_names
op_tys = [ty | (_,_,ty) <- sig_stuff]
op_names = [op | (op,_,_) <- sig_stuff]
arg_tys = map mkPredTy dict_theta ++ op_tys
rec_tycon = classTyCon rec_clas
; dict_con <- buildDataCon datacon_name
False
(map (const HsNoBang) args)
[]
tvs []
[]
eq_theta
arg_tys
(mkTyConApp rec_tycon (mkTyVarTys tvs))
rec_tycon
; rhs <- if use_newtype
then mkNewTyConRhs tycon_name rec_tycon dict_con
else return (mkDataTyConRhs [dict_con])
; let { clas_kind = mkArrowKinds (map tyVarKind tvs) liftedTypeKind
; tycon = mkClassTyCon tycon_name clas_kind tvs
rhs rec_clas tc_isrec
; atTyCons = [tycon | ATyCon tycon <- ats]
; result = mkClass class_name tvs fds
(eq_theta ++ dict_theta)
(length eq_theta)
sc_sel_ids atTyCons
op_items tycon
}
; traceIf (text "buildClass" <+> ppr tycon)
; return result
})}
where
mk_op_item :: Class -> TcMethInfo -> TcRnIf n m ClassOpItem
mk_op_item rec_clas (op_name, dm_spec, _)
= do { dm_info <- case dm_spec of
NoDM -> return NoDefMeth
GenericDM -> return GenDefMeth
VanillaDM -> do { dm_name <- newImplicitBinder op_name mkDefaultMethodOcc
; return (DefMeth dm_name) }
; return (mkDictSelId no_unf op_name rec_clas, dm_info) }
\end{code}
Note [Class newtypes and equality predicates]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
class (a ~ F b) => C a b where
op :: a -> b
We cannot represent this by a newtype, even though it's not
existential, and there's only one value field, because we do
capture an equality predicate:
data C a b where
MkC :: forall a b. (a ~ F b) => (a->b) -> C a b
We need to access this equality predicate when we get passes a C
dictionary. See Trac #2238