[project @ 2000-05-31 10:13:57 by lewie]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcDeriv.lhs
index 0014b14..58c3980 100644 (file)
@@ -11,42 +11,47 @@ module TcDeriv ( tcDeriving ) where
 #include "HsVersions.h"
 
 import HsSyn           ( HsBinds(..), MonoBinds(..), collectMonoBinders )
-import RdrHsSyn                ( RdrName, RdrNameMonoBinds )
+import RdrHsSyn                ( RdrNameMonoBinds )
 import RnHsSyn         ( RenamedHsBinds, RenamedMonoBinds )
+import CmdLineOpts     ( opt_D_dump_deriv )
 
 import TcMonad
 import Inst            ( InstanceMapper )
-import TcEnv           ( getEnv_TyCons )
+import TcEnv           ( getEnvTyCons )
 import TcGenDeriv      -- Deriv stuff
 import TcInstUtil      ( InstInfo(..), buildInstanceEnvs )
 import TcSimplify      ( tcSimplifyThetas )
 
 import RnBinds         ( rnMethodBinds, rnTopMonoBinds )
-import RnEnv           ( newDfunName, bindLocatedLocalsRn )
+import RnEnv           ( newDFunName, bindLocatedLocalsRn )
 import RnMonad         ( RnNameSupply, 
                          renameSourceCode, thenRn, mapRn, returnRn )
 
 import Bag             ( Bag, emptyBag, unionBags, listToBag )
 import Class           ( classKey, Class )
-import ErrUtils                ( ErrMsg )
+import ErrUtils                ( dumpIfSet, Message, pprBagOfErrors )
 import MkId            ( mkDictFunId )
 import Id              ( mkVanillaId )
-import DataCon         ( dataConArgTys, isNullaryDataCon )
+import DataCon         ( dataConArgTys, isNullaryDataCon, isExistentialDataCon )
 import PrelInfo                ( needsDataDeclCtxtClassKeys )
-import Maybes          ( maybeToBool )
+import Maybes          ( maybeToBool, catMaybes )
+import Module          ( ModuleName )
 import Name            ( isLocallyDefined, getSrcLoc,
-                         Name, Module, NamedThing(..),
+                         Name, NamedThing(..),
                          OccName, nameOccName
                        )
+import RdrName         ( RdrName )
+import RnMonad         ( FixityEnv )
 import SrcLoc          ( mkGeneratedSrcLoc, SrcLoc )
 import TyCon           ( tyConTyVars, tyConDataCons, tyConDerivings,
                          tyConTheta, maybeTyConSingleCon, isDataTyCon,
                          isEnumerationTyCon, isAlgTyCon, TyCon
                        )
-import Type            ( GenType(..), TauType, mkTyVarTys, mkTyConApp,
+import Type            ( TauType, mkTyVarTys, mkTyConApp,
                          mkSigmaTy, mkDictTy, isUnboxedType,
-                         splitAlgTyConApp
+                         splitAlgTyConApp, classesToPreds
                        )
+import PprType         ( {- instance Outputable Type -} )
 import TysWiredIn      ( voidTy )
 import Var             ( TyVar )
 import Unique          -- Keys stuff
@@ -182,22 +187,21 @@ context to the instance decl.  The "offending classes" are
 %************************************************************************
 
 \begin{code}
-tcDeriving  :: Module                  -- name of module under scrutiny
+tcDeriving  :: ModuleName              -- name of module under scrutiny
+           -> FixityEnv                -- for the deriving code (Show/Read.)
            -> RnNameSupply             -- for "renaming" bits of generated code
            -> Bag InstInfo             -- What we already know about instances
            -> TcM s (Bag InstInfo,     -- The generated "instance decls".
-                     RenamedHsBinds,   -- Extra generated bindings
-                     SDoc)             -- Printable derived instance decls;
-                                          -- for debugging via -ddump-derivings.
+                     RenamedHsBinds)   -- Extra generated bindings
 
-tcDeriving modname rn_name_supply inst_decl_infos_in
-  = recoverTc (returnTc (emptyBag, EmptyBinds, empty)) $
+tcDeriving modname fixs rn_name_supply inst_decl_infos_in
+  = recoverTc (returnTc (emptyBag, EmptyBinds)) $
 
        -- Fish the "deriving"-related information out of the TcEnv
        -- and make the necessary "equations".
     makeDerivEqns                              `thenTc` \ eqns ->
     if null eqns then
