+pseudoop "seq"
+ a -> b -> b
+ { Evaluates its first argument to head normal form, and then returns its second
+ argument as the result. }
+
+pseudoop "inline"
+ a -> a
+ { The call {\tt (inline f)} arranges that f is inlined, regardless of its size.
+ More precisely, the call {\tt (inline f)} rewrites to the right-hand side of
+ {\tt f}'s definition. This allows the programmer to control inlining from a
+ particular call site rather than the definition site of the function (c.f.
+ {\tt INLINE} pragmas in User's Guide, Section 7.10.3, "INLINE and NOINLINE
+ pragmas").
+
+ This inlining occurs regardless of the argument to the call or the size of
+ {\tt f}'s definition; it is unconditional. The main caveat is that {\tt f}'s
+ definition must be visible to the compiler. That is, {\tt f} must be
+ {\tt let}-bound in the current scope. If no inlining takes place, the
+ {\tt inline} function expands to the identity function in Phase zero; so its
+ use imposes no overhead.
+
+ It is good practice to mark the function with an INLINABLE pragma at
+ its definition, (a) so that GHC guarantees to expose its unfolding regardless
+ of size, and (b) so that you have control over exactly what is inlined. }
+
+pseudoop "lazy"
+ a -> a
+ { The {\tt lazy} function restrains strictness analysis a little. The call
+ {\tt (lazy e)} means the same as {\tt e}, but {\tt lazy} has a magical
+ property so far as strictness analysis is concerned: it is lazy in its first
+ argument, even though its semantics is strict. After strictness analysis has
+ run, calls to {\tt lazy} are inlined to be the identity function.
+
+ This behaviour is occasionally useful when controlling evaluation order.
+ Notably, {\tt lazy} is used in the library definition of {\tt Control.Parallel.par}:
+
+ {\tt par :: a -> b -> b}
+
+ {\tt par x y = case (par\# x) of \_ -> lazy y}
+
+ If {\tt lazy} were not lazy, {\tt par} would look strict in {\tt y} which
+ would defeat the whole purpose of {\tt par}.
+
+ Like {\tt seq}, the argument of {\tt lazy} can have an unboxed type. }
+
+primtype Any a
+ { The type constructor {\tt Any} is type to which you can unsafely coerce any
+ lifted type, and back.
+
+ * It is lifted, and hence represented by a pointer
+
+ * It does not claim to be a {\it data} type, and that's important for
+ the code generator, because the code gen may {\it enter} a data value
+ but never enters a function value.
+
+ It's also used to instantiate un-constrained type variables after type
+ checking. For example, {\tt length} has type
+
+ {\tt length :: forall a. [a] -> Int}
+
+ and the list datacon for the empty list has type
+
+ {\tt [] :: forall a. [a]}
+
+ In order to compose these two terms as {\tt length []} a type
+ application is required, but there is no constraint on the
+ choice. In this situation GHC uses {\tt Any}:
+
+ {\tt length Any ([] Any)}
+
+ Annoyingly, we sometimes need {\tt Any}s of other kinds, such as {\tt (* -> *)} etc.
+ This is a bit like tuples. We define a couple of useful ones here,
+ and make others up on the fly. If any of these others end up being exported
+ into interface files, we'll get a crash; at least until we add interface-file
+ syntax to support them. }
+
+pseudoop "unsafeCoerce#"
+ a -> b
+ { The function {\tt unsafeCoerce\#} allows you to side-step the typechecker entirely. That
+ is, it allows you to coerce any type into any other type. If you use this function,
+ you had better get it right, otherwise segmentation faults await. It is generally
+ 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 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) -> ...".
+
+primop TraceEventOp "traceEvent#" GenPrimOp
+ Addr# -> State# s -> State# s
+ { Emits an event via the RTS tracing framework. The contents
+ of the event is the zero-terminated byte string passed as the first
+ argument. The event will be emitted either to the .eventlog file,
+ or to stderr, depending on the runtime RTS flags. }
+ with
+ has_side_effects = True
+ out_of_line = True