clarify that unsafeCoerce# :: Float# -> Int# is not safe (see #2209)
[ghc-hetmet.git] / compiler / prelude / primops.txt.pp
index 54d72f0..471cba1 100644 (file)
@@ -545,6 +545,10 @@ primop   DoubleDivOp   "/##"   Dyadic
 primop   DoubleNegOp   "negateDouble#"  Monadic   Double# -> Double#
 
 primop   Double2IntOp   "double2Int#"          GenPrimOp  Double# -> Int#
+   {Truncates a {\tt Double#} value to the nearest {\tt Int#}.
+    Results are undefined if the truncation if truncation yields
+    a value outside the range of {\tt Int#}.}
+
 primop   Double2FloatOp   "double2Float#" GenPrimOp Double# -> Float#
 
 primop   DoubleExpOp   "expDouble#"      Monadic
@@ -614,6 +618,13 @@ primop   DoubleDecodeOp   "decodeDouble#" GenPrimOp
     represent an {\tt Integer\#} holding the mantissa.}
    with out_of_line = True
 
+primop   DoubleDecode_2IntOp   "decodeDouble_2Int#" GenPrimOp    
+   Double# -> (# Int#, Int#, Int# #)
+   {Convert to arbitrary-precision integer.
+    First {\tt Int\#} in result is the high 32 bits of the mantissa, and the
+    second is the low 32. The third is the exponent.}
+   with out_of_line = True
+
 ------------------------------------------------------------------------
 section "Float#" 
        {Operations on single-precision (32-bit) floating-point numbers.}
@@ -652,6 +663,9 @@ primop   FloatDivOp   "divideFloat#"      Dyadic
 primop   FloatNegOp   "negateFloat#"      Monadic    Float# -> Float#
 
 primop   Float2IntOp   "float2Int#"      GenPrimOp  Float# -> Int#
+   {Truncates a {\tt Float#} value to the nearest {\tt Int#}.
+    Results are undefined if the truncation if truncation yields
+    a value outside the range of {\tt Int#}.}
 
 primop   FloatExpOp   "expFloat#"      Monadic          
    Float# -> Float#
@@ -717,6 +731,12 @@ primop   FloatDecodeOp   "decodeFloat#" GenPrimOp
     represent an {\tt Integer\#} holding the mantissa.}
    with out_of_line = True
 
+primop   FloatDecode_IntOp   "decodeFloat_Int#" GenPrimOp
+   Float# -> (# Int#, Int# #)
+   {Convert to arbitrary-precision integer.
+    First {\tt Int\#} in result is the mantissa; second is the exponent.}
+   with out_of_line = True
+
 ------------------------------------------------------------------------
 section "Arrays"
        {Operations on {\tt Array\#}.}
@@ -1233,7 +1253,7 @@ primop  CatchOp "catch#" GenPrimOp
 primop  RaiseOp "raise#" GenPrimOp
    a -> b
    with
-   strictness  = { \ arity -> mkStrictSig (mkTopDmdType [lazyDmd] BotRes) }
+   strictness  = { \ _arity -> mkStrictSig (mkTopDmdType [lazyDmd] BotRes) }
       -- NB: result is bottom
    out_of_line = True
 
@@ -1653,7 +1673,7 @@ section "Tag to enum stuff"
 primop  DataToTagOp "dataToTag#" GenPrimOp
    a -> Int#
    with
-   strictness  = { \ arity -> mkStrictSig (mkTopDmdType [seqDmd] TopRes) }
+   strictness  = { \ _arity -> mkStrictSig (mkTopDmdType [seqDmd] TopRes) }
        -- dataToTag# must have an evaluated argument
 
 primop  TagToEnumOp "tagToEnum#" GenPrimOp     
@@ -1773,9 +1793,39 @@ pseudoop   "unsafeCoerce#"
        used when you want to write a program that you know is well-typed, but where Haskell's
        type system is not expressive enough to prove that it is well typed.
 
-       The argument to {\tt unsafeCoerce\#} can have unboxed types, although extremely bad
-       things will happen if you coerce a boxed type to an unboxed type.  }
+        The following uses of {\tt unsafeCoerce\#} are supposed to work (i.e. not lead to
+        spurious compile-time or run-time crashes):
+
+         * Casting any lifted type to {\tt Any}
+
+         * Casting {\tt Any} back to the real type
 
+         * Casting an unboxed type to another unboxed type of the same size
+           (but not coercions between floating-point and integral types)
+
+         * Casting between two types that have the same runtime representation.  One case is when
+           the two types differ only in "phantom" type parameters, for example
+           {\tt Ptr Int} to {\tt Ptr Float}, or {\tt [Int]} to {\tt [Float]} when the list is 
+           known to be empty.  Also, a {\tt newtype} of a type {\tt T} has the same representation
+           at runtime as {\tt T}.
+
+        Other uses of {\tt unsafeCoerce\#} are undefined.  In particular, you should not use
+       {\tt unsafeCoerce\#} to cast a T to an algebraic data type D, unless T is also
+       an algebraic data type.  For example, do not cast {\tt Int->Int} to {\tt Bool}, even if
+        you later cast that {\tt Bool} back to {\tt Int->Int} before applying it.  The reasons
+        have to do with GHC's internal representation details (for the congnoscenti, data values
+       can be entered but function closures cannot).  If you want a safe type to cast things
+       to, use {\tt Any}, which is not an algebraic data type.
+       
+        }
+
+-- NB. It is tempting to think that casting a value to a type that it doesn't have is safe
+-- as long as you don't "do anything" with the value in its cast form, such as seq on it.  This
+-- isn't the case: the compiler can insert seqs itself, and if these happen at the wrong type,
+-- Bad Things Might Happen.  See bug #1616: in this case we cast a function of type (a,b) -> (a,b)
+-- to () -> () and back again.  The strictness analyser saw that the function was strict, but
+-- the wrapper had type () -> (), and hence the wrapper de-constructed the (), the worker re-constructed
+-- a new (), with the result that the code ended up with "case () of (a,b) -> ...".
 
 ------------------------------------------------------------------------
 ---                                                                  ---