-       returnTc (emptyBag, EmptyBinds, text "No derivings")
+       returnTc (emptyBag, EmptyBinds)
     else
 
        -- Take the equation list and solve it, to deliver a list of
@@ -217,7 +221,7 @@ tcDeriving modname rn_name_supply inst_decl_infos_in
     let
        extra_mbind_list = map gen_tag_n_con_monobind nm_alist_etc
        extra_mbinds     = foldr AndMonoBinds EmptyMonoBinds extra_mbind_list
-       method_binds_s   = map gen_bind new_inst_infos
+       method_binds_s   = map (gen_bind fixs) new_inst_infos
        mbinders         = bagToList (collectMonoBinders extra_mbinds)
        
        -- Rename to get RenamedBinds.
@@ -226,35 +230,35 @@ tcDeriving modname rn_name_supply inst_decl_infos_in
        (dfun_names_w_method_binds, rn_extra_binds)
                = renameSourceCode modname rn_name_supply (
                        bindLocatedLocalsRn (ptext (SLIT("deriving"))) mbinders $ \ _ ->
-                       rnTopMonoBinds extra_mbinds []          `thenRn` \ rn_extra_binds ->
+                       rnTopMonoBinds extra_mbinds []          `thenRn` \ (rn_extra_binds, _) ->
                        mapRn rn_one method_binds_s             `thenRn` \ dfun_names_w_method_binds ->
                        returnRn (dfun_names_w_method_binds, rn_extra_binds)
                  )
        rn_one (cl_nm, tycon_nm, meth_binds) 
-               = newDfunName cl_nm tycon_nm
-                             Nothing mkGeneratedSrcLoc         `thenRn` \ dfun_name ->
-                 rnMethodBinds meth_binds                      `thenRn` \ rn_meth_binds ->
+               = newDFunName (cl_nm, tycon_nm)
+                             mkGeneratedSrcLoc         `thenRn` \ dfun_name ->
+                 rnMethodBinds meth_binds              `thenRn` \ (rn_meth_binds, _) ->
                  returnRn (dfun_name, rn_meth_binds)
 
-       really_new_inst_infos = map (gen_inst_info modname)
-                                   (new_inst_infos `zip` dfun_names_w_method_binds)
+       really_new_inst_infos = zipWith gen_inst_info
+                                       new_inst_infos
+                                       dfun_names_w_method_binds
 
        ddump_deriv = ddump_deriving really_new_inst_infos rn_extra_binds
     in
-    --pprTrace "derived:\n" (ddump_deriv) $
+    ioToTc (dumpIfSet opt_D_dump_deriv "Derived instances" ddump_deriv)        `thenTc_`
 
-    returnTc (listToBag really_new_inst_infos,
-             rn_extra_binds,
-             ddump_deriv)
+    returnTc (listToBag really_new_inst_infos, rn_extra_binds)
   where
     ddump_deriving :: [InstInfo] -> RenamedHsBinds -> SDoc
-
     ddump_deriving inst_infos extra_binds
-      = vcat ((map pp_info inst_infos) ++ [ppr extra_binds])
+      = vcat (map pp_info inst_infos) $$ ppr extra_binds
       where
        pp_info (InstInfo clas tvs [ty] inst_decl_theta _ mbinds _ _)
