{-# LANGUAGE Strict #-} {-# OPTIONS_GHC -fexpose-all-unfoldings #-} {-| Functions in this module are for internal compiler use only, and should not be used elsewhere. -} module PlutusTx.AsData.Internal where import PlutusTx.Builtins.Internal as BI -- See Note [Compiling AsData Matchers and Their Invocations] -- This may no longer be needed post the van Rossem HF. It needs to be examined and verified. wrapUnsafeDataAsConstr :: BuiltinData -> BuiltinPair BuiltinInteger (BuiltinList BuiltinData) wrapUnsafeDataAsConstr :: BuiltinData -> BuiltinPair BuiltinInteger (BuiltinList BuiltinData) wrapUnsafeDataAsConstr = BuiltinData -> BuiltinPair BuiltinInteger (BuiltinList BuiltinData) BI.unsafeDataAsConstr {-# OPAQUE wrapUnsafeDataAsConstr #-} -- See Note [Dropping redundant unsafeCaseList calls produced by AsData] droppableUnsafeCaseList :: forall a r. (a -> BuiltinList a -> r) -> BuiltinList a -> r droppableUnsafeCaseList :: forall a r. (a -> BuiltinList a -> r) -> BuiltinList a -> r droppableUnsafeCaseList = (a -> BuiltinList a -> r) -> BuiltinList a -> r forall a r. (a -> BuiltinList a -> r) -> BuiltinList a -> r BI.unsafeCaseList {-# OPAQUE droppableUnsafeCaseList #-} -- See Note [Use list casing in AsData pattern synonyms] directUnsafeCaseList :: BuiltinList a -> (a, BuiltinList a) directUnsafeCaseList :: forall a. BuiltinList a -> (a, BuiltinList a) directUnsafeCaseList = (a -> BuiltinList a -> (a, BuiltinList a)) -> BuiltinList a -> (a, BuiltinList a) forall a r. (a -> BuiltinList a -> r) -> BuiltinList a -> r BI.unsafeCaseList (,) {-# OPAQUE directUnsafeCaseList #-} {- Note [Compiling AsData Matchers and Their Invocations] The AsData matchers, such as `AsData.Budget.Types.$mInts`, eagerly unpack all fields, even for unused fields. This leads to strict dead bindings. Since they are strict and the inliner doesn't know that they are effect-free, it can't remove them. It is not uncommon that only one or a small number of fields in `ScriptContext` are used, so this could cause severe performance penalties. The matches are generated by GHC for pattern synonyms, not written by hand. As a result, they are unfortunately not customizable - for example, by attaching certain annotations to certain variables as signals for the Plinth compiler. The workaround are the wrapper functions in this module. `wrapUnsafeDataAsConstr` is marked OPAQUE so that GHC doesn't inline it, yet its unfolding is made available via `-fexpose-all-unfoldings`. `wrapUnsafeDataAsConstr` is supposed to be used by AsData only, and not elsewhere, and the Plinth compiler relies on it to identify which functions are AsData matchers. An AsData matcher unpacks the fields and passes them to a continuation. What we need is to mark the variables bound in the continuation as safe to inline. For instance, if the continuation is `\x y z w -> f x` (indicating a data type with 4 fields, of which only the first is used), marking `x`, `y`, `z` and `w` as safe to inline allows the inliner to drop the unused ones. -} {- Note [Dropping redundant unsafeCaseList calls produced by AsData] AsData generates `unsafeCaseList` calls to unpack lists in the Data. It unpacks a list completely, obtaining all fields, then calls the continuation with the fields. This can lead to unnecessary `unsafeCaseList` calls, if the continuation does not access all fields. In general, we cannot drop the unnecessary `unsafeCaseList` calls, because doing so may change the semantics: `unsafeCaseList` throws an error if the list is empty, and dropping it would eliminate the error. However, we know that the `unsafeCaseList` calls generated from AsData are never applied to empty lists, so redundant ones can be dropped safely. To do so, we annotate the `case` expressions with `SafeToDrop`, and use a PIR simplifier pass, DeadCase, to drop the redundant ones. -} {- Note [Use list casing in AsData pattern synonyms] AsData pattern synonyms cannot directly call `unsafeCaseList` or `droppableUnsafeCaseList` because they are CPS-style functions and aren't compatible with view patterns. The solution is to introduce an opaque, direct-style `directUnsafeCaseList`, and rewrite it to `droppableUnsafeCaseList` in the plugin. Specifically, the plugin turns case directUnsafeCaseList xs of (hd, tl) -> body into droppableUnsafeCaseList (\hd tl -> body) xs -}