\begin{code}
#include "HsVersions.h"
-module TcClassDcl (
- tcClassDecl1, tcClassDecls2
- ) where
+module TcClassDcl ( tcClassDecl1, tcClassDecls2 ) where
-import Ubiq
+IMP_Ubiq()
import HsSyn ( ClassDecl(..), HsBinds(..), Bind(..), MonoBinds(..),
Match(..), GRHSsAndBinds(..), GRHS(..), HsExpr(..),
HsLit(..), OutPat(..), Sig(..), PolyType(..), MonoType,
- Stmt, Qual, ArithSeqInfo, InPat, Fake )
+ Stmt, Qualifier, ArithSeqInfo, InPat, Fake )
import HsPragmas ( ClassPragmas(..) )
import RnHsSyn ( RenamedClassDecl(..), RenamedClassPragmas(..),
- RenamedClassOpSig(..), RenamedMonoBinds(..),
- RenamedGenPragmas(..), RenamedContext(..) )
-import TcHsSyn ( TcIdOcc(..), TcHsBinds(..), TcMonoBinds(..), TcExpr(..),
- mkHsTyApp, mkHsTyLam, mkHsDictApp, mkHsDictLam, unZonkId )
-
-import TcMonad
-import GenSpecEtc ( specTy )
-import Inst ( Inst, InstOrigin(..), LIE(..), emptyLIE, plusLIE, newDicts )
-import TcEnv ( tcLookupClass, tcLookupTyVar, tcLookupTyCon, newLocalIds)
+ RenamedClassOpSig(..), SYN_IE(RenamedMonoBinds),
+ RenamedGenPragmas(..), RenamedContext(..),
+ RnName{-instance Uniquable-}
+ )
+import TcHsSyn ( TcIdOcc(..), SYN_IE(TcHsBinds), SYN_IE(TcMonoBinds), SYN_IE(TcExpr),
+ mkHsTyApp, mkHsTyLam, mkHsDictApp, mkHsDictLam, tcIdType )
+
+import Inst ( Inst, InstOrigin(..), SYN_IE(LIE), emptyLIE, plusLIE, newDicts, newMethod )
+import TcEnv ( tcLookupClass, tcLookupTyVar, tcLookupTyCon, newLocalIds, tcExtendGlobalTyVars )
+import SpecEnv ( SpecEnv )
import TcInstDcls ( processInstBinds )
-import TcKind ( unifyKind )
-import TcMonoType ( tcMonoType, tcContext )
-import TcType ( TcTyVar(..), tcInstType, tcInstTyVar )
-import TcKind ( TcKind )
-
-import Bag ( foldBag )
-import Class ( GenClass, mkClass, mkClassOp, getClassBigSig,
- getClassOps, getClassOpString, getClassOpLocalType )
-import CoreUtils ( escErrorMsg )
+import TcKind ( unifyKind, TcKind )
+import TcMonad hiding ( rnMtoTcM )
+import TcMonoType ( tcPolyType, tcMonoType, tcContext )
+import TcSimplify ( tcSimplifyAndCheck )
+import TcType ( SYN_IE(TcType), SYN_IE(TcTyVar), tcInstType, tcInstSigTyVars, tcInstSigType )
+
+import Bag ( foldBag, unionManyBags )
+import Class ( GenClass, mkClass, mkClassOp, classBigSig,
+ classOps, classOpString, classOpLocalType,
+ classOpTagByString, SYN_IE(ClassOp)
+ )
import Id ( mkSuperDictSelId, mkMethodSelId, mkDefaultMethodId,
idType )
-import IdInfo ( noIdInfo )
-import Name ( Name, getNameFullName, getTagFromClassOpName )
-import PrelVals ( pAT_ERROR_ID )
+import IdInfo
+import Name ( isLocallyDefined, origName, getLocalName )
+import PrelVals ( nO_DEFAULT_METHOD_ERROR_ID )
import PprStyle
import Pretty
import PprType ( GenType, GenTyVar, GenClassOp )
-import SpecEnv ( SpecEnv(..) )
+import SpecEnv ( SYN_IE(SpecEnv) )
import SrcLoc ( mkGeneratedSrcLoc )
-import Type ( mkFunTy, mkTyVarTy, mkDictTy,
+import Type ( mkFunTy, mkTyVarTy, mkTyVarTys, mkDictTy,
mkForAllTy, mkSigmaTy, splitSigmaTy)
import TysWiredIn ( stringTy )
-import TyVar ( GenTyVar )
+import TyVar ( unitTyVarSet, GenTyVar )
import Unique ( Unique )
import Util
+
-- import TcPragmas ( tcGenPragmas, tcClassOpPragmas )
tcGenPragmas ty id ps = returnNF_Tc noIdInfo
-tcClassOpPragmas ty sel def spec ps = returnNF_Tc (noIdInfo, noIdInfo)
-
+tcClassOpPragmas ty sel def spec ps = returnNF_Tc (noIdInfo `addInfo` spec,
+ noIdInfo)
\end{code}
+
+
+Dictionary handling
+~~~~~~~~~~~~~~~~~~~
+Every class implicitly declares a new data type, corresponding to dictionaries
+of that class. So, for example:
+
+ class (D a) => C a where
+ op1 :: a -> a
+ op2 :: forall b. Ord b => a -> b -> b
+
+would implicitly declare
+
+ data CDict a = CDict (D a)
+ (a -> a)
+ (forall b. Ord b => a -> b -> b)
+
+(We could use a record decl, but that means changing more of the existing apparatus.
+One step at at time!)
+
+For classes with just one superclass+method, we use a newtype decl instead:
+
+ class C a where
+ op :: forallb. a -> b -> b
+
+generates
+
+ newtype CDict a = CDict (forall b. a -> b -> b)
+
+Now DictTy in Type is just a form of type synomym:
+ DictTy c t = TyConTy CDict `AppTy` t
+
+Death to "ExpandingDicts".
+
+
\begin{code}
tcClassDecl1 rec_inst_mapper
(ClassDecl context class_name
`thenTc` \ sig_stuff ->
-- MAKE THE CLASS OBJECT ITSELF
- tcGetUnique `thenNF_Tc` \ uniq ->
let
(ops, op_sel_ids, defm_ids) = unzip3 sig_stuff
- clas = mkClass uniq (getNameFullName class_name) rec_tyvar
+ clas = mkClass (uniqueOf class_name) (getName class_name) rec_tyvar
scs sc_sel_ids ops op_sel_ids defm_ids
rec_class_inst_env
in
\end{code}
+ let
+ clas_ty = mkTyVarTy clas_tyvar
+ dict_component_tys = [mkDictTy sc clas_ty | sc <- scs] ++
+ [classOpLocalType op | op <- ops])
+ new_or_data = case dict_component_tys of
+ [_] -> NewType
+ other -> DataType
+
+ dict_con_id = mkDataCon class_name
+ [NotMarkedStrict]
+ [{- No labelled fields -}]
+ [clas_tyvar]
+ [{-No context-}]
+ dict_component_tys
+ tycon
+
+ tycon = mkDataTyCon class_name
+ (tyVarKind rec_tyvar `mkArrowKind` mkBoxedTypeKind)
+ [rec_tyvar]
+ [{- Empty context -}]
+ [dict_con_id]
+ [{- No derived classes -}]
+ new_or_data
+ in
+
+
\begin{code}
tcClassContext :: Class -> TyVar
-> RenamedContext -- class context
-- Make super-class selector ids
mapTc (mk_super_id rec_class)
- (super_classes `zip` maybe_pragmas) `thenTc` \ sc_sel_ids ->
+ (super_classes `zip` maybe_pragmas) `thenTc` \ sc_sel_ids ->
+ -- NB: we worry about matching list lengths below
-- Done
returnTc (super_classes, sc_sel_ids)
Just prag -> tcGenPragmas Nothing{-ty unknown-} rec_super_id prag
) `thenNF_Tc` \ id_info ->
let
- ty = mkForAllTy rec_tyvar (
- mkFunTy (mkDictTy rec_class (mkTyVarTy rec_tyvar))
- (mkDictTy super_class (mkTyVarTy rec_tyvar))
- )
+ rec_tyvar_ty = mkTyVarTy rec_tyvar
+ ty = mkForAllTy rec_tyvar $
+ mkFunTy (mkDictTy rec_class rec_tyvar_ty)
+ (mkDictTy super_class rec_tyvar_ty)
in
-- BUILD THE SUPERCLASS ID
returnTc (mkSuperDictSelId uniq rec_class super_class ty id_info)
tcClassSig rec_clas rec_clas_tyvar rec_classop_spec_fn
(ClassOpSig op_name
- (HsForAllTy tyvar_names context monotype)
+ op_ty
pragmas src_loc)
= tcAddSrcLoc src_loc $
fixTc ( \ ~(_, rec_sel_id, rec_defm_id) -> -- Knot for pragmas
-- Check the type signature. NB that the envt *already has*
-- bindings for the type variables; see comments in TcTyAndClassDcls.
- tcContext context `thenTc` \ theta ->
- tcMonoType monotype `thenTc` \ tau ->
- mapAndUnzipNF_Tc tcLookupTyVar tyvar_names `thenNF_Tc` \ (_,tyvars) ->
+
+ -- NB: Renamer checks that the class type variable is mentioned in local_ty,
+ -- and that it is not constrained by theta
+ tcPolyType op_ty `thenTc` \ local_ty ->
let
- full_tyvars = rec_clas_tyvar : tyvars
- full_theta = (rec_clas, mkTyVarTy rec_clas_tyvar) : theta
- global_ty = mkSigmaTy full_tyvars full_theta tau
- local_ty = mkSigmaTy tyvars theta tau
- class_op = mkClassOp (getOccurrenceName op_name)
- (getTagFromClassOpName op_name)
+ global_ty = mkSigmaTy [rec_clas_tyvar]
+ [(rec_clas, mkTyVarTy rec_clas_tyvar)]
+ local_ty
+ class_op_nm = getLocalName op_name
+ class_op = mkClassOp class_op_nm
+ (classOpTagByString rec_clas{-yeeps!-} class_op_nm)
local_ty
in
-- Build the selector id and default method id
tcGetUnique `thenNF_Tc` \ d_uniq ->
let
- op_uniq = getItsUnique op_name
+ op_uniq = uniqueOf op_name
sel_id = mkMethodSelId op_uniq rec_clas class_op global_ty op_info
defm_id = mkDefaultMethodId d_uniq rec_clas class_op False global_ty defm_info
-- ToDo: improve the "False"
tcClassDecl2 (ClassDecl context class_name
tyvar_name class_sigs default_binds pragmas src_loc)
+
+ | not (isLocallyDefined class_name)
+ = returnNF_Tc (emptyLIE, EmptyBinds)
+
+ | otherwise -- It is locally defined
= recoverNF_Tc (returnNF_Tc (emptyLIE, EmptyBinds)) $
tcAddSrcLoc src_loc $
tcLookupClass class_name `thenNF_Tc` \ (_, clas) ->
let
(tyvar, scs, sc_sel_ids, ops, op_sel_ids, defm_ids)
- = getClassBigSig clas
+ = classBigSig clas
in
- tcInstTyVar tyvar `thenNF_Tc` \ clas_tyvar ->
+ tcInstSigTyVars [tyvar] `thenNF_Tc` \ ([clas_tyvar], _, _) ->
-- Generate bindings for the selector functions
- buildSelectors clas clas_tyvar scs sc_sel_ids ops op_sel_ids
- `thenNF_Tc` \ sel_binds ->
+ buildSelectors clas tyvar clas_tyvar scs sc_sel_ids ops op_sel_ids
+ `thenNF_Tc` \ sel_binds ->
-- Ditto for the methods
buildDefaultMethodBinds clas clas_tyvar defm_ids default_binds
- `thenTc` \ (const_insts, meth_binds) ->
+ `thenTc` \ (const_insts, meth_binds) ->
returnTc (const_insts, sel_binds `ThenBinds` meth_binds)
\end{code}
\begin{code}
buildSelectors :: Class -- The class object
- -> TcTyVar s -- Class type variable
+ -> TyVar -- Class type variable
+ -> TcTyVar s -- Instantiated class type variable (TyVarTy)
-> [Class] -> [Id] -- Superclasses and selectors
-> [ClassOp] -> [Id] -- Class ops and selectors
-> NF_TcM s (TcHsBinds s)
-buildSelectors clas clas_tyvar scs sc_sel_ids ops op_sel_ids
+buildSelectors clas clas_tyvar clas_tc_tyvar scs sc_sel_ids ops op_sel_ids
=
-- Make new Ids for the components of the dictionary
- mapNF_Tc (tcInstType [] . getClassOpLocalType) ops `thenNF_Tc` \ op_tys ->
-
- newLocalIds (map getClassOpString ops) op_tys `thenNF_Tc` \ method_ids ->
+ let
+ clas_tyvar_ty = mkTyVarTy clas_tc_tyvar
+ mk_op_ty = tcInstType [(clas_tyvar, clas_tyvar_ty)] . classOpLocalType
+ in
+ mapNF_Tc mk_op_ty ops `thenNF_Tc` \ op_tys ->
+ newLocalIds (map classOpString ops) op_tys `thenNF_Tc` \ method_ids ->
newDicts ClassDeclOrigin
- [ (super_clas, mkTyVarTy clas_tyvar)
+ [ (super_clas, clas_tyvar_ty)
| super_clas <- scs ] `thenNF_Tc` \ (_,dict_ids) ->
newDicts ClassDeclOrigin
- [ (clas, mkTyVarTy clas_tyvar) ] `thenNF_Tc` \ (_,[clas_dict]) ->
+ [ (clas, clas_tyvar_ty) ] `thenNF_Tc` \ (_,[clas_dict]) ->
-- Make suitable bindings for the selectors
let
- tc_method_ids = map TcId method_ids
-
mk_sel sel_id method_or_dict
- = mkSelBind sel_id clas_tyvar clas_dict dict_ids tc_method_ids method_or_dict
+ = mkSelBind sel_id clas_tc_tyvar clas_dict dict_ids method_ids method_or_dict
in
- listNF_Tc (zipWithEqual mk_sel op_sel_ids tc_method_ids) `thenNF_Tc` \ op_sel_binds ->
- listNF_Tc (zipWithEqual mk_sel sc_sel_ids dict_ids) `thenNF_Tc` \ sc_sel_binds ->
+ listNF_Tc (zipWithEqual "mk_sel1" mk_sel op_sel_ids method_ids) `thenNF_Tc` \ op_sel_binds ->
+ listNF_Tc (zipWithEqual "mk_sel2" mk_sel sc_sel_ids dict_ids) `thenNF_Tc` \ sc_sel_binds ->
returnNF_Tc (SingleBind (
NonRecBind (
Make a selector expression for @sel_id@ from a dictionary @clas_dict@
consisting of @dicts@ and @methods@.
+====================== OLD ============================
We have to do a bit of jiggery pokery to get the type variables right.
Suppose we have the class decl:
\begin{verbatim}
\begin{verbatim}
op1_sel :: forall a b. Foo a -> Ord b -> a -> b -> a
\end{verbatim}
+========================= END OF OLD ===========================
+
+NEW COMMENT: instead we now go for op1_sel' above. Seems tidier and
+the rest of the compiler darn well ought to cope.
+
+
NOTE that we return a TcMonoBinds (which is later zonked) even though
there's no real back-substitution to do. It's just simpler this way!
-> NF_TcM s (TcMonoBinds s)
mkSelBind sel_id clas_tyvar clas_dict dicts methods method_or_dict@(TcId op)
- = let
- (op_tyvars,op_theta,op_tau) = splitSigmaTy (idType op)
- op_tys = map mkTyVarTy op_tyvars
- in
- newDicts ClassDeclOrigin op_theta `thenNF_Tc` \ (_, op_dicts) ->
-
- -- sel_id = /\ clas_tyvar op_tyvars -> \ clas_dict op_dicts ->
+ =
+ -- sel_id = /\ clas_tyvar -> \ clas_dict ->
-- case clas_dict of
- -- <dicts..methods> -> method_or_dict op_tyvars op_dicts
+ -- <dicts..methods> -> method_or_dict
returnNF_Tc (VarMonoBind (RealId sel_id) (
- TyLam (clas_tyvar:op_tyvars) (
- DictLam (clas_dict:op_dicts) (
+ TyLam [clas_tyvar] (
+ DictLam [clas_dict] (
HsCase
(HsVar clas_dict)
([PatMatch (DictPat dicts methods) (
GRHSMatch (GRHSsAndBindsOut
[OtherwiseGRHS
- (mkHsDictApp (mkHsTyApp (HsVar method_or_dict) op_tys) op_dicts)
+ (HsVar method_or_dict)
mkGeneratedSrcLoc]
EmptyBinds
- op_tau))])
+ (idType op)))])
mkGeneratedSrcLoc
))))
\end{code}
defm.Foo.op1 :: forall a. Foo a => a -> Bool
defm.Foo.op1 = /\a -> \dfoo -> \x -> True
+====================== OLD ==================
+\begin{verbatim}
defm.Foo.op2 :: forall a, b. (Foo a, Ord b) => a -> b -> b -> b
defm.Foo.op2 = /\ a b -> \ dfoo dord -> \x y z ->
if (op1 a dfoo x) && (< b dord y z) then y else z
\end{verbatim}
Notice that, like all ids, the foralls of defm.Foo.op2 are at the top.
+====================== END OF OLD ===================
+
+NEW:
+\begin{verbatim}
+defm.Foo.op2 :: forall a. Foo a => forall b. Ord b => a -> b -> b -> b
+defm.Foo.op2 = /\ a -> \ dfoo -> /\ b -> \ dord -> \x y z ->
+ if (op1 a dfoo x) && (< b dord y z) then y else z
+\end{verbatim}
+
When we come across an instance decl, we may need to use the default
methods:
const.Foo.Int.op1 = defm.Foo.op1 Int dfun.Foo.Int
const.Foo.Int.op2 :: forall b. Ord b => Int -> b -> b -> b
-const.Foo.Int.op2 = /\b -> defm.Foo.op2 Int b dfun.Foo.Int
+const.Foo.Int.op2 = defm.Foo.op2 Int dfun.Foo.Int
dfun.Foo.Int :: Foo Int
dfun.Foo.Int = (const.Foo.Int.op1, const.Foo.Int.op2)
\end{verbatim}
Notice that, as with method selectors above, we assume that dictionary
application is curried, so there's no need to mention the Ord dictionary
-in const.Foo.Int.op2
+in const.Foo.Int.op2 (or the type variable).
+
\begin{verbatim}
instance Foo a => Foo [a] where {}
= /\ a -> \ dfoo_a ->
let rec
op1 = defm.Foo.op1 [a] dfoo_list
- op2 = /\b -> defm.Foo.op2 [a] b dfoo_list
+ op2 = defm.Foo.op2 [a] dfoo_list
dfoo_list = (op1, op2)
in
dfoo_list
buildDefaultMethodBinds clas clas_tyvar
default_method_ids default_binds
- = -- Deal with the method declarations themselves
- mapNF_Tc unZonkId default_method_ids `thenNF_Tc` \ tc_defm_ids ->
- processInstBinds
- (makeClassDeclDefaultMethodRhs clas default_method_ids)
- [] -- No tyvars in scope for "this inst decl"
- emptyLIE -- No insts available
- (map TcId tc_defm_ids)
- default_binds `thenTc` \ (dicts_needed, default_binds') ->
-
- returnTc (dicts_needed, SingleBind (NonRecBind default_binds'))
+ = newDicts origin [(clas,inst_ty)] `thenNF_Tc` \ (this_dict, [this_dict_id]) ->
+ mapAndUnzipNF_Tc mk_method default_method_ids `thenNF_Tc` \ (insts_s, local_defm_ids) ->
+ let
+ avail_insts = this_dict `plusLIE` unionManyBags insts_s -- Insts available
+ clas_tyvar_set = unitTyVarSet clas_tyvar
+ in
+ tcExtendGlobalTyVars clas_tyvar_set (
+ processInstBinds
+ clas
+ (makeClassDeclDefaultMethodRhs clas local_defm_ids)
+ avail_insts
+ local_defm_ids
+ default_binds
+ ) `thenTc` \ (insts_needed, default_binds') ->
+
+ tcSimplifyAndCheck
+ clas_tyvar_set
+ avail_insts
+ insts_needed `thenTc` \ (const_lie, dict_binds) ->
+
+
+ let
+ defm_binds = AbsBinds
+ [clas_tyvar]
+ [this_dict_id]
+ (local_defm_ids `zip` map RealId default_method_ids)
+ dict_binds
+ (RecBind default_binds')
+ in
+ returnTc (const_lie, defm_binds)
+ where
+ inst_ty = mkTyVarTy clas_tyvar
+ mk_method defm_id = newMethod origin (RealId defm_id) [inst_ty]
+ origin = ClassDeclOrigin
\end{code}
@makeClassDeclDefaultMethodRhs@ builds the default method for a
\begin{code}
makeClassDeclDefaultMethodRhs
:: Class
- -> [Id]
+ -> [TcIdOcc s]
-> Int
-> NF_TcM s (TcExpr s)
makeClassDeclDefaultMethodRhs clas method_ids tag
- = specTy ClassDeclOrigin (idType method_id) `thenNF_Tc` \ (tyvars, dicts, tau, dict_ids) ->
+ = -- Return the expression
+ -- error ty "No default method for ..."
+ -- The interesting thing is that method_ty is a for-all type;
+ -- this is fun, although unusual in a type application!
+
+ returnNF_Tc (HsApp (mkHsTyApp (HsVar (RealId nO_DEFAULT_METHOD_ERROR_ID)) [tcIdType method_id])
+ (HsLitOut (HsString (_PK_ error_msg)) stringTy))
+
+{- OLD AND COMPLICATED
+ tcInstSigType () `thenNF_Tc` \ method_ty ->
+ let
+ (tyvars, theta, tau) = splitSigmaTy method_ty
+ in
+ newDicts ClassDeclOrigin theta `thenNF_Tc` \ (lie, dict_ids) ->
returnNF_Tc (mkHsTyLam tyvars (
mkHsDictLam dict_ids (
- HsApp (mkHsTyApp (HsVar (RealId pAT_ERROR_ID)) [tau])
+ HsApp (mkHsTyApp (HsVar (RealId nO_DEFAULT_METHOD_ERROR_ID)) [tau])
(HsLitOut (HsString (_PK_ error_msg)) stringTy))))
+-}
+
where
- (clas_mod, clas_name) = getOrigName clas
+ (OrigName clas_mod clas_name) = origName "makeClassDeclDefaultMethodRhs" clas
method_id = method_ids !! (tag-1)
- class_op = (getClassOps clas) !! (tag-1)
-
- error_msg = "%D" -- => No default method for \"
- ++ unencoded_part_of_msg
+ class_op = (classOps clas) !! (tag-1)
- unencoded_part_of_msg = escErrorMsg (
- _UNPK_ clas_mod ++ "." ++ _UNPK_ clas_name ++ "."
- ++ (ppShow 80 (ppr PprForUser class_op))
- ++ "\"" )
+ error_msg = _UNPK_ clas_mod ++ "." ++ _UNPK_ clas_name ++ "."
+ ++ (ppShow 80 (ppr PprForUser class_op))
+ ++ "\""
\end{code}