-         = ($$) (ppr (mkSigmaTy tvs inst_decl_theta (mkDictTy clas [ty])))
-                   (ppr mbinds)
+         = ppr (mkSigmaTy tvs inst_decl_theta' (mkDictTy clas [ty]))
+           $$
+           ppr mbinds
+           where inst_decl_theta' = classesToPreds inst_decl_theta
 \end{code}
 
 
@@ -286,7 +290,7 @@ makeDerivEqns
   = tcGetEnv                       `thenNF_Tc` \ env ->
     let
        local_data_tycons = filter (\tc -> isLocallyDefined tc && isAlgTyCon tc)
-                                  (getEnv_TyCons env)
+                                  (getEnvTyCons env)
 
        think_about_deriving = need_deriving local_data_tycons
        (derive_these, _)    = removeDups cmp_deriv think_about_deriving
@@ -295,8 +299,8 @@ makeDerivEqns
     if null local_data_tycons then
        returnTc []     -- Bale out now
     else
-    mapTc chk_out think_about_deriving `thenTc_`
-    returnTc eqns
+    mapTc mk_eqn derive_these `thenTc` \ maybe_eqns ->
+    returnTc (catMaybes maybe_eqns)
   where
     ------------------------------------------------------------------
     need_deriving :: [TyCon] -> [(Class, TyCon)]
@@ -308,45 +312,20 @@ makeDerivEqns
              tycons_to_consider
 
     ------------------------------------------------------------------
-    chk_out :: (Class, TyCon) -> TcM s ()
-    chk_out this_one@(clas, tycon)
-      =        let
-           clas_key = classKey clas
-
-           is_enumeration = isEnumerationTyCon tycon
-           is_single_con  = maybeToBool (maybeTyConSingleCon tycon)
-
-           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")
-
-           chk_clas clas_uniq clas_str clas_why cond
-             = if (clas_uniq == clas_key)
-               then checkTc cond (derivingThingErr clas_str clas_why tycon)
-               else returnTc ()
-       in
-           -- Are things OK for deriving Enum (if appropriate)?
-       chk_clas enumClassKey (SLIT("Enum")) nullary_why is_enumeration `thenTc_`
-
-           -- Are things OK for deriving Bounded (if appropriate)?
-       chk_clas boundedClassKey (SLIT("Bounded")) single_nullary_why
-                (is_enumeration || is_single_con) `thenTc_`
-
-           -- Are things OK for deriving Ix (if appropriate)?
-       chk_clas ixClassKey (SLIT("Ix.Ix")) single_nullary_why 
-                (is_enumeration || is_single_con)
-
-    ------------------------------------------------------------------
     cmp_deriv :: (Class, TyCon) -> (Class, TyCon) -> Ordering
     cmp_deriv (c1, t1) (c2, t2)
       = (c1 `compare` c2) `thenCmp` (t1 `compare` t2)
 
     ------------------------------------------------------------------
-    mk_eqn :: (Class, TyCon) -> DerivEqn
+    mk_eqn :: (Class, TyCon) -> NF_TcM s (Maybe DerivEqn)
        -- we swizzle the tyvars and datacons out of the tycon
        -- to make the rest of the equation
 
     mk_eqn (clas, tycon)
-      = (clas, tycon, tyvars, constraints)
+      = case chk_out clas tycon of
+          Just err ->  addErrTc err    `thenNF_Tc_` 
+                       returnNF_Tc Nothing
+          Nothing  ->  returnNF_Tc (Just (clas, tycon, tyvars, constraints))
       where
        clas_key  = classKey clas
        tyvars    = tyConTyVars tycon   -- ToDo: Do we need new tyvars ???
@@ -369,6 +348,24 @@ makeDerivEqns
             ]
           where
             instd_arg_tys  = dataConArgTys data_con tyvar_tys
+
+    ------------------------------------------------------------------
+    chk_out :: Class -> TyCon -> Maybe Message
+    chk_out clas tycon
+       | clas `hasKey` enumClassKey    && not is_enumeration         = bog_out nullary_why
+       | clas `hasKey` boundedClassKey && not is_enumeration_or_single = bog_out single_nullary_why
+       | clas `hasKey` ixClassKey      && not is_enumeration_or_single = bog_out single_nullary_why
+       | any isExistentialDataCon (tyConDataCons tycon)              = Just (existentialErr clas tycon)
+       | otherwise                                                   = Nothing
+       where
+           is_enumeration = isEnumerationTyCon tycon
+           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")
+
+           bog_out why = Just (derivingThingErr clas tycon why)
 \end{code}
 
 %************************************************************************
@@ -474,7 +471,8 @@ add_solns inst_infos_in eqns solns
          = mkVanillaId (getName tycon) dummy_dfun_ty
                -- The name is getSrcLoc'd in an error message 
 
-       dummy_dfun_ty = mkSigmaTy tyvars theta voidTy
+       theta' = classesToPreds theta
+       dummy_dfun_ty = mkSigmaTy tyvars theta' voidTy
                -- All we need from the dfun is its "theta" part, used during
                -- equation simplification (tcSimplifyThetas).  The final
                -- dfun_id will have the superclass dictionaries as arguments too,
