diff options
author | Ben Gamari <bgamari.foss@gmail.com> | 2015-10-30 20:22:42 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2015-10-30 20:22:44 +0100 |
commit | 91c6b1f54aea658b0056caec45655475897f1972 (patch) | |
tree | aeb80a04e102e51dfd41343d4f697baf34c95739 /libraries/base | |
parent | 59e728bc0b47116e3c9a8b21b14dc3198531b9a9 (diff) | |
download | haskell-91c6b1f54aea658b0056caec45655475897f1972.tar.gz |
Generate Typeable info at definition sites
This is the second attempt at merging D757.
This patch implements the idea floated in Trac #9858, namely that we
should generate type-representation information at the data type
declaration site, rather than when solving a Typeable constraint.
However, this turned out quite a bit harder than I expected. I still
think it's the right thing to do, and it's done now, but it was quite
a struggle.
See particularly
* Note [Grand plan for Typeable] in TcTypeable (which is a new module)
* Note [The overall promotion story] in DataCon (clarifies existing
stuff)
The most painful bit was that to generate Typeable instances (ie
TyConRepName bindings) for every TyCon is tricky for types in ghc-prim
etc:
* We need to have enough data types around to *define* a TyCon
* Many of these types are wired-in
Also, to minimise the code generated for each data type, I wanted to
generate pure data, not CAFs with unpackCString# stuff floating about.
Performance
~~~~~~~~~~~
Three perf/compiler tests start to allocate quite a bit more. This isn't
surprising, because they all allocate zillions of data types, with
practically no other code, esp. T1969
* T1969: GHC allocates 19% more
* T4801: GHC allocates 13% more
* T5321FD: GHC allocates 13% more
* T9675: GHC allocates 11% more
* T783: GHC allocates 11% more
* T5642: GHC allocates 10% more
I'm treating this as acceptable. The payoff comes in Typeable-heavy
code.
Remaining to do
~~~~~~~~~~~~~~~
* I think that "TyCon" and "Module" are over-generic names to use for
the runtime type representations used in GHC.Typeable. Better might
be
"TrTyCon" and "TrModule". But I have not yet done this
* Add more info the the "TyCon" e.g. source location where it was
defined
* Use the new "Module" type to help with Trac Trac #10068
* It would be possible to generate TyConRepName (ie Typeable
instances) selectively rather than all the time. We'd need to persist
the information in interface files. Lacking a motivating reason I
have
not done this, but it would not be difficult.
Refactoring
~~~~~~~~~~~
As is so often the case, I ended up refactoring more than I intended.
In particular
* In TyCon, a type *family* (whether type or data) is repesented by a
FamilyTyCon
* a algebraic data type (including data/newtype instances) is
represented by AlgTyCon This wasn't true before; a data family
was represented as an AlgTyCon. There are some corresponding
changes in IfaceSyn.
* Also get rid of the (unhelpfully named) tyConParent.
* In TyCon define 'Promoted', isomorphic to Maybe, used when things are
optionally promoted; and use it elsewhere in GHC.
* Cleanup handling of knownKeyNames
* Each TyCon, including promoted TyCons, contains its TyConRepName, if
it has one. This is, in effect, the name of its Typeable instance.
Updates haddock submodule
Test Plan: Let Harbormaster validate
Reviewers: austin, hvr, goldfire
Subscribers: goldfire, thomie
Differential Revision: https://phabricator.haskell.org/D1404
GHC Trac Issues: #9858
Diffstat (limited to 'libraries/base')
-rw-r--r-- | libraries/base/Data/Typeable.hs | 5 | ||||
-rw-r--r-- | libraries/base/Data/Typeable/Internal.hs | 330 | ||||
-rw-r--r-- | libraries/base/GHC/Show.hs | 10 | ||||
-rw-r--r-- | libraries/base/GHC/Stack/Types.hs | 13 |
4 files changed, 245 insertions, 113 deletions
diff --git a/libraries/base/Data/Typeable.hs b/libraries/base/Data/Typeable.hs index c30a43dd65..1afc6a9563 100644 --- a/libraries/base/Data/Typeable.hs +++ b/libraries/base/Data/Typeable.hs @@ -58,7 +58,7 @@ module Data.Typeable -- * A canonical proxy type Proxy (..), - + -- * Type representations TypeRep, -- abstract, instance of: Eq, Show, Typeable typeRepFingerprint, @@ -66,6 +66,7 @@ module Data.Typeable showsTypeRep, TyCon, -- abstract, instance of: Eq, Show, Typeable + -- For now don't export Module, to avoid name clashes tyConFingerprint, tyConString, tyConPackage, @@ -87,7 +88,7 @@ module Data.Typeable typeRepArgs, -- :: TypeRep -> [TypeRep] ) where -import Data.Typeable.Internal hiding (mkTyCon) +import Data.Typeable.Internal import Data.Type.Equality import Unsafe.Coerce diff --git a/libraries/base/Data/Typeable/Internal.hs b/libraries/base/Data/Typeable/Internal.hs index e35d794a62..4379155c57 100644 --- a/libraries/base/Data/Typeable/Internal.hs +++ b/libraries/base/Data/Typeable/Internal.hs @@ -25,15 +25,34 @@ module Data.Typeable.Internal ( Proxy (..), - TypeRep(..), - KindRep, Fingerprint(..), + + -- * Typeable class typeOf, typeOf1, typeOf2, typeOf3, typeOf4, typeOf5, typeOf6, typeOf7, Typeable1, Typeable2, Typeable3, Typeable4, Typeable5, Typeable6, Typeable7, - TyCon(..), + + -- * Module + Module, -- Abstract + moduleName, modulePackage, + + -- * TyCon + TyCon, -- Abstract + tyConPackage, tyConModule, tyConName, tyConString, tyConFingerprint, + mkTyCon3, mkTyCon3#, + rnfTyCon, + + tcBool, tc'True, tc'False, + tcOrdering, tc'LT, tc'EQ, tc'GT, + tcChar, tcInt, tcWord, tcFloat, tcDouble, tcFun, + tcIO, tcSPEC, tcTyCon, tcModule, + tcCoercible, tcList, tcEq, + tcLiftedKind, tcUnliftedKind, tcOpenKind, tcBOX, tcConstraint, tcAnyK, + + funTc, -- ToDo + + -- * TypeRep + TypeRep(..), KindRep, typeRep, - mkTyCon, - mkTyCon3, mkTyConApp, mkPolyTyConApp, mkAppTy, @@ -47,19 +66,15 @@ module Data.Typeable.Internal ( typeRepFingerprint, rnfTypeRep, showsTypeRep, - tyConString, - rnfTyCon, - listTc, funTc, typeRepKinds, - typeNatTypeRep, - typeSymbolTypeRep + typeSymbolTypeRep, typeNatTypeRep ) where import GHC.Base import GHC.Word import GHC.Show -import GHC.TypeLits import Data.Proxy +import GHC.TypeLits( KnownNat, KnownSymbol, natVal', symbolVal' ) import GHC.Fingerprint.Type import {-# SOURCE #-} GHC.Fingerprint @@ -68,9 +83,106 @@ import {-# SOURCE #-} GHC.Fingerprint -- of Data.Typeable as much as possible so we can optimise the derived -- instances. --- | A concrete representation of a (monomorphic) type. 'TypeRep' --- supports reasonably efficient equality. +#include "MachDeps.h" + +{- ********************************************************************* +* * + The TyCon type +* * +********************************************************************* -} + +modulePackage :: Module -> String +modulePackage (Module p _) = trNameString p + +moduleName :: Module -> String +moduleName (Module _ m) = trNameString m + +tyConPackage :: TyCon -> String +tyConPackage (TyCon _ _ m _) = modulePackage m + +tyConModule :: TyCon -> String +tyConModule (TyCon _ _ m _) = moduleName m + +tyConName :: TyCon -> String +tyConName (TyCon _ _ _ n) = trNameString n + +trNameString :: TrName -> String +trNameString (TrNameS s) = unpackCString# s +trNameString (TrNameD s) = s + +-- | Observe string encoding of a type representation +{-# DEPRECATED tyConString "renamed to 'tyConName'; 'tyConModule' and 'tyConPackage' are also available." #-} +-- deprecated in 7.4 +tyConString :: TyCon -> String +tyConString = tyConName + +tyConFingerprint :: TyCon -> Fingerprint +tyConFingerprint (TyCon hi lo _ _) + = Fingerprint (W64# hi) (W64# lo) + +mkTyCon3# :: Addr# -- ^ package name + -> Addr# -- ^ module name + -> Addr# -- ^ the name of the type constructor + -> TyCon -- ^ A unique 'TyCon' object +mkTyCon3# pkg modl name + | Fingerprint (W64# hi) (W64# lo) <- fingerprint + = TyCon hi lo (Module (TrNameS pkg) (TrNameS modl)) (TrNameS name) + where + fingerprint :: Fingerprint + fingerprint = fingerprintString (unpackCString# pkg + ++ (' ': unpackCString# modl) + ++ (' ' : unpackCString# name)) + +mkTyCon3 :: String -- ^ package name + -> String -- ^ module name + -> String -- ^ the name of the type constructor + -> TyCon -- ^ A unique 'TyCon' object +-- Used when the strings are dynamically allocated, +-- eg from binary deserialisation +mkTyCon3 pkg modl name + | Fingerprint (W64# hi) (W64# lo) <- fingerprint + = TyCon hi lo (Module (TrNameD pkg) (TrNameD modl)) (TrNameD name) + where + fingerprint :: Fingerprint + fingerprint = fingerprintString (pkg ++ (' ':modl) ++ (' ':name)) + +isTupleTyCon :: TyCon -> Bool +isTupleTyCon tc + | ('(':',':_) <- tyConName tc = True + | otherwise = False + +-- | Helper to fully evaluate 'TyCon' for use as @NFData(rnf)@ implementation +-- +-- @since 4.8.0.0 +rnfModule :: Module -> () +rnfModule (Module p m) = rnfTrName p `seq` rnfTrName m + +rnfTrName :: TrName -> () +rnfTrName (TrNameS _) = () +rnfTrName (TrNameD n) = rnfString n + +rnfTyCon :: TyCon -> () +rnfTyCon (TyCon _ _ m n) = rnfModule m `seq` rnfTrName n + +rnfString :: [Char] -> () +rnfString [] = () +rnfString (c:cs) = c `seq` rnfString cs + + +{- ********************************************************************* +* * + The TypeRep type +* * +********************************************************************* -} + +-- | A concrete representation of a (monomorphic) type. +-- 'TypeRep' supports reasonably efficient equality. data TypeRep = TypeRep {-# UNPACK #-} !Fingerprint TyCon [KindRep] [TypeRep] + -- NB: For now I've made this lazy so that it's easy to + -- optimise code that constructs and deconstructs TypeReps + -- perf/should_run/T9203 is a good example + -- Also note that mkAppTy does discards the fingerprint, + -- so it's a waste to compute it type KindRep = TypeRep @@ -81,56 +193,42 @@ instance Eq TypeRep where instance Ord TypeRep where TypeRep x _ _ _ <= TypeRep y _ _ _ = x <= y +-- | Observe the 'Fingerprint' of a type representation +-- +-- @since 4.8.0.0 +typeRepFingerprint :: TypeRep -> Fingerprint +typeRepFingerprint (TypeRep fpr _ _ _) = fpr --- | An abstract representation of a type constructor. 'TyCon' objects can --- be built using 'mkTyCon'. -data TyCon = TyCon { - tyConFingerprint :: {-# UNPACK #-} !Fingerprint, -- ^ @since 4.8.0.0 - tyConPackage :: String, -- ^ @since 4.5.0.0 - tyConModule :: String, -- ^ @since 4.5.0.0 - tyConName :: String -- ^ @since 4.5.0.0 - } - -instance Eq TyCon where - (TyCon t1 _ _ _) == (TyCon t2 _ _ _) = t1 == t2 - -instance Ord TyCon where - (TyCon k1 _ _ _) <= (TyCon k2 _ _ _) = k1 <= k2 - ------------------ Construction -------------------- - -#include "MachDeps.h" - --- mkTyCon is an internal function to make it easier for GHC to --- generate derived instances. GHC precomputes the MD5 hash for the --- TyCon and passes it as two separate 64-bit values to mkTyCon. The --- TyCon for a derived Typeable instance will end up being statically --- allocated. - -#if WORD_SIZE_IN_BITS < 64 -mkTyCon :: Word64# -> Word64# -> String -> String -> String -> TyCon -#else -mkTyCon :: Word# -> Word# -> String -> String -> String -> TyCon -#endif -mkTyCon high# low# pkg modl name - = TyCon (Fingerprint (W64# high#) (W64# low#)) pkg modl name - --- | Applies a polymorhic type constructor to a sequence of kinds and types +-- | Applies a kind-polymorphic type constructor to a sequence of kinds and +-- types mkPolyTyConApp :: TyCon -> [KindRep] -> [TypeRep] -> TypeRep -mkPolyTyConApp tc@(TyCon tc_k _ _ _) [] [] = TypeRep tc_k tc [] [] -mkPolyTyConApp tc@(TyCon tc_k _ _ _) kinds types = - TypeRep (fingerprintFingerprints (tc_k : arg_ks)) tc kinds types +{-# INLINE mkPolyTyConApp #-} +mkPolyTyConApp tc kinds types + = TypeRep (fingerprintFingerprints sub_fps) tc kinds types where - arg_ks = [ k | TypeRep k _ _ _ <- kinds ++ types ] + !kt_fps = typeRepFingerprints kinds types + sub_fps = tyConFingerprint tc : kt_fps --- | Applies a monomorphic type constructor to a sequence of types +typeRepFingerprints :: [KindRep] -> [TypeRep] -> [Fingerprint] +-- Builds no thunks +typeRepFingerprints kinds types + = go1 [] kinds + where + go1 acc [] = go2 acc types + go1 acc (k:ks) = let !fp = typeRepFingerprint k + in go1 (fp:acc) ks + go2 acc [] = acc + go2 acc (t:ts) = let !fp = typeRepFingerprint t + in go2 (fp:acc) ts + +-- | Applies a kind-monomorphic type constructor to a sequence of types mkTyConApp :: TyCon -> [TypeRep] -> TypeRep mkTyConApp tc = mkPolyTyConApp tc [] -- | A special case of 'mkTyConApp', which applies the function -- type constructor to a pair of types. mkFunTy :: TypeRep -> TypeRep -> TypeRep -mkFunTy f a = mkTyConApp funTc [f,a] +mkFunTy f a = mkTyConApp tcFun [f,a] -- | Splits a type constructor application. -- Note that if the type construcotr is polymorphic, this will @@ -150,11 +248,12 @@ splitPolyTyConApp (TypeRep _ tc ks trs) = (tc,ks,trs) funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep funResultTy trFun trArg = case splitTyConApp trFun of - (tc, [t1,t2]) | tc == funTc && t1 == trArg -> Just t2 + (tc, [t1,t2]) | tc == tcFun && t1 == trArg -> Just t2 _ -> Nothing -- | Adds a TypeRep argument to a TypeRep. mkAppTy :: TypeRep -> TypeRep -> TypeRep +{-# INLINE mkAppTy #-} mkAppTy (TypeRep _ tc ks trs) arg_tr = mkPolyTyConApp tc ks (trs ++ [arg_tr]) -- Notice that we call mkTyConApp to construct the fingerprint from tc and -- the arg fingerprints. Simply combining the current fingerprint with @@ -162,20 +261,6 @@ mkAppTy (TypeRep _ tc ks trs) arg_tr = mkPolyTyConApp tc ks (trs ++ [arg_tr]) -- ensure that a TypeRep of the same shape has the same fingerprint! -- See Trac #5962 --- | Builds a 'TyCon' object representing a type constructor. An --- implementation of "Data.Typeable" should ensure that the following holds: --- --- > A==A' ^ B==B' ^ C==C' ==> mkTyCon A B C == mkTyCon A' B' C' --- - --- -mkTyCon3 :: String -- ^ package name - -> String -- ^ module name - -> String -- ^ the name of the type constructor - -> TyCon -- ^ A unique 'TyCon' object -mkTyCon3 pkg modl name = - TyCon (fingerprintString (pkg ++ (' ':modl) ++ (' ':name))) pkg modl name - ----------------- Observation --------------------- -- | Observe the type constructor of a type representation @@ -190,16 +275,12 @@ typeRepArgs (TypeRep _ _ _ tys) = tys typeRepKinds :: TypeRep -> [KindRep] typeRepKinds (TypeRep _ _ ks _) = ks --- | Observe string encoding of a type representation -{-# DEPRECATED tyConString "renamed to 'tyConName'; 'tyConModule' and 'tyConPackage' are also available." #-} -- deprecated in 7.4 -tyConString :: TyCon -> String -tyConString = tyConName --- | Observe the 'Fingerprint' of a type representation --- --- @since 4.8.0.0 -typeRepFingerprint :: TypeRep -> Fingerprint -typeRepFingerprint (TypeRep fpr _ _ _) = fpr +{- ********************************************************************* +* * + The Typeable class +* * +********************************************************************* -} ------------------------------------------------------------- -- @@ -273,8 +354,8 @@ instance Show TypeRep where showsPrec p (TypeRep _ tycon kinds tys) = case tys of [] -> showsPrec p tycon - [x] | tycon == listTc -> showChar '[' . shows x . showChar ']' - [a,r] | tycon == funTc -> showParen (p > 8) $ + [x] | tycon == tcList -> showChar '[' . shows x . showChar ']' + [a,r] | tycon == tcFun -> showParen (p > 8) $ showsPrec 9 a . showString " -> " . showsPrec 8 r @@ -288,13 +369,6 @@ instance Show TypeRep where showsTypeRep :: TypeRep -> ShowS showsTypeRep = shows -instance Show TyCon where - showsPrec _ t = showString (tyConName t) - -isTupleTyCon :: TyCon -> Bool -isTupleTyCon (TyCon _ _ _ ('(':',':_)) = True -isTupleTyCon _ = False - -- | Helper to fully evaluate 'TypeRep' for use as @NFData(rnf)@ implementation -- -- @since 4.8.0.0 @@ -304,15 +378,6 @@ rnfTypeRep (TypeRep _ tyc krs tyrs) = rnfTyCon tyc `seq` go krs `seq` go tyrs go [] = () go (x:xs) = rnfTypeRep x `seq` go xs --- | Helper to fully evaluate 'TyCon' for use as @NFData(rnf)@ implementation --- --- @since 4.8.0.0 -rnfTyCon :: TyCon -> () -rnfTyCon (TyCon _ tcp tcm tcn) = go tcp `seq` go tcm `seq` go tcn - where - go [] = () - go (x:xs) = x `seq` go xs - -- Some (Show.TypeRep) helpers: showArgs :: Show a => ShowS -> [a] -> ShowS @@ -325,13 +390,68 @@ showTuple args = showChar '(' . showArgs (showChar ',') args . showChar ')' -listTc :: TyCon -listTc = typeRepTyCon (typeOf [()]) +{- ********************************************************* +* * +* TyCon definitions for GHC.Types * +* * +********************************************************* -} + +mkGhcTypesTyCon :: Addr# -> TyCon +{-# INLINE mkGhcTypesTyCon #-} +mkGhcTypesTyCon name = mkTyCon3# "ghc-prim"# "GHC.Types"# name + +tcBool, tc'True, tc'False, + tcOrdering, tc'GT, tc'EQ, tc'LT, + tcChar, tcInt, tcWord, tcFloat, tcDouble, tcFun, + tcIO, tcSPEC, tcTyCon, tcModule, + tcCoercible, tcEq, tcList :: TyCon + +tcBool = mkGhcTypesTyCon "Bool"# -- Bool is promotable +tc'True = mkGhcTypesTyCon "'True"# +tc'False = mkGhcTypesTyCon "'False"# +tcOrdering = mkGhcTypesTyCon "Ordering"# -- Ordering is promotable +tc'GT = mkGhcTypesTyCon "'GT"# +tc'EQ = mkGhcTypesTyCon "'EQ"# +tc'LT = mkGhcTypesTyCon "'LT"# + +-- None of the rest are promotable (see TysWiredIn) +tcChar = mkGhcTypesTyCon "Char"# +tcInt = mkGhcTypesTyCon "Int"# +tcWord = mkGhcTypesTyCon "Word"# +tcFloat = mkGhcTypesTyCon "Float"# +tcDouble = mkGhcTypesTyCon "Double"# +tcSPEC = mkGhcTypesTyCon "SPEC"# +tcIO = mkGhcTypesTyCon "IO"# +tcTyCon = mkGhcTypesTyCon "TyCon"# +tcModule = mkGhcTypesTyCon "Module"# +tcCoercible = mkGhcTypesTyCon "Coercible"# + +tcFun = mkGhcTypesTyCon "->"# +tcList = mkGhcTypesTyCon "[]"# -- Type rep for the list type constructor +tcEq = mkGhcTypesTyCon "~"# -- Type rep for the (~) type constructor + +tcLiftedKind, tcUnliftedKind, tcOpenKind, tcBOX, tcConstraint, tcAnyK :: TyCon +tcLiftedKind = mkGhcTypesTyCon "*"# +tcUnliftedKind = mkGhcTypesTyCon "#"# +tcOpenKind = mkGhcTypesTyCon "#"# +tcBOX = mkGhcTypesTyCon "BOX"# +tcAnyK = mkGhcTypesTyCon "AnyK"# +tcConstraint = mkGhcTypesTyCon "Constraint"# funTc :: TyCon -funTc = typeRepTyCon (typeRep (Proxy :: Proxy (->))) +funTc = tcFun -- Legacy + +{- ********************************************************* +* * +* TyCon/TypeRep definitions for type literals * +* (Symbol and Nat) * +* * +********************************************************* -} +mkTypeLitTyCon :: String -> TyCon +mkTypeLitTyCon name = mkTyCon3 "base" "GHC.TypeLits" name + -- | Used to make `'Typeable' instance for things of kind Nat typeNatTypeRep :: KnownNat a => Proxy# a -> TypeRep typeNatTypeRep p = typeLitTypeRep (show (natVal' p)) @@ -342,17 +462,5 @@ typeSymbolTypeRep p = typeLitTypeRep (show (symbolVal' p)) -- | An internal function, to make representations for type literals. typeLitTypeRep :: String -> TypeRep -typeLitTypeRep nm = rep - where - rep = mkTyConApp tc [] - tc = TyCon - { tyConFingerprint = fingerprintString (mk pack modu nm) - , tyConPackage = pack - , tyConModule = modu - , tyConName = nm - } - pack = "base" - modu = "GHC.TypeLits" - mk a b c = a ++ " " ++ b ++ " " ++ c - +typeLitTypeRep nm = mkTyConApp (mkTypeLitTyCon nm) [] diff --git a/libraries/base/GHC/Show.hs b/libraries/base/GHC/Show.hs index 4aeecb15f3..879d666bb0 100644 --- a/libraries/base/GHC/Show.hs +++ b/libraries/base/GHC/Show.hs @@ -194,6 +194,16 @@ showWord w# cs deriving instance Show a => Show (Maybe a) +instance Show TyCon where + showsPrec p (TyCon _ _ _ tc_name) = showsPrec p tc_name + +instance Show TrName where + showsPrec _ (TrNameS s) = showString (unpackCString# s) + showsPrec _ (TrNameD s) = showString s + +instance Show Module where + showsPrec _ (Module p m) = shows p . (':' :) . shows m + -------------------------------------------------------------- -- Show instances for the first few tuple -------------------------------------------------------------- diff --git a/libraries/base/GHC/Stack/Types.hs b/libraries/base/GHC/Stack/Types.hs index 5c37f64713..d3ea1d2147 100644 --- a/libraries/base/GHC/Stack/Types.hs +++ b/libraries/base/GHC/Stack/Types.hs @@ -21,6 +21,19 @@ module GHC.Stack.Types ( SrcLoc(..), CallStack(..), ) where +{- +Ideally these would live in GHC.Stack but sadly they can't due to this +import cycle, + + Module imports form a cycle: + module ‘Data.Maybe’ (libraries/base/Data/Maybe.hs) + imports ‘GHC.Base’ (libraries/base/GHC/Base.hs) + which imports ‘GHC.Err’ (libraries/base/GHC/Err.hs) + which imports ‘GHC.Stack’ (libraries/base/dist-install/build/GHC/Stack.hs) + which imports ‘GHC.Foreign’ (libraries/base/GHC/Foreign.hs) + which imports ‘Data.Maybe’ (libraries/base/Data/Maybe.hs) +-} + import GHC.Types -- Make implicit dependency known to build system |