@@ -40,7 +40,6 @@ module PlutusCore.Default.Universe
40
40
, pattern DefaultUniArray
41
41
, pattern DefaultUniPair
42
42
, noMoreTypeFunctions
43
- , geqLDefaultUni
44
43
, module Export -- Re-exporting universes infrastructure for convenience.
45
44
) where
46
45
@@ -54,14 +53,12 @@ import PlutusCore.Crypto.BLS12_381.Pairing qualified as BLS12_381.Pairing
54
53
import PlutusCore.Data (Data )
55
54
import PlutusCore.Evaluation.Machine.ExMemoryUsage (IntegerCostedLiterally (.. ),
56
55
NumBytesCostedAsNumWords (.. ))
57
- import PlutusCore.Evaluation.Result (EvaluationResult )
58
56
import PlutusCore.Pretty.Extra (juxtRenderContext )
59
57
import PlutusCore.Value (Value )
60
58
61
59
import Control.Monad.Except (throwError )
62
60
import Data.ByteString (ByteString )
63
61
import Data.Int (Int16 , Int32 , Int64 , Int8 )
64
- import Data.Kind qualified as GHC
65
62
import Data.Proxy (Proxy (Proxy ))
66
63
import Data.Text (Text )
67
64
import Data.Text qualified as Text
@@ -185,46 +182,23 @@ instance AllBuiltinArgs DefaultUni (GEqL DefaultUni) a => GEqL DefaultUni a wher
185
182
pure Refl
186
183
{-# INLINE geqL #-}
187
184
188
- -- | 'geqL' for 'DefaultUni' without requiring any constraints.
189
- --
190
- -- This is useful if you want to efficiently check equality of two arbitrary runtime type tags, for
191
- -- example we use this function in the implementation of the 'MkCons' builtin.
192
- --
193
- -- It's the same thing as just calling 'GEq.geq', except is slightly more efficient, because one
194
- -- step of recursion gets inlined and a strict 'EvaluationResult' result gets returned instead of a
195
- -- lazy 'Maybe'.
196
- geqLDefaultUni
197
- :: forall (a :: GHC. Type ) (b :: GHC. Type ).
198
- DefaultUni (Esc a )
199
- -> DefaultUni (Esc b )
200
- -> EvaluationResult (a :~: b )
201
- -- It's not clear why GHC decides to inline 'bring' and how exactly that happens given that it's a
202
- -- recursive function. So that can easily break in future, however it would introduce a very small
203
- -- slowdown and only for builtins that do runtime type tag equality checks, of which at the time
204
- -- this comment was written we had only 'MkCons'.
205
- geqLDefaultUni uniA uniB = bring (Proxy @ (GEqL DefaultUni )) uniA $ geqL uniA uniB
206
- {-# INLINE geqLDefaultUni #-}
207
-
208
- -- | For checking equality of two 'DefaultUni' values representing arbitrarily-kinded built-in types
209
- -- (i.e. works for an unapplied 'DefaultUniProtoList' for example). Don't use it for checking
210
- -- equality of runtime type tags, for that we have the more efficient 'geqL' and 'geqLDefaultUni'.
211
185
instance GEq DefaultUni where
186
+ -- We define 'geq' manually instead of using 'deriveGEq', because the latter creates a single
187
+ -- recursive definition and we want two instead. The reason why we want two is because this
188
+ -- allows GHC to inline the initial step that appears non-recursive to GHC, because recursion
189
+ -- is hidden in the other function that is marked as @OPAQUE@ and is chosen by GHC as a
190
+ -- loop-breaker, see https://wiki.haskell.org/Inlining_and_Specialisation#What_is_a_loop-breaker
191
+ -- (we're not really sure if this is a reliable solution, but if it stops working, we won't miss
192
+ -- very much and we've failed to settle on any other approach).
193
+ --
194
+ -- On the critical path this definition should only be used for builtins that perform equality
195
+ -- checking of statically unknown runtime type tags ('MkCons' is one such builtin for
196
+ -- example). All other builtins should use 'geqL' (the latter is internal to 'readKnownConstant'
197
+ -- and is therefore hidden from the person adding a new builtin).
198
+ --
199
+ -- We use @NOINLINE@ instead of @OPAQUE@, because we don't actually care about the recursive
200
+ -- definition not being inlined, we just want it to be chosen as the loop breaker.
212
201
geq = goStep where
213
- -- Even though performance of this definition isn't particularly important, we still define
214
- -- 'geq' manually instead of using 'deriveGEq', because the latter not only requires a
215
- -- dependency on the 'dependent-sum-template' library that caused multiple problems, it also
216
- -- creates a single recursive definition and having two instead is faster while not being
217
- -- very annoying to implement and maintain.
218
- --
219
- -- Splitting the definition in two allows GHC to inline the initial step that appears
220
- -- non-recursive to GHC, because recursion is hidden in the other function that is marked as
221
- -- @NOINLINE@ and is chosen by GHC as a loop-breaker, see
222
- -- https://wiki.haskell.org/Inlining_and_Specialisation#What_is_a_loop-breaker (we're not
223
- -- really sure if this is a reliable solution, but if it stops working, we won't miss very
224
- -- much and we've failed to settle on any other approach).
225
- --
226
- -- We use @NOINLINE@ instead of @OPAQUE@, because we don't actually care about the recursive
227
- -- definition not being inlined, we just want it to be chosen as a loop breaker.
228
202
goStep , goRec :: DefaultUni a1 -> DefaultUni a2 -> Maybe (a1 :~: a2 )
229
203
goStep DefaultUniInteger a2 = do
230
204
DefaultUniInteger <- pure a2
0 commit comments