@@ -555,10 +553,14 @@ the renamer.  What a great hack!
 -- Generate the method bindings for the required instance
 -- (paired with class name, as we need that when generating dict
 --  names.)
-gen_bind :: InstInfo -> ({-class-}OccName, {-tyCon-}OccName, RdrNameMonoBinds)
-gen_bind (InstInfo clas _ [ty] _ _ _ _ _)
+gen_bind :: FixityEnv -> InstInfo -> ({-class-}OccName, {-tyCon-}OccName, RdrNameMonoBinds)
+gen_bind fixities (InstInfo clas _ [ty] _ _ _ _ _)
   | not from_here 
   = (clas_nm, tycon_nm, EmptyMonoBinds)
+  |  clas `hasKey` showClassKey 
+  = (clas_nm, tycon_nm, gen_Show_binds fixities tycon)
+  |  clas `hasKey` readClassKey 
+  = (clas_nm, tycon_nm, gen_Read_binds fixities tycon)
   | otherwise
   = (clas_nm, tycon_nm,
      assoc "gen_bind:bad derived class"
@@ -566,25 +568,22 @@ gen_bind (InstInfo clas _ [ty] _ _ _ _ _)
           ,(ordClassKey,     gen_Ord_binds)
           ,(enumClassKey,    gen_Enum_binds)
           ,(boundedClassKey, gen_Bounded_binds)
-          ,(showClassKey,    gen_Show_binds)
-          ,(readClassKey,    gen_Read_binds)
           ,(ixClassKey,      gen_Ix_binds)
           ]
-          (classKey clas) 
+          (classKey clas)
           tycon)
   where
       clas_nm     = nameOccName (getName clas)
       tycon_nm    = nameOccName (getName tycon)
       from_here   = isLocallyDefined tycon
       (tycon,_,_) = splitAlgTyConApp ty        
-           
 
-gen_inst_info :: Module                                        -- Module name
-             -> (InstInfo, (Name, RenamedMonoBinds))           -- the main stuff to work on
+gen_inst_info :: InstInfo
+             -> (Name, RenamedMonoBinds)
              -> InstInfo                               -- the gen'd (filled-in) "instance decl"
 
-gen_inst_info modname
-    (InstInfo clas tyvars tys@(ty:_) inst_decl_theta _ _ locn _, (dfun_name, meth_binds))
+gen_inst_info (InstInfo clas tyvars tys@(ty:_) inst_decl_theta _ _ locn _) 
+             (dfun_name, meth_binds)
   =
        -- Generate the various instance-related Ids
     InstInfo clas tyvars tys inst_decl_theta
@@ -666,7 +665,8 @@ gen_taggery_Names inst_infos
     do_tag2con acc_Names tycon
       | isDataTyCon tycon &&
          (we_are_deriving enumClassKey tycon ||
-         we_are_deriving ixClassKey   tycon)
+         we_are_deriving ixClassKey   tycon
+         && isEnumerationTyCon tycon)
       = returnTc ( (tag2con_RDR tycon, tycon, GenTag2Con)
                 : (maxtag_RDR  tycon, tycon, GenMaxTag)
                 : acc_Names)
@@ -684,12 +684,16 @@ gen_taggery_Names inst_infos
 \end{code}
 
 \begin{code}
-derivingThingErr :: FAST_STRING -> FAST_STRING -> TyCon -> ErrMsg
+derivingThingErr :: Class -> TyCon -> FAST_STRING -> Message
+
+derivingThingErr clas tycon why
+  = sep [hsep [ptext SLIT("Can't make a derived instance of"), quotes (ppr clas)],
+        hsep [ptext SLIT("for the type"), quotes (ppr tycon)],
+        parens (ptext why)]
 
-derivingThingErr thing why tycon
-  = hang (hsep [ptext SLIT("Can't make a derived instance of"), ptext thing])
-        0 (hang (hsep [ptext SLIT("for the type"), quotes (ppr tycon)])
-                0 (parens (ptext why)))
+existentialErr clas tycon
+  = sep [ptext SLIT("Can't derive any instances for type") <+> quotes (ppr tycon),
+        ptext SLIT("because it has existentially-quantified constructor(s)")]
 
 derivCtxt tycon
   = ptext SLIT("When deriving classes for") <+> quotes (ppr tycon)