summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorIavor S. Diatchki <diatchki@galois.com>2015-03-07 10:37:31 -0600
committerAustin Seipp <austin@well-typed.com>2015-03-07 10:38:30 -0600
commitb359c886cd7578ed083bcedcea05d315ecaeeb54 (patch)
treebb1959149dde78d29614966131841a77fa38bbab /compiler
parent479523f3c37894d63352f1718e06696f3ed63143 (diff)
downloadhaskell-b359c886cd7578ed083bcedcea05d315ecaeeb54.tar.gz
Custom `Typeable` solver, that keeps track of kinds.
Summary: This implements the new `Typeable` solver: when GHC sees `Typeable` constraints it solves them on the spot. The current implementation creates `TyCon` representations on the spot. Pro: No overhead at all in code that does not use `Typeable` Cons: Code that uses `Typeable` may create multipe `TyCon` represntations. We have discussed an implementation where representations of `TyCons` are computed once, in the module, where a datatype is declared. This would lead to more code being generated: for a promotable datatype we need to generate `2 + number_of_data_cons` type-constructro representations, and we have to do that for all programs, even ones that do not intend to use typeable. I added code to emit warning whenevar `deriving Typeable` is encountered--- the idea being that this is not needed anymore, and shold be fixed. Also, we allow `instance Typeable T` in .hs-boot files, but they result in a warning, and are ignored. This last one was to avoid breaking exisitng code, and should become an error, eventually. Test Plan: 1. GHC can compile itself. 2. I compiled a number of large libraries, including `lens`. - I had to make some small changes: `unordered-containers` uses internals of `TypeReps`, so I had to do a 1 line fix - `lens` needed one instance changed, due to a poly-kinded `Typeble` instance 3. I also run some code that uses `syb` to traverse a largish datastrucutre. I didn't notice any signifiant performance difference between the 7.8.3 version, and this implementation. Reviewers: simonpj, simonmar, austin, hvr Reviewed By: austin, hvr Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D652 GHC Trac Issues: #9858
Diffstat (limited to 'compiler')
-rw-r--r--compiler/basicTypes/MkId.hs1
-rw-r--r--compiler/deSugar/DsBinds.hs128
-rw-r--r--compiler/main/DynFlags.hs2
-rw-r--r--compiler/prelude/PrelNames.hs44
-rw-r--r--compiler/typecheck/TcDeriv.hs230
-rw-r--r--compiler/typecheck/TcEvidence.hs35
-rw-r--r--compiler/typecheck/TcGenDeriv.hs52
-rw-r--r--compiler/typecheck/TcHsSyn.hs14
-rw-r--r--compiler/typecheck/TcInstDcls.hs47
-rw-r--r--compiler/typecheck/TcInteract.hs65
10 files changed, 393 insertions, 225 deletions
diff --git a/compiler/basicTypes/MkId.hs b/compiler/basicTypes/MkId.hs
index c4222be0f5..98e6847d8d 100644
--- a/compiler/basicTypes/MkId.hs
+++ b/compiler/basicTypes/MkId.hs
@@ -32,6 +32,7 @@ module MkId (
voidPrimId, voidArgId,
nullAddrId, seqId, lazyId, lazyIdKey,
coercionTokenId, magicDictId, coerceId,
+ proxyHashId,
-- Re-export error Ids
module PrelRules
diff --git a/compiler/deSugar/DsBinds.hs b/compiler/deSugar/DsBinds.hs
index 6e9fcdf05a..079cfbf8ba 100644
--- a/compiler/deSugar/DsBinds.hs
+++ b/compiler/deSugar/DsBinds.hs
@@ -39,7 +39,9 @@ import UniqSupply
import Digraph
import PrelNames
-import TyCon ( isTupleTyCon, tyConDataCons_maybe )
+import TysPrim ( mkProxyPrimTy )
+import TyCon ( isTupleTyCon, tyConDataCons_maybe
+ , tyConName, isPromotedTyCon, isPromotedDataCon )
import TcEvidence
import TcType
import Type
@@ -47,6 +49,7 @@ import Coercion hiding (substCo)
import TysWiredIn ( eqBoxDataCon, coercibleDataCon, tupleCon, mkListTy
, mkBoxedTupleTy, stringTy )
import Id
+import MkId(proxyHashId)
import Class
import DataCon ( dataConTyCon, dataConWorkId )
import Name
@@ -71,6 +74,7 @@ import Util
import Control.Monad( when )
import MonadUtils
import Control.Monad(liftM)
+import Fingerprint(Fingerprint(..), fingerprintString)
{-
************************************************************************
@@ -879,6 +883,128 @@ dsEvTerm (EvLit l) =
dsEvTerm (EvCallStack cs) = dsEvCallStack cs
+dsEvTerm (EvTypeable ev) = dsEvTypeable ev
+
+dsEvTypeable :: EvTypeable -> DsM CoreExpr
+dsEvTypeable ev =
+ do tyCl <- dsLookupTyCon typeableClassName
+ typeRepTc <- dsLookupTyCon typeRepTyConName
+ let tyRepType = mkTyConApp typeRepTc []
+
+ (ty, rep) <-
+ case ev of
+
+ EvTypeableTyCon tc ks ts ->
+ do ctr <- dsLookupGlobalId mkPolyTyConAppName
+ mkTyCon <- dsLookupGlobalId mkTyConName
+ dflags <- getDynFlags
+ let mkRep cRep kReps tReps =
+ mkApps (Var ctr) [ cRep, mkListExpr tyRepType kReps
+ , mkListExpr tyRepType tReps ]
+
+ let kindRep k =
+ case splitTyConApp_maybe k of
+ Nothing -> panic "dsEvTypeable: not a kind constructor"
+ Just (kc,ks) ->
+ do kcRep <- tyConRep dflags mkTyCon kc
+ reps <- mapM kindRep ks
+ return (mkRep kcRep [] reps)
+
+ tcRep <- tyConRep dflags mkTyCon tc
+
+ kReps <- mapM kindRep ks
+ tReps <- mapM (getRep tyCl) ts
+
+ return ( mkTyConApp tc (ks ++ map snd ts)
+ , mkRep tcRep kReps tReps
+ )
+
+ EvTypeableTyApp t1 t2 ->
+ do e1 <- getRep tyCl t1
+ e2 <- getRep tyCl t2
+ ctr <- dsLookupGlobalId mkAppTyName
+
+ return ( mkAppTy (snd t1) (snd t2)
+ , mkApps (Var ctr) [ e1, e2 ]
+ )
+
+ EvTypeableTyLit ty ->
+ do str <- case (isNumLitTy ty, isStrLitTy ty) of
+ (Just n, _) -> return (show n)
+ (_, Just n) -> return (show n)
+ _ -> panic "dsEvTypeable: malformed TyLit evidence"
+ ctr <- dsLookupGlobalId typeLitTypeRepName
+ tag <- mkStringExpr str
+ return (ty, mkApps (Var ctr) [ tag ])
+
+ -- TyRep -> Typeable t
+ -- see also: Note [Memoising typeOf]
+ repName <- newSysLocalDs tyRepType
+ let proxyT = mkProxyPrimTy (typeKind ty) ty
+ method = bindNonRec repName rep
+ $ mkLams [mkWildValBinder proxyT] (Var repName)
+
+ -- package up the method as `Typeable` dictionary
+ return $ mkCast method $ mkSymCo $ getTypeableCo tyCl ty
+
+ where
+ -- co: method -> Typeable k t
+ getTypeableCo tc t =
+ case instNewTyCon_maybe tc [typeKind t, t] of
+ Just (_,co) -> co
+ _ -> panic "Class `Typeable` is not a `newtype`."
+
+ -- Typeable t -> TyRep
+ getRep tc (ev,t) =
+ do typeableExpr <- dsEvTerm ev
+ let co = getTypeableCo tc t
+ method = mkCast typeableExpr co
+ proxy = mkTyApps (Var proxyHashId) [typeKind t, t]
+ return (mkApps method [proxy])
+
+ -- This part could be cached
+ tyConRep dflags mkTyCon tc =
+ do pkgStr <- mkStringExprFS pkg_fs
+ modStr <- mkStringExprFS modl_fs
+ nameStr <- mkStringExprFS name_fs
+ return (mkApps (Var mkTyCon) [ int64 high, int64 low
+ , pkgStr, modStr, nameStr
+ ])
+ where
+ tycon_name = tyConName tc
+ modl = nameModule tycon_name
+ pkg = modulePackageKey modl
+
+ modl_fs = moduleNameFS (moduleName modl)
+ pkg_fs = packageKeyFS pkg
+ name_fs = occNameFS (nameOccName tycon_name)
+ hash_name_fs
+ | isPromotedTyCon tc = appendFS (mkFastString "$k") name_fs
+ | isPromotedDataCon tc = appendFS (mkFastString "$c") name_fs
+ | otherwise = name_fs
+
+ hashThis = unwords $ map unpackFS [pkg_fs, modl_fs, hash_name_fs]
+ Fingerprint high low = fingerprintString hashThis
+
+ int64
+ | wORD_SIZE dflags == 4 = mkWord64LitWord64
+ | otherwise = mkWordLit dflags . fromIntegral
+
+
+
+{- Note [Memoising typeOf]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+See #3245, #9203
+
+IMPORTANT: we don't want to recalculate the TypeRep once per call with
+the proxy argument. This is what went wrong in #3245 and #9203. So we
+help GHC by manually keeping the 'rep' *outside* the lambda.
+-}
+
+
+
+
+
dsEvCallStack :: EvCallStack -> DsM CoreExpr
-- See Note [Overview of implicit CallStacks] in TcEvidence.hs
dsEvCallStack cs = do
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 8d6d4296b8..04445c8cdc 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -518,6 +518,7 @@ data WarningFlag =
| Opt_WarnPartialTypeSignatures
| Opt_WarnMissingExportedSigs
| Opt_WarnUntickedPromotedConstructors
+ | Opt_WarnDerivingTypeable
deriving (Eq, Show, Enum)
data Language = Haskell98 | Haskell2010
@@ -2845,6 +2846,7 @@ fWarningFlags = [
flagSpec "warn-auto-orphans" Opt_WarnAutoOrphans,
flagSpec "warn-deprecations" Opt_WarnWarningsDeprecations,
flagSpec "warn-deprecated-flags" Opt_WarnDeprecatedFlags,
+ flagSpec "warn-deriving-typeable" Opt_WarnDerivingTypeable,
flagSpec "warn-dodgy-exports" Opt_WarnDodgyExports,
flagSpec "warn-dodgy-foreign-imports" Opt_WarnDodgyForeignImports,
flagSpec "warn-dodgy-imports" Opt_WarnDodgyImports,
diff --git a/compiler/prelude/PrelNames.hs b/compiler/prelude/PrelNames.hs
index a3d00996fd..5e13227572 100644
--- a/compiler/prelude/PrelNames.hs
+++ b/compiler/prelude/PrelNames.hs
@@ -213,7 +213,15 @@ basicKnownKeyNames
alternativeClassName,
foldableClassName,
traversableClassName,
- typeableClassName, -- derivable
+
+ -- Typeable
+ typeableClassName,
+ typeRepTyConName,
+ mkTyConName,
+ mkPolyTyConAppName,
+ mkAppTyName,
+ typeLitTypeRepName,
+
-- Numeric stuff
negateName, minusName, geName, eqName,
@@ -1032,9 +1040,21 @@ rationalToDoubleName = varQual gHC_FLOAT (fsLit "rationalToDouble") rationalToDo
ixClassName :: Name
ixClassName = clsQual gHC_ARR (fsLit "Ix") ixClassKey
--- Class Typeable
-typeableClassName :: Name
-typeableClassName = clsQual tYPEABLE_INTERNAL (fsLit "Typeable") typeableClassKey
+-- Class Typeable, and functions for constructing `Typeable` dictionaries
+typeableClassName
+ , typeRepTyConName
+ , mkTyConName
+ , mkPolyTyConAppName
+ , mkAppTyName
+ , typeLitTypeRepName
+ :: Name
+typeableClassName = clsQual tYPEABLE_INTERNAL (fsLit "Typeable") typeableClassKey
+typeRepTyConName = tcQual tYPEABLE_INTERNAL (fsLit "TypeRep") typeRepTyConKey
+mkTyConName = varQual tYPEABLE_INTERNAL (fsLit "mkTyCon") mkTyConKey
+mkPolyTyConAppName = varQual tYPEABLE_INTERNAL (fsLit "mkPolyTyConApp") mkPolyTyConAppKey
+mkAppTyName = varQual tYPEABLE_INTERNAL (fsLit "mkAppTy") mkAppTyKey
+typeLitTypeRepName = varQual tYPEABLE_INTERNAL (fsLit "typeLitTypeRep") typeLitTypeRepKey
+
-- Class Data
@@ -1541,6 +1561,10 @@ staticPtrInfoTyConKey = mkPreludeTyConUnique 181
callStackTyConKey :: Unique
callStackTyConKey = mkPreludeTyConUnique 182
+-- Typeables
+typeRepTyConKey :: Unique
+typeRepTyConKey = mkPreludeTyConUnique 183
+
---------------- Template Haskell -------------------
-- USES TyConUniques 200-299
-----------------------------------------------------
@@ -1872,6 +1896,18 @@ proxyHashKey = mkPreludeMiscIdUnique 502
-- USES IdUniques 200-499
-----------------------------------------------------
+-- Used to make `Typeable` dictionaries
+mkTyConKey
+ , mkPolyTyConAppKey
+ , mkAppTyKey
+ , typeLitTypeRepKey
+ :: Unique
+mkTyConKey = mkPreludeMiscIdUnique 503
+mkPolyTyConAppKey = mkPreludeMiscIdUnique 504
+mkAppTyKey = mkPreludeMiscIdUnique 505
+typeLitTypeRepKey = mkPreludeMiscIdUnique 506
+
+
{-
************************************************************************
* *
diff --git a/compiler/typecheck/TcDeriv.hs b/compiler/typecheck/TcDeriv.hs
index 04023b56fb..7719c08534 100644
--- a/compiler/typecheck/TcDeriv.hs
+++ b/compiler/typecheck/TcDeriv.hs
@@ -43,7 +43,6 @@ import Avail
import Unify( tcUnifyTy )
import Class
import Type
-import Kind( isKind )
import ErrUtils
import DataCon
import Maybes
@@ -150,18 +149,10 @@ forgetTheta :: EarlyDerivSpec -> DerivSpec ()
forgetTheta (InferTheta spec) = spec { ds_theta = () }
forgetTheta (GivenTheta spec) = spec { ds_theta = () }
-earlyDSTyCon :: EarlyDerivSpec -> TyCon
-earlyDSTyCon (InferTheta spec) = ds_tc spec
-earlyDSTyCon (GivenTheta spec) = ds_tc spec
-
earlyDSLoc :: EarlyDerivSpec -> SrcSpan
earlyDSLoc (InferTheta spec) = ds_loc spec
earlyDSLoc (GivenTheta spec) = ds_loc spec
-earlyDSClass :: EarlyDerivSpec -> Class
-earlyDSClass (InferTheta spec) = ds_cls spec
-earlyDSClass (GivenTheta spec) = ds_cls spec
-
splitEarlyDerivSpec :: [EarlyDerivSpec] -> ([DerivSpec ThetaOrigin], [DerivSpec ThetaType])
splitEarlyDerivSpec [] = ([],[])
splitEarlyDerivSpec (InferTheta spec : specs) =
@@ -382,10 +373,11 @@ tcDeriving tycl_decls inst_decls deriv_decls
; let (binds, newTyCons, famInsts, extraInstances) =
genAuxBinds loc (unionManyBags (auxDerivStuff : deriv_stuff))
+ ; dflags <- getDynFlags
+
; (inst_info, rn_binds, rn_dus) <-
renameDeriv is_boot (inst_infos ++ (bagToList extraInstances)) binds
- ; dflags <- getDynFlags
; unless (isEmptyBag inst_info) $
liftIO (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"
(ddump_deriving inst_info rn_binds newTyCons famInsts))
@@ -414,6 +406,73 @@ tcDeriving tycl_decls inst_decls deriv_decls
hangP s x = text "" $$ hang (ptext (sLit s)) 2 x
+{-
+genTypeableTyConReps :: DynFlags ->
+ [LTyClDecl Name] ->
+ [LInstDecl Name] ->
+ TcM (Bag (LHsBind RdrName, LSig RdrName))
+genTypeableTyConReps dflags decls insts =
+ do tcs1 <- mapM tyConsFromDecl decls
+ tcs2 <- mapM tyConsFromInst insts
+ return $ listToBag [ genTypeableTyConRep dflags loc tc
+ | (loc,tc) <- concat (tcs1 ++ tcs2) ]
+ where
+
+ tyConFromDataCon (L l n) = do dc <- tcLookupDataCon n
+ return (do tc <- promoteDataCon_maybe dc
+ return (l,tc))
+
+ -- Promoted data constructors from a data declaration, or
+ -- a data-family instance.
+ tyConsFromDataRHS = fmap catMaybes
+ . mapM tyConFromDataCon
+ . concatMap (con_names . unLoc)
+ . dd_cons
+
+ -- Tycons from a data-family declaration; not promotable.
+ tyConFromDataFamDecl FamilyDecl { fdLName = L loc name } =
+ do tc <- tcLookupTyCon name
+ return (loc,tc)
+
+
+ -- tycons from a type-level declaration
+ tyConsFromDecl (L _ d)
+
+ -- data or newtype declaration: promoted tycon, tycon, promoted ctrs.
+ | isDataDecl d =
+ do let L loc name = tcdLName d
+ tc <- tcLookupTyCon name
+ promotedCtrs <- tyConsFromDataRHS (tcdDataDefn d)
+ let tyCons = (loc,tc) : promotedCtrs
+
+ return (case promotableTyCon_maybe tc of
+ Nothing -> tyCons
+ Just kc -> (loc,kc) : tyCons)
+
+ -- data family: just the type constructor; these are not promotable.
+ | isDataFamilyDecl d =
+ do res <- tyConFromDataFamDecl (tcdFam d)
+ return [res]
+
+ -- class: the type constructors of associated data families
+ | isClassDecl d =
+ let isData FamilyDecl { fdInfo = DataFamily } = True
+ isData _ = False
+
+ in mapM tyConFromDataFamDecl (filter isData (map unLoc (tcdATs d)))
+
+ | otherwise = return []
+
+
+ tyConsFromInst (L _ d) =
+ case d of
+ ClsInstD ci -> fmap concat
+ $ mapM (tyConsFromDataRHS . dfid_defn . unLoc)
+ $ cid_datafam_insts ci
+ DataFamInstD dfi -> tyConsFromDataRHS (dfid_defn dfi)
+ TyFamInstD {} -> return []
+-}
+
-- Prints the representable type family instance
pprRepTy :: FamInst -> SDoc
pprRepTy fi@(FamInst { fi_tys = lhs })
@@ -527,13 +586,7 @@ makeDerivSpecs is_boot tycl_decls inst_decls deriv_decls
= do { eqns1 <- concatMapM (recoverM (return []) . deriveTyDecl) tycl_decls
; eqns2 <- concatMapM (recoverM (return []) . deriveInstDecl) inst_decls
; eqns3 <- concatMapM (recoverM (return []) . deriveStandalone) deriv_decls
-
- -- If AutoDeriveTypeable is set, we automatically add Typeable instances
- -- for every data type and type class declared in the module
- ; auto_typeable <- xoptM Opt_AutoDeriveTypeable
- ; eqns4 <- deriveAutoTypeable auto_typeable (eqns1 ++ eqns3) tycl_decls
-
- ; let eqns = eqns1 ++ eqns2 ++ eqns3 ++ eqns4
+ ; let eqns = eqns1 ++ eqns2 ++ eqns3
; if is_boot then -- No 'deriving' at all in hs-boot files
do { unless (null eqns) (add_deriv_err (head eqns))
@@ -545,31 +598,6 @@ makeDerivSpecs is_boot tycl_decls inst_decls deriv_decls
addErr (hang (ptext (sLit "Deriving not permitted in hs-boot file"))
2 (ptext (sLit "Use an instance declaration instead")))
-deriveAutoTypeable :: Bool -> [EarlyDerivSpec] -> [LTyClDecl Name] -> TcM [EarlyDerivSpec]
--- Runs over *all* TyCl declarations, including classes and data families
--- i.e. not just data type decls
-deriveAutoTypeable auto_typeable done_specs tycl_decls
- | not auto_typeable = return []
- | otherwise = do { cls <- tcLookupClass typeableClassName
- ; concatMapM (do_one cls) tycl_decls }
- where
- done_tcs = mkNameSet [ tyConName (earlyDSTyCon spec)
- | spec <- done_specs
- , className (earlyDSClass spec) == typeableClassName ]
- -- Check if an automatically generated DS for deriving Typeable should be
- -- omitted because the user had manually requested an instance
-
- do_one cls (L _ decl)
- | isClassDecl decl -- Traverse into class declarations to check if they have ATs (#9999)
- = concatMapM (do_one cls) (map (fmap FamDecl) (tcdATs decl))
- | otherwise
- = do { tc <- tcLookupTyCon (tcdName decl)
- ; if (isTypeSynonymTyCon tc || isTypeFamilyTyCon tc
- || tyConName tc `elemNameSet` done_tcs)
- -- Do not derive Typeable for type synonyms or type families
- then return []
- else mkPolyKindedTypeableEqn cls tc }
-
------------------------------------------------------------------
deriveTyDecl :: LTyClDecl Name -> TcM [EarlyDerivSpec]
deriveTyDecl (L _ decl@(DataDecl { tcdLName = L _ tc_name
@@ -580,7 +608,7 @@ deriveTyDecl (L _ decl@(DataDecl { tcdLName = L _ tc_name
tys = mkTyVarTys tvs
; case preds of
- Just (L _ preds') -> concatMapM (deriveTyData False tvs tc tys) preds'
+ Just (L _ preds') -> concatMapM (deriveTyData tvs tc tys) preds'
Nothing -> return [] }
deriveTyDecl _ = return []
@@ -604,7 +632,7 @@ deriveFamInst decl@(DataFamInstDecl
; tcFamTyPats (famTyConShape fam_tc) pats (kcDataDefn defn) $
-- kcDataDefn defn: see Note [Finding the LHS patterns]
\ tvs' pats' _ ->
- concatMapM (deriveTyData True tvs' fam_tc pats') preds }
+ concatMapM (deriveTyData tvs' fam_tc pats') preds }
deriveFamInst _ = return []
@@ -638,8 +666,7 @@ deriveStandalone (L loc (DerivDecl deriv_ty overlap_mode))
= setSrcSpan loc $
addErrCtxt (standaloneCtxt deriv_ty) $
do { traceTc "Standalone deriving decl for" (ppr deriv_ty)
- ; (tvs, theta, cls, inst_tys) <- setXOptM Opt_DataKinds $ -- for polykinded typeable
- tcHsInstHead TcType.InstDeclCtxt deriv_ty
+ ; (tvs, theta, cls, inst_tys) <- tcHsInstHead TcType.InstDeclCtxt deriv_ty
; traceTc "Standalone deriving;" $ vcat
[ text "tvs:" <+> ppr tvs
, text "theta:" <+> ppr theta
@@ -657,10 +684,12 @@ deriveStandalone (L loc (DerivDecl deriv_ty overlap_mode))
; case tcSplitTyConApp_maybe inst_ty of
Just (tc, tc_args)
- | className cls == typeableClassName -- Works for algebraic TyCons
- -- _and_ data families
- -> do { check_standalone_typeable theta tc tc_args
- ; mkPolyKindedTypeableEqn cls tc }
+ | className cls == typeableClassName
+ -> do warn <- woptM Opt_WarnDerivingTypeable
+ when warn
+ $ addWarnTc
+ $ text "Standalone deriving `Typeable` has no effect."
+ return []
| isAlgTyCon tc -- All other classes
-> do { spec <- mkEqnHelp (fmap unLoc overlap_mode)
@@ -668,59 +697,19 @@ deriveStandalone (L loc (DerivDecl deriv_ty overlap_mode))
; return [spec] }
_ -> -- Complain about functions, primitive types, etc,
- -- except for the Typeable class
failWithTc $ derivingThingErr False cls cls_tys inst_ty $
ptext (sLit "The last argument of the instance must be a data or newtype application")
}
- where
- check_standalone_typeable theta tc tc_args
- -- We expect to see
- -- deriving Typeable <kind> T
- -- for some tycon T. But if S is kind-polymorphic,
- -- say (S :: forall k. k -> *), we might see
- -- deriving Typable <kind> (S k)
- --
- -- But we should NOT see
- -- deriving Typeable <kind> (T Int)
- -- or deriving Typeable <kind> (S *) where S is kind-polymorphic
- --
- -- So all the tc_args should be distinct kind variables
- | null theta
- , allDistinctTyVars tc_args
- , all is_kind_var tc_args
- = return ()
-
- | otherwise
- = do { polykinds <- xoptM Opt_PolyKinds
- ; failWith (mk_msg polykinds theta tc tc_args) }
-
- is_kind_var tc_arg = case tcGetTyVar_maybe tc_arg of
- Just v -> isKindVar v
- Nothing -> False
-
- mk_msg polykinds theta tc tc_args
- | not polykinds
- , all isKind tc_args -- Non-empty, all kinds, at least one not a kind variable
- , null theta
- = hang (ptext (sLit "To make a Typeable instance of poly-kinded")
- <+> quotes (ppr tc) <> comma)
- 2 (ptext (sLit "use XPolyKinds"))
-
- | otherwise
- = hang (ptext (sLit "Derived Typeable instance must be of form"))
- 2 (ptext (sLit "deriving instance Typeable") <+> ppr tc)
------------------------------------------------------------------
-deriveTyData :: Bool -- False <=> data/newtype
- -- True <=> data/newtype *instance*
- -> [TyVar] -> TyCon -> [Type] -- LHS of data or data instance
+deriveTyData :: [TyVar] -> TyCon -> [Type] -- LHS of data or data instance
-- Can be a data instance, hence [Type] args
-> LHsType Name -- The deriving predicate
-> TcM [EarlyDerivSpec]
-- The deriving clause of a data or newtype declaration
-- I.e. not standalone deriving
-deriveTyData is_instance tvs tc tc_args (L loc deriv_pred)
+deriveTyData tvs tc tc_args (L loc deriv_pred)
= setSrcSpan loc $ -- Use the location of the 'deriving' item
do { (deriv_tvs, cls, cls_tys, cls_arg_kind)
<- tcExtendTyVarEnv tvs $
@@ -734,7 +723,11 @@ deriveTyData is_instance tvs tc tc_args (L loc deriv_pred)
-- so the argument kind 'k' is not decomposable by splitKindFunTys
-- as is the case for all other derivable type classes
; if className cls == typeableClassName
- then derivePolyKindedTypeable is_instance cls cls_tys tvs tc tc_args
+ then do warn <- woptM Opt_WarnDerivingTypeable
+ when warn
+ $ addWarnTc
+ $ text "Deriving `Typeable` has no effect."
+ return []
else
do { -- Given data T a b c = ... deriving( C d ),
@@ -790,25 +783,6 @@ deriveTyData is_instance tvs tc tc_args (L loc deriv_pred)
cls final_cls_tys tc final_tc_args Nothing
; return [spec] } }
-derivePolyKindedTypeable :: Bool -> Class -> [Type]
- -> [TyVar] -> TyCon -> [Type]
- -> TcM [EarlyDerivSpec]
--- The deriving( Typeable ) clause of a data/newtype decl
--- I.e. not standalone deriving
-derivePolyKindedTypeable is_instance cls cls_tys _tvs tc tc_args
- | is_instance
- = failWith (sep [ ptext (sLit "Deriving Typeable is not allowed for family instances;")
- , ptext (sLit "derive Typeable for")
- <+> quotes (pprSourceTyCon tc)
- <+> ptext (sLit "alone") ])
-
- | otherwise
- = ASSERT( allDistinctTyVars tc_args ) -- Came from a data/newtype decl
- do { checkTc (isSingleton cls_tys) $ -- Typeable k
- derivingThingErr False cls cls_tys (mkTyConApp tc tc_args)
- (classArgsErr cls cls_tys)
-
- ; mkPolyKindedTypeableEqn cls tc }
{-
Note [Unify kinds in deriving]
@@ -1044,38 +1018,6 @@ mk_data_eqn overlap_mode tvs cls tycon tc_args rep_tc rep_tc_args mtheta
----------------------
-mkPolyKindedTypeableEqn :: Class -> TyCon -> TcM [EarlyDerivSpec]
--- We can arrive here from a 'deriving' clause
--- or from standalone deriving
-mkPolyKindedTypeableEqn cls tc
- = do { dflags <- getDynFlags -- It's awkward to re-used checkFlag here,
- ; checkTc(xopt Opt_DeriveDataTypeable dflags) -- so we do a DIY job
- (hang (ptext (sLit "Can't make a Typeable instance of") <+> quotes (ppr tc))
- 2 (ptext (sLit "You need DeriveDataTypeable to derive Typeable instances")))
-
- ; loc <- getSrcSpanM
- ; let prom_dcs = mapMaybe promoteDataCon_maybe (tyConDataCons tc)
- ; mapM (mk_one loc) (tc : prom_dcs) }
- where
- mk_one loc tc = do { traceTc "mkPolyKindedTypeableEqn" (ppr tc)
- ; dfun_name <- new_dfun_name cls tc
- ; return $ GivenTheta $
- DS { ds_loc = loc, ds_name = dfun_name
- , ds_tvs = kvs, ds_cls = cls
- , ds_tys = [tc_app_kind, tc_app]
- -- Remember, Typeable :: forall k. k -> *
- -- so we must instantiate it appropiately
- , ds_tc = tc, ds_tc_args = tc_args
- , ds_theta = [] -- Context is empty for polykinded Typeable
- , ds_overlap = Nothing
- -- Perhaps this should be `Just NoOverlap`?
-
- , ds_newtype = False } }
- where
- (kvs,tc_app_kind) = splitForAllTys (tyConKind tc)
- tc_args = mkTyVarTys kvs
- tc_app = mkTyConApp tc tc_args
-
inferConstraints :: Class -> [TcType]
-> TyCon -> [TcType]
-> TcM ThetaOrigin
diff --git a/compiler/typecheck/TcEvidence.hs b/compiler/typecheck/TcEvidence.hs
index e549b1e8e5..3eb5a31736 100644
--- a/compiler/typecheck/TcEvidence.hs
+++ b/compiler/typecheck/TcEvidence.hs
@@ -17,6 +17,7 @@ module TcEvidence (
EvTerm(..), mkEvCast, evVarsOfTerm,
EvLit(..), evTermCoercion,
EvCallStack(..),
+ EvTypeable(..),
-- TcCoercion
TcCoercion(..), LeftOrRight(..), pickLR,
@@ -727,9 +728,25 @@ data EvTerm
| EvCallStack EvCallStack -- Dictionary for CallStack implicit parameters
+ | EvTypeable EvTypeable -- Dictionary for `Typeable`
+
deriving( Data.Data, Data.Typeable )
+-- | Instructions on how to make a 'Typeable' dictionary.
+data EvTypeable
+ = EvTypeableTyCon TyCon [Kind] [(EvTerm, Type)]
+ -- ^ Dicitionary for concrete type constructors.
+
+ | EvTypeableTyApp (EvTerm,Type) (EvTerm,Type)
+ -- ^ Dictionary for type applications; this is used when we have
+ -- a type expression starting with a type variable (e.g., @Typeable (f a)@)
+
+ | EvTypeableTyLit Type
+ -- ^ Dictionary for a type literal.
+
+ deriving ( Data.Data, Data.Typeable )
+
data EvLit
= EvNum Integer
| EvStr FastString
@@ -984,6 +1001,7 @@ evVarsOfTerm (EvTupleMk evs) = evVarsOfTerms evs
evVarsOfTerm (EvDelayedError _ _) = emptyVarSet
evVarsOfTerm (EvLit _) = emptyVarSet
evVarsOfTerm (EvCallStack cs) = evVarsOfCallStack cs
+evVarsOfTerm (EvTypeable ev) = evVarsOfTypeable ev
evVarsOfTerms :: [EvTerm] -> VarSet
evVarsOfTerms = mapUnionVarSet evVarsOfTerm
@@ -994,6 +1012,13 @@ evVarsOfCallStack cs = case cs of
EvCsTop _ _ tm -> evVarsOfTerm tm
EvCsPushCall _ _ tm -> evVarsOfTerm tm
+evVarsOfTypeable :: EvTypeable -> VarSet
+evVarsOfTypeable ev =
+ case ev of
+ EvTypeableTyCon _ _ es -> evVarsOfTerms (map fst es)
+ EvTypeableTyApp e1 e2 -> evVarsOfTerms (map fst [e1,e2])
+ EvTypeableTyLit _ -> emptyVarSet
+
{-
************************************************************************
* *
@@ -1060,6 +1085,7 @@ instance Outputable EvTerm where
ppr (EvCallStack cs) = ppr cs
ppr (EvDelayedError ty msg) = ptext (sLit "error")
<+> sep [ char '@' <> ppr ty, ppr msg ]
+ ppr (EvTypeable ev) = ppr ev
instance Outputable EvLit where
ppr (EvNum n) = integer n
@@ -1073,6 +1099,15 @@ instance Outputable EvCallStack where
ppr (EvCsPushCall name loc tm)
= angleBrackets (ppr (name,loc)) <+> ptext (sLit ":") <+> ppr tm
+instance Outputable EvTypeable where
+ ppr ev =
+ case ev of
+ EvTypeableTyCon tc ks ts -> parens (ppr tc <+> sep (map ppr ks) <+>
+ sep (map (ppr . fst) ts))
+ EvTypeableTyApp t1 t2 -> parens (ppr (fst t1) <+> ppr (fst t2))
+ EvTypeableTyLit x -> ppr x
+
+
----------------------------------------------------------------------
-- Helper functions for dealing with IP newtype-dictionaries
----------------------------------------------------------------------
diff --git a/compiler/typecheck/TcGenDeriv.hs b/compiler/typecheck/TcGenDeriv.hs
index 57718b0007..7802a22f87 100644
--- a/compiler/typecheck/TcGenDeriv.hs
+++ b/compiler/typecheck/TcGenDeriv.hs
@@ -54,7 +54,6 @@ import Class
import TypeRep
import VarSet
import VarEnv
-import Module
import State
import Util
import Var
@@ -66,7 +65,6 @@ import Lexeme
import FastString
import Pair
import Bag
-import Fingerprint
import TcEnv (InstInfo)
import StaticFlags( opt_PprStyle_Debug )
@@ -121,7 +119,6 @@ genDerivedBinds dflags fix_env clas loc tycon
where
gen_list :: [(Unique, SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff))]
gen_list = [ (eqClassKey, gen_Eq_binds)
- , (typeableClassKey, gen_Typeable_binds dflags)
, (ordClassKey, gen_Ord_binds)
, (enumClassKey, gen_Enum_binds)
, (boundedClassKey, gen_Bounded_binds)
@@ -1252,55 +1249,6 @@ getPrecedence get_fixity nm
{-
************************************************************************
* *
-\subsection{Typeable (new)}
-* *
-************************************************************************
-
-From the data type
-
- data T a b = ....
-
-we generate
-
- instance Typeable2 T where
- typeOf2 _ = mkTyConApp (mkTyCon <hash-high> <hash-low>
- <pkg> <module> "T") []
-
-We are passed the Typeable2 class as well as T
--}
-
-gen_Typeable_binds :: DynFlags -> SrcSpan -> TyCon
- -> (LHsBinds RdrName, BagDerivStuff)
-gen_Typeable_binds dflags loc tycon
- = ( unitBag $ mk_easy_FunBind loc typeRep_RDR [nlWildPat]
- (nlHsApps mkTyConApp_RDR [tycon_rep, nlList []])
- , emptyBag )
- where
- tycon_name = tyConName tycon
- modl = nameModule tycon_name
- pkg = modulePackageKey modl
-
- modl_fs = moduleNameFS (moduleName modl)
- pkg_fs = packageKeyFS pkg
- name_fs = occNameFS (nameOccName tycon_name)
-
- tycon_rep = nlHsApps mkTyCon_RDR
- (map nlHsLit [int64 high,
- int64 low,
- HsString "" pkg_fs,
- HsString "" modl_fs,
- HsString "" name_fs])
-
- hashThis = unwords $ map unpackFS [pkg_fs, modl_fs, name_fs]
- Fingerprint high low = fingerprintString hashThis
-
- int64
- | wORD_SIZE dflags == 4 = HsWord64Prim "" . fromIntegral
- | otherwise = HsWordPrim "" . fromIntegral
-
-{-
-************************************************************************
-* *
Data instances
* *
************************************************************************
diff --git a/compiler/typecheck/TcHsSyn.hs b/compiler/typecheck/TcHsSyn.hs
index b46212ea6d..69bb795c86 100644
--- a/compiler/typecheck/TcHsSyn.hs
+++ b/compiler/typecheck/TcHsSyn.hs
@@ -1246,6 +1246,20 @@ zonkEvTerm env (EvTupleSel tm n) = do { tm' <- zonkEvTerm env tm
zonkEvTerm env (EvTupleMk tms) = do { tms' <- mapM (zonkEvTerm env) tms
; return (EvTupleMk tms') }
zonkEvTerm _ (EvLit l) = return (EvLit l)
+
+zonkEvTerm env (EvTypeable ev) =
+ fmap EvTypeable $
+ case ev of
+ EvTypeableTyCon tc ks ts -> EvTypeableTyCon tc ks `fmap` mapM zonk ts
+ EvTypeableTyApp t1 t2 -> do e1 <- zonk t1
+ e2 <- zonk t2
+ return (EvTypeableTyApp e1 e2)
+ EvTypeableTyLit t -> EvTypeableTyLit `fmap` zonkTcTypeToType env t
+ where
+ zonk (ev,t) = do ev' <- zonkEvTerm env ev
+ t' <- zonkTcTypeToType env t
+ return (ev',t')
+
zonkEvTerm env (EvCallStack cs)
= case cs of
EvCsEmpty -> return (EvCallStack cs)
diff --git a/compiler/typecheck/TcInstDcls.hs b/compiler/typecheck/TcInstDcls.hs
index 5ee64791e9..2dc2117bf0 100644
--- a/compiler/typecheck/TcInstDcls.hs
+++ b/compiler/typecheck/TcInstDcls.hs
@@ -43,7 +43,7 @@ import Class
import Var
import VarEnv
import VarSet
-import PrelNames ( tYPEABLE_INTERNAL, typeableClassName, genericClassNames )
+import PrelNames ( typeableClassName, genericClassNames )
import Bag
import BasicTypes
import DynFlags
@@ -371,7 +371,6 @@ 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
fam_insts = concat fam_insts_s
@@ -379,7 +378,7 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
-- Handwritten instances of the poly-kinded Typeable class are
-- forbidden, so we handle those separately
(typeable_instances, local_infos)
- = partition (bad_typeable_instance env) local_infos'
+ = partition bad_typeable_instance local_infos'
; addClsInsts local_infos $
addFamInsts fam_insts $
@@ -423,14 +422,9 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
}}
where
-- Separate the Typeable instances from the rest
- bad_typeable_instance env i
- = -- Class name is Typeable
- typeableClassName == is_cls_nm (iSpec i)
- -- but not those that come from Data.Typeable.Internal
- && tcg_mod env /= tYPEABLE_INTERNAL
- -- nor those from an .hs-boot or .hsig file
- -- (deriving can't be used there)
- && not (isHsBootOrSig (tcg_src env))
+ bad_typeable_instance i
+ = typeableClassName == is_cls_nm (iSpec i)
+
overlapCheck ty = case overlapMode (is_flag $ iSpec ty) of
NoOverlap _ -> False
@@ -441,18 +435,21 @@ tcInstDecls1 tycl_decls inst_decls deriv_decls
ptext (sLit "Replace the following instance:"))
2 (pprInstanceHdr (iSpec i))
- typeable_err i
- = setSrcSpan (getSrcSpan ispec) $
- addErrTc $ hang (ptext (sLit "Typeable instances can only be derived"))
- 2 (vcat [ ptext (sLit "Try") <+> quotes (ptext (sLit "deriving instance Typeable")
- <+> pp_tc)
- , ptext (sLit "(requires StandaloneDeriving)") ])
- where
- ispec = iSpec i
- pp_tc | [_kind, ty] <- is_tys ispec
- , Just (tc,_) <- tcSplitTyConApp_maybe ty
- = ppr tc
- | otherwise = ptext (sLit "<tycon>")
+ -- Report an error or a warning for a `Typeable` instances.
+ -- If we are workikng on an .hs-boot file, we just report a warning,
+ -- and ignore the instance. We do this, to give users a chance to fix
+ -- their code.
+ typeable_err i =
+ setSrcSpan (getSrcSpan (iSpec i)) $
+ do env <- getGblEnv
+ if isHsBootOrSig (tcg_src env)
+ then
+ do warn <- woptM Opt_WarnDerivingTypeable
+ when warn $ addWarnTc $ vcat
+ [ ptext (sLit "`Typeable` instances in .hs-boot files are ignored.")
+ , ptext (sLit "This warning will become an error in future versions of the compiler.")
+ ]
+ else addErrTc $ ptext (sLit "Class `Typeable` does not support user-specified instances.")
addClsInsts :: [InstInfo Name] -> TcM a -> TcM a
addClsInsts infos thing_inside
@@ -1068,6 +1065,10 @@ tcSuperClasses dfun_id cls tyvars dfun_evs inst_tys dfun_ev_binds fam_envs sc_th
| (sc_co, norm_sc_pred) <- normaliseType fam_envs Nominal sc_pred
-- sc_co :: sc_pred ~ norm_sc_pred
, ClassPred cls tys <- classifyPredType norm_sc_pred
+ , className cls /= typeableClassName
+ -- `Typeable` has custom solving rules, which is why we exlucde it
+ -- from the short cut, and fall throught to calling the solver.
+
= do { sc_ev_tm <- emit_sc_cls_pred norm_sc_pred cls tys
; sc_ev_id <- newEvVar sc_pred
; let tc_co = TcCoercion (mkSubCo (mkSymCo sc_co))
diff --git a/compiler/typecheck/TcInteract.hs b/compiler/typecheck/TcInteract.hs
index 5ebeb270b1..8f85dd3c81 100644
--- a/compiler/typecheck/TcInteract.hs
+++ b/compiler/typecheck/TcInteract.hs
@@ -14,6 +14,7 @@ import TcCanonical
import TcFlatten
import VarSet
import Type
+import Kind (isKind)
import Unify
import InstEnv( DFunInstType, lookupInstEnv, instanceDFunId )
import CoAxiom(sfInteractTop, sfInteractInert)
@@ -21,7 +22,7 @@ import CoAxiom(sfInteractTop, sfInteractInert)
import Var
import TcType
import PrelNames ( knownNatClassName, knownSymbolClassName, ipClassNameKey,
- callStackTyConKey )
+ callStackTyConKey, typeableClassName )
import Id( idType )
import Class
import TyCon
@@ -1691,6 +1692,9 @@ matchClassInst _ clas [ ty ] _
= panicTcS (text "Unexpected evidence for" <+> ppr (className clas)
$$ vcat (map (ppr . idType) (classMethods clas)))
+matchClassInst _ clas [k,t] loc
+ | className clas == typeableClassName = matchTypeableClass clas k t loc
+
matchClassInst inerts clas tys loc
= do { dflags <- getDynFlags
; tclvl <- getTcLevel
@@ -1833,3 +1837,62 @@ isCallStackIP loc cls ty
= ctLocSpan loc
isCallStackIP _ _ _
= Nothing
+
+
+
+-- | Assumes that we've checked that this is the 'Typeable' class,
+-- and it was applied to the correc arugment.
+matchTypeableClass :: Class -> Kind -> Type -> CtLoc -> TcS LookupInstResult
+matchTypeableClass clas k t loc
+ | isForAllTy k = return NoInstance
+ | Just (tc, ks_tys) <- splitTyConApp_maybe t = doTyConApp tc ks_tys
+ | Just (f,kt) <- splitAppTy_maybe t = doTyApp f kt
+ | Just _ <- isNumLitTy t = mkEv [] (EvTypeableTyLit t)
+ | Just _ <- isStrLitTy t = mkEv [] (EvTypeableTyLit t)
+ | otherwise = return NoInstance
+
+ where
+ -- Representation for type constructor applied to some kinds and some types.
+ doTyConApp tc ks_ts =
+ case mapM kindRep ks of
+ Nothing -> return NoInstance -- Not concrete kinds
+ Just kReps ->
+ do tCts <- mapM subGoal ts
+ mkEv tCts (EvTypeableTyCon tc kReps (map ctEvTerm tCts `zip` ts))
+ where
+ (ks,ts) = span isKind ks_ts
+
+
+ {- Representation for an application of a type to a type-or-kind.
+ This may happen when the type expression starts with a type variable.
+ Example (ignoring kind parameter):
+ Typeable (f Int Char) -->
+ (Typeable (f Int), Typeable Char) -->
+ (Typeable f, Typeable Int, Typeable Char) --> (after some simp. steps)
+ Typeable f
+ -}
+ doTyApp f tk
+ | isKind tk = return NoInstance -- We can't solve until we know the ctr.
+ | otherwise =
+ do ct1 <- subGoal f
+ ct2 <- subGoal tk
+ mkEv [ct1,ct2] (EvTypeableTyApp (ctEvTerm ct1,f) (ctEvTerm ct2,tk))
+
+
+ -- Representation for concrete kinds. We just use the kind itself,
+ -- but first check to make sure that it is "simple" (i.e., made entirely
+ -- out of kind constructors).
+ kindRep ki = do (_,ks) <- splitTyConApp_maybe ki
+ mapM_ kindRep ks
+ return ki
+
+
+ -- Emit a `Typeable` constraint for the given type.
+ subGoal ty = do let goal = mkClassPred clas [ typeKind ty, ty ]
+ ev <- newWantedEvVarNC loc goal
+ return ev
+
+
+ mkEv subs ev = return (GenInst subs (EvTypeable ev))
+
+