Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : new-typeable

http://hackage.haskell.org/trac/ghc/changeset/101334a0aabea62ec9885e601397d935764b2bf7

>---------------------------------------------------------------

commit 101334a0aabea62ec9885e601397d935764b2bf7
Author: Jose Pedro Magalhaes <j...@cs.ox.ac.uk>
Date:   Mon Nov 26 13:53:01 2012 +0000

    Implement -XAutoDeriveTypeable, warn for manual instances

>---------------------------------------------------------------

 compiler/main/DynFlags.hs         |    9 ++++++-
 compiler/typecheck/TcDeriv.lhs    |   15 +++++++++++++-
 compiler/typecheck/TcInstDcls.lhs |   40 +++++++++++++++++++++++++++++-------
 3 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 1bb3966..b1bd8bc 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -415,6 +415,7 @@ data WarningFlag =
    | Opt_WarnPointlessPragmas
    | Opt_WarnUnsupportedCallingConventions
    | Opt_WarnInlineRuleShadowing
+   | Opt_WarnTypeableInstances
    deriving (Eq, Show, Enum)
 
 data Language = Haskell98 | Haskell2010
@@ -481,6 +482,7 @@ data ExtensionFlag
  
    | Opt_StandaloneDeriving
    | Opt_DeriveDataTypeable
+   | Opt_AutoDeriveTypeable       -- Automatic derivation of Typeable
    | Opt_DeriveFunctor
    | Opt_DeriveTraversable
    | Opt_DeriveFoldable
@@ -2299,7 +2301,8 @@ fWarningFlags = [
   ( "warn-safe",                        Opt_WarnSafe, setWarnSafe ),
   ( "warn-pointless-pragmas",           Opt_WarnPointlessPragmas, nop ),
   ( "warn-unsupported-calling-conventions", 
Opt_WarnUnsupportedCallingConventions, nop ),
-  ( "warn-inline-rule-shadowing",       Opt_WarnInlineRuleShadowing, nop ) ]
+  ( "warn-inline-rule-shadowing",       Opt_WarnInlineRuleShadowing, nop ),
+  ( "warn-typeable-instances",          Opt_WarnTypeableInstances, nop ) ]
 
 -- | These @-\<blah\>@ flags can all be reversed with @-no-\<blah\>@
 negatableFlags :: [FlagSpec GeneralFlag]
@@ -2528,6 +2531,7 @@ xFlags = [
   ( "UnboxedTuples",                    Opt_UnboxedTuples, nop ),
   ( "StandaloneDeriving",               Opt_StandaloneDeriving, nop ),
   ( "DeriveDataTypeable",               Opt_DeriveDataTypeable, nop ),
+  ( "AutoDeriveTypeable",               Opt_AutoDeriveTypeable, nop ),
   ( "DeriveFunctor",                    Opt_DeriveFunctor, nop ),
   ( "DeriveTraversable",                Opt_DeriveTraversable, nop ),
   ( "DeriveFoldable",                   Opt_DeriveFoldable, nop ),
@@ -2681,7 +2685,8 @@ standardWarnings
         Opt_WarnAlternativeLayoutRuleTransitional,
         Opt_WarnPointlessPragmas,
         Opt_WarnUnsupportedCallingConventions,
-        Opt_WarnInlineRuleShadowing
+        Opt_WarnInlineRuleShadowing,
+        Opt_WarnTypeableInstances
       ]
 
 minusWOpts :: [WarningFlag]
diff --git a/compiler/typecheck/TcDeriv.lhs b/compiler/typecheck/TcDeriv.lhs
index 59da454..0ad9790 100644
--- a/compiler/typecheck/TcDeriv.lhs
+++ b/compiler/typecheck/TcDeriv.lhs
@@ -308,7 +308,15 @@ tcDeriving tycl_decls inst_decls deriv_decls
                 -- And make the necessary "equations".
           is_boot <- tcIsHsBoot
         ; traceTc "tcDeriving" (ppr is_boot)
