+%************************************************************************
+%* *
+\subsection{Extracting generic instance declaration from class declarations}
+%* *
+%************************************************************************
+
+@getGenericInstances@ extracts the generic instance declarations from a class
+declaration. For exmaple
+
+ class C a where
+ op :: a -> a
+
+ op{ x+y } (Inl v) = ...
+ op{ x+y } (Inr v) = ...
+ op{ x*y } (v :*: w) = ...
+ op{ 1 } Unit = ...
+
+gives rise to the instance declarations
+
+ instance C (x+y) where
+ op (Inl v) = ...
+ op (Inr v) = ...
+
+ instance C (x*y) where
+ op (v :*: w) = ...
+
+ instance C 1 where
+ op Unit = ...
+
+
+\begin{code}
+getGenericInstances :: [LTyClDecl Name] -> TcM [InstInfo]
+getGenericInstances class_decls
+ = do { gen_inst_infos <- mappM (addLocM get_generics) class_decls
+ ; let { gen_inst_info = concat gen_inst_infos }
+
+ -- Return right away if there is no generic stuff
+ ; if null gen_inst_info then returnM []
+ else do
+
+ -- Otherwise print it out
+ { dflags <- getDOpts
+ ; ioToTcRn (dumpIfSet_dyn dflags Opt_D_dump_deriv "Generic instances"
+ (vcat (map pprInstInfoDetails gen_inst_info)))
+ ; returnM gen_inst_info }}
+
+get_generics decl@(ClassDecl {tcdLName = class_name, tcdMeths = def_methods})
+ | null generic_binds
+ = returnM [] -- The comon case: no generic default methods
+
+ | otherwise -- A source class decl with generic default methods
+ = recoverM (returnM []) $
+ tcAddDeclCtxt decl $
+ tcLookupLocatedClass class_name `thenM` \ clas ->
+
+ -- Group by type, and
+ -- make an InstInfo out of each group
+ let
+ groups = groupWith listToBag generic_binds
+ in
+ mappM (mkGenericInstance clas) groups `thenM` \ inst_infos ->
+
+ -- Check that there is only one InstInfo for each type constructor
+ -- The main way this can fail is if you write
+ -- f {| a+b |} ... = ...
+ -- f {| x+y |} ... = ...
+ -- Then at this point we'll have an InstInfo for each
+ let
+ tc_inst_infos :: [(TyCon, InstInfo)]
+ tc_inst_infos = [(simpleInstInfoTyCon i, i) | i <- inst_infos]
+
+ bad_groups = [group | group <- equivClassesByUniq get_uniq tc_inst_infos,
+ group `lengthExceeds` 1]
+ get_uniq (tc,_) = getUnique tc
+ in
+ mappM (addErrTc . dupGenericInsts) bad_groups `thenM_`
+
+ -- Check that there is an InstInfo for each generic type constructor
+ let
+ missing = genericTyConNames `minusList` [tyConName tc | (tc,_) <- tc_inst_infos]
+ in
+ checkTc (null missing) (missingGenericInstances missing) `thenM_`
+
+ returnM inst_infos
+ where
+ generic_binds :: [(HsType Name, LHsBind Name)]
+ generic_binds = getGenericBinds def_methods
+
+
+---------------------------------
+getGenericBinds :: LHsBinds Name -> [(HsType Name, LHsBind Name)]
+ -- Takes a group of method bindings, finds the generic ones, and returns
+ -- them in finite map indexed by the type parameter in the definition.
+getGenericBinds binds = concat (map getGenericBind (bagToList binds))
+
+getGenericBind (L loc (FunBind id infixop (MatchGroup matches ty) fvs))
+ = groupWith wrap (mapCatMaybes maybeGenericMatch matches)
+ where
+ wrap ms = L loc (FunBind id infixop (MatchGroup ms ty) fvs)
+getGenericBind _
+ = []
+
+groupWith :: ([a] -> b) -> [(HsType Name, a)] -> [(HsType Name, b)]
+groupWith op [] = []
+groupWith op ((t,v):prs) = (t, op (v:vs)) : groupWith op rest
+ where
+ vs = map snd this
+ (this,rest) = partition same_t prs
+ same_t (t',v) = t `eqPatType` t'
+
+eqPatLType :: LHsType Name -> LHsType Name -> Bool
+eqPatLType t1 t2 = unLoc t1 `eqPatType` unLoc t2
+
+eqPatType :: HsType Name -> HsType Name -> Bool
+-- A very simple equality function, only for
+-- type patterns in generic function definitions.
+eqPatType (HsTyVar v1) (HsTyVar v2) = v1==v2
+eqPatType (HsAppTy s1 t1) (HsAppTy s2 t2) = s1 `eqPatLType` s2 && t2 `eqPatLType` t2
+eqPatType (HsOpTy s1 op1 t1) (HsOpTy s2 op2 t2) = s1 `eqPatLType` s2 && t2 `eqPatLType` t2 && unLoc op1 == unLoc op2
+eqPatType (HsNumTy n1) (HsNumTy n2) = n1 == n2
+eqPatType (HsParTy t1) t2 = unLoc t1 `eqPatType` t2
+eqPatType t1 (HsParTy t2) = t1 `eqPatType` unLoc t2
+eqPatType _ _ = False
+
+---------------------------------
+mkGenericInstance :: Class
+ -> (HsType Name, LHsBinds Name)
+ -> TcM InstInfo
+
+mkGenericInstance clas (hs_ty, binds)
+ -- Make a generic instance declaration
+ -- For example: instance (C a, C b) => C (a+b) where { binds }
+
+ = -- Extract the universally quantified type variables
+ -- and wrap them as forall'd tyvars, so that kind inference
+ -- works in the standard way
+ let
+ sig_tvs = map (noLoc.UserTyVar) (nameSetToList (extractHsTyVars (noLoc hs_ty)))
+ hs_forall_ty = noLoc $ mkExplicitHsForAllTy sig_tvs (noLoc []) (noLoc hs_ty)
+ in
+ -- Type-check the instance type, and check its form
+ tcHsSigType GenPatCtxt hs_forall_ty `thenM` \ forall_inst_ty ->
+ let
+ (tyvars, inst_ty) = tcSplitForAllTys forall_inst_ty
+ in
+ checkTc (validGenericInstanceType inst_ty)
+ (badGenericInstanceType binds) `thenM_`
+
+ -- Make the dictionary function.
+ getSrcSpanM `thenM` \ span ->
+ getOverlapFlag `thenM` \ overlap_flag ->
+ newDFunName clas [inst_ty] (srcSpanStart span) `thenM` \ dfun_name ->
+ let
+ inst_theta = [mkClassPred clas [mkTyVarTy tv] | tv <- tyvars]
+ dfun_id = mkDictFunId dfun_name tyvars inst_theta clas [inst_ty]
+ ispec = mkLocalInstance dfun_id overlap_flag
+ in
+ returnM (InstInfo { iSpec = ispec, iBinds = VanillaInst binds [] })
+\end{code}
+
+
+%************************************************************************
+%* *
+ Error messages
+%* *
+%************************************************************************
+