summaryrefslogtreecommitdiff
path: root/compiler/prelude
diff options
context:
space:
mode:
authorJoachim Breitner <mail@joachim-breitner.de>2013-09-13 18:40:36 +0200
committerJoachim Breitner <mail@joachim-breitner.de>2013-09-13 21:58:26 +0200
commit17a868afa169c52d8525a95cbed87b2fc12044c6 (patch)
treea04530408077a286a80ca8d34c5d6dc0c98eddc6 /compiler/prelude
parent638da2fecaaaf743c4da7f8e2522f4afc0d8400c (diff)
downloadhaskell-coercible.tar.gz
Introduce coerce :: Coercible a b -> a -> bcoercible
This is the result of the design at http://ghc.haskell.org/trac/ghc/wiki/NewtypeWrappers The goal is to be able to convert between, say [First Int] and [Last Int] with zero run-time overhead. To that end, we introduce a special two parameter type class Coercible whose instances are created automatically and on-the fly. This relies on and exploits the recent addition of roles to core.
Diffstat (limited to 'compiler/prelude')
-rw-r--r--compiler/prelude/PrelInfo.lhs2
-rw-r--r--compiler/prelude/PrelNames.lhs15
-rw-r--r--compiler/prelude/TysWiredIn.lhs27
-rw-r--r--compiler/prelude/primops.txt.pp56
4 files changed, 97 insertions, 3 deletions
diff --git a/compiler/prelude/PrelInfo.lhs b/compiler/prelude/PrelInfo.lhs
index 4a39977797..0ef5b32eb3 100644
--- a/compiler/prelude/PrelInfo.lhs
+++ b/compiler/prelude/PrelInfo.lhs
@@ -130,7 +130,7 @@ ghcPrimExports
= map (Avail . idName) ghcPrimIds ++
map (Avail . idName . primOpId) allThePrimOps ++
[ AvailTC n [n]
- | tc <- funTyCon : primTyCons, let n = tyConName tc ]
+ | tc <- funTyCon : coercibleTyCon : primTyCons, let n = tyConName tc ]
\end{code}
diff --git a/compiler/prelude/PrelNames.lhs b/compiler/prelude/PrelNames.lhs
index acac400c04..dfb3f82b7b 100644
--- a/compiler/prelude/PrelNames.lhs
+++ b/compiler/prelude/PrelNames.lhs
@@ -352,7 +352,7 @@ genericTyConNames = [
pRELUDE :: Module
pRELUDE = mkBaseModule_ pRELUDE_NAME
-gHC_PRIM, gHC_PRIMWRAPPERS, gHC_TYPES, gHC_GENERICS, gHC_MAGIC,
+gHC_PRIM, gHC_PRIMWRAPPERS, gHC_TYPES, gHC_GENERICS, gHC_MAGIC, gHC_COERCIBLE,
gHC_CLASSES, gHC_BASE, gHC_ENUM, gHC_GHCI, gHC_CSTRING,
gHC_SHOW, gHC_READ, gHC_NUM, gHC_INTEGER_TYPE, gHC_LIST,
gHC_TUPLE, dATA_TUPLE, dATA_EITHER, dATA_STRING, dATA_FOLDABLE, dATA_TRAVERSABLE, dATA_MONOID,
@@ -370,6 +370,7 @@ gHC_TYPES = mkPrimModule (fsLit "GHC.Types")
gHC_MAGIC = mkPrimModule (fsLit "GHC.Magic")
gHC_CSTRING = mkPrimModule (fsLit "GHC.CString")
gHC_CLASSES = mkPrimModule (fsLit "GHC.Classes")
+gHC_COERCIBLE = mkPrimModule (fsLit "GHC.Coercible")
gHC_BASE = mkBaseModule (fsLit "GHC.Base")
gHC_ENUM = mkBaseModule (fsLit "GHC.Enum")
@@ -1486,6 +1487,11 @@ doubleX2PrimTyConKey = mkPreludeTyConUnique 171
int32X4PrimTyConKey = mkPreludeTyConUnique 172
int64X2PrimTyConKey = mkPreludeTyConUnique 173
+ntTyConKey:: Unique
+ntTyConKey = mkPreludeTyConUnique 174
+coercibleTyConKey :: Unique
+coercibleTyConKey = mkPreludeTyConUnique 175
+
---------------- Template Haskell -------------------
-- USES TyConUniques 200-299
-----------------------------------------------------
@@ -1504,7 +1510,7 @@ unitTyConKey = mkTupleTyConUnique BoxedTuple 0
charDataConKey, consDataConKey, doubleDataConKey, falseDataConKey,
floatDataConKey, intDataConKey, nilDataConKey, ratioDataConKey,
stableNameDataConKey, trueDataConKey, wordDataConKey,
- ioDataConKey, integerDataConKey, eqBoxDataConKey :: Unique
+ ioDataConKey, integerDataConKey, eqBoxDataConKey, coercibleDataConKey :: Unique
charDataConKey = mkPreludeDataConUnique 1
consDataConKey = mkPreludeDataConUnique 2
doubleDataConKey = mkPreludeDataConUnique 3
@@ -1544,6 +1550,8 @@ gtDataConKey = mkPreludeDataConUnique 29
integerGmpSDataConKey, integerGmpJDataConKey :: Unique
integerGmpSDataConKey = mkPreludeDataConUnique 30
integerGmpJDataConKey = mkPreludeDataConUnique 31
+
+coercibleDataConKey = mkPreludeDataConUnique 32
\end{code}
%************************************************************************
@@ -1710,6 +1718,9 @@ undefinedKey = mkPreludeMiscIdUnique 155
magicSingIKey :: Unique
magicSingIKey = mkPreludeMiscIdUnique 156
+
+coerceKey :: Unique
+coerceKey = mkPreludeMiscIdUnique 157
\end{code}
Certain class operations from Prelude classes. They get their own
diff --git a/compiler/prelude/TysWiredIn.lhs b/compiler/prelude/TysWiredIn.lhs
index d8c880f1c3..443c09cf1e 100644
--- a/compiler/prelude/TysWiredIn.lhs
+++ b/compiler/prelude/TysWiredIn.lhs
@@ -68,6 +68,7 @@ module TysWiredIn (
-- * Equality predicates
eqTyCon_RDR, eqTyCon, eqTyConName, eqBoxDataCon,
+ coercibleTyCon, coercibleDataCon, coercibleClass,
mkWiredInTyConName -- This is used in TcTypeNats to define the
-- built-in functions for evaluation.
@@ -88,6 +89,7 @@ import Type ( mkTyConApp )
import DataCon
import Var
import TyCon
+import Class ( Class, mkClass )
import TypeRep
import RdrName
import Name
@@ -147,6 +149,7 @@ wiredInTyCons = [ unitTyCon -- Not treated like other tuples, because
, listTyCon
, parrTyCon
, eqTyCon
+ , coercibleTyCon
, typeNatKindCon
, typeSymbolKindCon
]
@@ -172,6 +175,10 @@ eqTyConName, eqBoxDataConName :: Name
eqTyConName = mkWiredInTyConName BuiltInSyntax gHC_TYPES (fsLit "~") eqTyConKey eqTyCon
eqBoxDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "Eq#") eqBoxDataConKey eqBoxDataCon
+coercibleTyConName, coercibleDataConName :: Name
+coercibleTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Coercible") coercibleTyConKey coercibleTyCon
+coercibleDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "MkCoercible") coercibleDataConKey coercibleDataCon
+
charTyConName, charDataConName, intTyConName, intDataConName :: Name
charTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Char") charTyConKey charTyCon
charDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "C#") charDataConKey charDataCon
@@ -451,6 +458,26 @@ eqBoxDataCon = pcDataCon eqBoxDataConName args [TyConApp eqPrimTyCon (map mkTyVa
k = mkTyVarTy kv
a:b:_ = tyVarList k
args = [kv, a, b]
+
+
+coercibleTyCon :: TyCon
+coercibleTyCon = mkClassTyCon
+ coercibleTyConName kind tvs [Representational, Representational]
+ rhs coercibleClass NonRecursive
+ where kind = mkArrowKinds [liftedTypeKind, liftedTypeKind] constraintKind
+ a:b:_ = tyVarList liftedTypeKind
+ tvs = [a, b]
+ rhs = DataTyCon [coercibleDataCon] False
+
+coercibleDataCon :: DataCon
+coercibleDataCon = pcDataCon coercibleDataConName args [TyConApp eqReprPrimTyCon (liftedTypeKind : map mkTyVarTy args)] coercibleTyCon
+ where
+ a:b:_ = tyVarList liftedTypeKind
+ args = [a, b]
+
+coercibleClass :: Class
+coercibleClass = mkClass (tyConTyVars coercibleTyCon) [] [] [] [] [] coercibleTyCon
+
\end{code}
\begin{code}
diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index 094c2f55e6..a59dfd624d 100644
--- a/compiler/prelude/primops.txt.pp
+++ b/compiler/prelude/primops.txt.pp
@@ -2279,6 +2279,62 @@ primop TraceMarkerOp "traceMarker#" GenPrimOp
has_side_effects = True
out_of_line = True
+------------------------------------------------------------------------
+section "Safe coercions"
+------------------------------------------------------------------------
+
+pseudoop "coerce"
+ Coercible a b => a -> b
+ { The function {\tt coerce} allows you to safely convert between values of
+ types that have the same representation with no run-time overhead. In the
+ simplest case you can use it instead of a newtype constructor, to go from
+ the newtype's concrete type to the abstract type. But it also works in
+ more complicated settings, e.g. converting a list of newtypes to a list of
+ concrete types.
+ }
+
+primclass Coercible a b
+ { This two-parameter class has instances for types {\tt a} and {\tt b} if
+ the compiler can infer that they have the same representation. This class
+ does not have regular instances; instead they are created on-the-fly during
+ type-checking. Trying to manually declare an instance of {\tt Coercible}
+ is an error.
+
+ Nevertheless one can pretend that the following three kinds of instances
+ exist. First, as a trivial base-case:
+
+ {\tt instance a a}
+
+ Furthermore, for every type constructor there is
+ an instance that allows to coerce under the type constructor. For
+ example, let {\tt D} be a prototypical type constructor ({\tt data} or {\tt
+ newtype}) with three type arguments, which have roles Nominal,
+ Representational resp. Phantom. Then there is an instance of the form
+
+ {\tt instance Coercible b b' => Coercible (D a b c) (D a b' c')}
+
+ Note that the nominal type arguments are equal, the representational type
+ arguments can differ, but need to have a {\tt Coercible} instance
+ themself, and the phantom type arguments can be changed arbitrarily.
+
+ In SafeHaskell code, this instance is only usable if the constructors of
+ every type constructor used in the definition of {\tt D} (including
+ those of {\tt D} itself) is in scope.
+
+ The third kind of instance exists for every {\tt newtype NT = MkNT T} and
+ comes in two variants, namely
+
+ {\tt instance Coercible a T => Coercible a NT}
+
+ {\tt instance Coercible T b => Coercible NT b}
+
+ This instance is only usable if the constructor {\tt MkNT} is in scope.
+
+ If, as a library author of a type constructor like {\tt Set a}, you
+ want to prevent a user of your module to write
+ {\tt coerce :: Set T -> Set NT},
+ you need to set the role of {\tt Set}'s type parameter to Nominal.
+ }
------------------------------------------------------------------------
section "Float SIMD Vectors"