-        ; early_specs <- makeDerivSpecs is_boot tycl_decls inst_decls 
deriv_decls
+
+        -- If -XAutoDeriveTypeable is on, add Typeable instances for each
+        -- datatype and class defined in this module
+        ; isAutoDeriveTypeable <- xoptM Opt_AutoDeriveTypeable
+        ; let deriv_decls' = deriv_decls ++ if isAutoDeriveTypeable
+                                              then deriveTypeable tycl_decls
+                                              else []
+
+        ; early_specs <- makeDerivSpecs is_boot tycl_decls inst_decls 
deriv_decls'
 
         -- for each type, determine the auxliary declarations that are common
         -- to multiple derivations involving that type (e.g. Generic and
@@ -363,6 +371,11 @@ tcDeriving tycl_decls inst_decls deriv_decls
 
     hangP s x = text "" $$ hang (ptext (sLit s)) 2 x
 
+    deriveTypeable :: [LTyClDecl Name] -> [LDerivDecl Name]
+    deriveTypeable tys =
+      [ L l (DerivDecl (L l (HsAppTy (noLoc (HsTyVar typeableClassName))
+                                     (L l (HsTyVar (tcdName t))))))
+      | L l t <- tys ]
 
 
 -- As of 24 April 2012, this only shares MetaTyCons between derivations of
diff --git a/compiler/typecheck/TcInstDcls.lhs 
b/compiler/typecheck/TcInstDcls.lhs
index bb56bf9..e5a5baf 100644
--- a/compiler/typecheck/TcInstDcls.lhs
+++ b/compiler/typecheck/TcInstDcls.lhs
@@ -51,13 +51,14 @@ import VarSet     ( mkVarSet, subVarSet, varSetElems )
 import Pair
 import CoreUnfold ( mkDFunUnfolding )
 import CoreSyn    ( Expr(Var), CoreExpr )
-import PrelNames  ( typeableClassName, oldTypeableClassNames )
+import PrelNames  ( tYPEABLE_INTERNAL, typeableClassName, 
oldTypeableClassNames )
 
 import Bag
 import BasicTypes
 import DynFlags
 import ErrUtils
 import FastString
+import HscTypes ( isHsBoot )
 import Id
 import MkId
 import Name
@@ -377,13 +378,17 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
             -- round)
 
             -- Do class and family instance declarations
+       ; env <- getGblEnv
        ; stuff <- mapAndRecoverM tcLocalInstDecl inst_decls
        ; let (local_infos_s, fam_insts_s) = unzip stuff
-             local_infos = concat local_infos_s
-             fam_insts   = concat fam_insts_s
+             fam_insts    = concat fam_insts_s
+             local_infos' = concat local_infos_s
+             -- Handwritten instances of the poly-kinded Typeable class are
+             -- forbidden, so we handle those separately
+             (typeable_instances, local_infos) = splitTypeable env local_infos'
+
        ; addClsInsts local_infos $
          addFamInsts fam_insts   $ 
-
     do {    -- Compute instances from "deriving" clauses;
             -- This stuff computes a context for the derived instance
             -- decl, so it needs to know about all the instances possible
@@ -401,11 +406,14 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
                          ; return (gbl_env, emptyBag, emptyValBindsOut) }
                  else tcDeriving tycl_decls inst_decls deriv_decls
 
+       -- Remove any handwritten instance of poly-kinded Typeable and warn
+       ; dflags <- getDynFlags
+       ; when (wopt Opt_WarnTypeableInstances dflags) $
+              mapM_ (addWarnTc . instMsg) typeable_instances
 
        -- Check that if the module is compiled with -XSafe, there are no
-       -- hand written instances of Typeable as then unsafe casts could be
+       -- hand written instances of old Typeable as then unsafe casts could be
        -- performed. Derived instances are OK.
-       ; dflags <- getDynFlags
        ; when (safeLanguageOn dflags) $
              mapM_ (\x -> when (typInstCheck x)
                                (addErrAt (getSrcSpan $ iSpec x) typInstErr))
@@ -419,11 +427,27 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
                 , deriv_binds)
     }}
   where
-    typInstCheck ty = is_cls (iSpec ty) `elem`
-                        (typeableClassName : oldTypeableClassNames)
+    -- Separate the Typeable instances from the rest
+    splitTypeable _   []     = ([],[])
+    splitTypeable env (i:is) =
+      let (typeableInsts, otherInsts) = splitTypeable env is
+      in if -- We will filter out instances of Typeable
+            (typeableClassName == is_cls (iSpec i))
+            -- but not those that come from Data.Typeable.Internal
+            && tcg_mod env /= tYPEABLE_INTERNAL
+            -- nor those from an .hs-boot file (deriving can't be used there)
+            && not (isHsBoot (tcg_src env))
+         then (i:typeableInsts, otherInsts)
+         else (typeableInsts, i:otherInsts)
+
+    typInstCheck ty = is_cls (iSpec ty) `elem` oldTypeableClassNames
     typInstErr = ptext $ sLit $ "Can't create hand written instances of 
Typeable in Safe"
                               ++ " Haskell! Can only derive them"
 
+    instMsg i = hang (ptext (sLit $ "Typeable instances can only be derived; 
ignoring "
+                                 ++ "the following instance:"))
+                     2 (pprInstance (iSpec i))
+
 addClsInsts :: [InstInfo Name] -> TcM a -> TcM a
 addClsInsts infos thing_inside
   = tcExtendLocalInstEnv (map iSpec infos) thing_inside



_______________________________________________
Cvs-ghc mailing list
Cvs-ghc@haskell.org
http://www.haskell.org/mailman/listinfo/cvs-ghc

Reply via email to