[project @ 2000-05-31 10:13:57 by lewie]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcDeriv.lhs
index c0f1c90..58c3980 100644 (file)
@@ -29,19 +29,19 @@ import RnMonad              ( RnNameSupply,
 
 import Bag             ( Bag, emptyBag, unionBags, listToBag )
 import Class           ( classKey, Class )
-import ErrUtils                ( dumpIfSet, Message )
+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 Module          ( Module )
+import Maybes          ( maybeToBool, catMaybes )
+import Module          ( ModuleName )
 import Name            ( isLocallyDefined, getSrcLoc,
                          Name, NamedThing(..),
                          OccName, nameOccName
                        )
 import RdrName         ( RdrName )
-import RnMonad         ( Fixities )
+import RnMonad         ( FixityEnv )
 import SrcLoc          ( mkGeneratedSrcLoc, SrcLoc )
 import TyCon           ( tyConTyVars, tyConDataCons, tyConDerivings,
                          tyConTheta, maybeTyConSingleCon, isDataTyCon,
@@ -49,8 +49,9 @@ import TyCon          ( tyConTyVars, tyConDataCons, tyConDerivings,
                        )
 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
@@ -186,8 +187,8 @@ context to the instance decl.  The "offending classes" are
 %************************************************************************
 
 \begin{code}
-tcDeriving  :: Module                  -- name of module under scrutiny
-           -> Fixities                 -- for the deriving code (Show/Read.)
+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".
@@ -211,7 +212,7 @@ tcDeriving modname fixs rn_name_supply inst_decl_infos_in
        -- Now augment the InstInfos, adding in the rather boring
        -- actual-code-to-do-the-methods binds.  We may also need to
        -- generate extra not-one-inst-decl-specific binds, notably
-       -- the "con2tag" function.  We do these
+       -- "con2tag" and/or "tag2con" functions.  We do these
        -- separately.
 
     gen_taggery_Names new_inst_infos           `thenTc` \ nm_alist_etc ->
@@ -234,13 +235,14 @@ tcDeriving modname fixs rn_name_supply inst_decl_infos_in
                        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
@@ -253,9 +255,10 @@ tcDeriving modname fixs rn_name_supply inst_decl_infos_in
       = 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 (mkSigmaTy tvs inst_decl_theta' (mkDictTy clas [ty]))
            $$
            ppr mbinds
+           where inst_decl_theta' = classesToPreds inst_decl_theta
 \end{code}
 
 
@@ -296,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)]
@@ -309,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 ???
@@ -370,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}
 
 %************************************************************************
@@ -475,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,
@@ -540,6 +537,10 @@ The examples under the different sections below will make this
 clearer.
 
 \item
+Much less often (really just for deriving @Ix@), we use a
+@_tag2con_<tycon>@ function.  See the examples.
+
+\item
 We use the renamer!!!  Reason: we're supposed to be
 producing @RenamedMonoBinds@ for the methods, but that means
 producing correctly-uniquified code on the fly.  This is entirely
@@ -552,13 +553,13 @@ 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 :: Fixities -> InstInfo -> ({-class-}OccName, {-tyCon-}OccName, RdrNameMonoBinds)
+gen_bind :: FixityEnv -> InstInfo -> ({-class-}OccName, {-tyCon-}OccName, RdrNameMonoBinds)
 gen_bind fixities (InstInfo clas _ [ty] _ _ _ _ _)
   | not from_here 
   = (clas_nm, tycon_nm, EmptyMonoBinds)
-  |  ckey == showClassKey 
+  |  clas `hasKey` showClassKey 
   = (clas_nm, tycon_nm, gen_Show_binds fixities tycon)
-  |  ckey == readClassKey 
+  |  clas `hasKey` readClassKey 
   = (clas_nm, tycon_nm, gen_Read_binds fixities tycon)
   | otherwise
   = (clas_nm, tycon_nm,
@@ -569,22 +570,20 @@ gen_bind fixities (InstInfo clas _ [ty] _ _ _ _ _)
           ,(boundedClassKey, gen_Bounded_binds)
           ,(ixClassKey,      gen_Ix_binds)
           ]
-          ckey
+          (classKey clas)
           tycon)
   where
       clas_nm     = nameOccName (getName clas)
       tycon_nm    = nameOccName (getName tycon)
       from_here   = isLocallyDefined tycon
       (tycon,_,_) = splitAlgTyConApp ty        
-      ckey       = classKey clas
-           
 
-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
@@ -601,7 +600,7 @@ gen_inst_info modname
 
 %************************************************************************
 %*                                                                     *
-\subsection[TcDeriv-taggery-Names]{What con2tag functions are available?}
+\subsection[TcDeriv-taggery-Names]{What con2tag/tag2con functions are available?}
 %*                                                                     *
 %************************************************************************
 
@@ -609,6 +608,7 @@ gen_inst_info modname
 data Foo ... = ...
 
 con2tag_Foo :: Foo ... -> Int#
+tag2con_Foo :: Int -> Foo ...  -- easier if Int, not Int#
 maxtag_Foo  :: Int             -- ditto (NB: not unboxed)
 
 
@@ -622,6 +622,14 @@ Or: we're deriving @Ord@ (unless single-constructor), @Enum@, @Ix@
 (enum type only????)
 \end{itemize}
 
+We have a @tag2con@ function for a tycon if:
+\begin{itemize}
+\item
+We're deriving @Enum@, or @Ix@ (enum type only???)
+\end{itemize}
+
+If we have a @tag2con@ function, we also generate a @maxtag@ constant.
+
 \begin{code}
 gen_taggery_Names :: [InstInfo]
                  -> TcM s [(RdrName,   -- for an assoc list
@@ -631,7 +639,7 @@ gen_taggery_Names :: [InstInfo]
 gen_taggery_Names inst_infos
   = --pprTrace "gen_taggery:\n" (vcat [hsep [ppr c, ppr t] | (c,t) <- all_CTs]) $
     foldlTc do_con2tag []           tycons_of_interest `thenTc` \ names_so_far ->
-    foldlTc do_maxtag names_so_far tycons_of_interest
+    foldlTc do_tag2con names_so_far tycons_of_interest
   where
     all_CTs = [ (c, get_tycon ty) | (InstInfo c _ [ty] _ _ _ _ _) <- inst_infos ]
                    
@@ -654,11 +662,13 @@ gen_taggery_Names inst_infos
       | otherwise
       = returnTc acc_Names
 
-    do_maxtag acc_Names tycon
+    do_tag2con acc_Names tycon
       | isDataTyCon tycon &&
          (we_are_deriving enumClassKey tycon ||
-         we_are_deriving ixClassKey   tycon)
-      = returnTc ( (maxtag_RDR  tycon, tycon, GenMaxTag)
+         we_are_deriving ixClassKey   tycon
+         && isEnumerationTyCon tycon)
+      = returnTc ( (tag2con_RDR tycon, tycon, GenTag2Con)
+                : (maxtag_RDR  tycon, tycon, GenMaxTag)
                 : acc_Names)
       | otherwise
       = returnTc acc_Names
@@ -674,12 +684,16 @@ gen_taggery_Names inst_infos
 \end{code}
 
 \begin{code}
-derivingThingErr :: FAST_STRING -> FAST_STRING -> TyCon -> Message
+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)