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
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.}
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#
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\#}.}
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
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
with
out_of_line = True
-primop GetStackFrame "getStackFrame#" GenPrimOp
- ThreadId# -> Int# -> (# Int#, Int# #)
- with
- out_of_line = True
-
------------------------------------------------------------------------
section "Etc"
{Miscellaneous built-ins}
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
+
+ * 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) -> ...".
------------------------------------------------------------------------
--- ---