Skip to content

Commit d9866f6

Browse files
committed
Remove 'geqLDefaultUni'
1 parent 95242eb commit d9866f6

File tree

2 files changed

+22
-48
lines changed

2 files changed

+22
-48
lines changed

plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -847,10 +847,10 @@ Our final example is this:
847847
(SomeConstant (Some (ValueOf uniA x)))
848848
(SomeConstant (Some (ValueOf uniListA xs))) =
849849
case uniListA of
850-
DefaultUniList uniA' -> case uniA `geqLDefaultUni` uniA' of -- [1]
851-
EvaluationSuccess Refl -> -- [2]
852-
pure . fromValueOf uniListA $ x : xs -- [3]
853-
EvaluationFailure -> throwError $ structuralUnliftingError
850+
DefaultUniList uniA' -> case uniA `geq` uniA' of -- [1]
851+
Just Refl -> -- [2]
852+
pure . fromValueOf uniListA $ x : xs -- [3]
853+
Nothing -> throwError $ structuralUnliftingError
854854
"The type of the value does not match the type of elements in the list"
855855
_ -> throwError $ structuralUnliftingError "Expected a list but got something else"
856856
{-# INLINE mkConsDenotation #-}
@@ -1424,9 +1424,9 @@ instance uni ~ DefaultUni => ToBuiltinMeaning uni DefaultFun where
14241424
(SomeConstant (Some (ValueOf uniListA xs))) =
14251425
-- See Note [Structural vs operational errors within builtins].
14261426
case uniListA of
1427-
DefaultUniList uniA' -> case uniA `geqLDefaultUni` uniA' of
1428-
EvaluationSuccess Refl -> pure . fromValueOf uniListA $ x : xs
1429-
EvaluationFailure -> throwError $ structuralUnliftingError
1427+
DefaultUniList uniA' -> case uniA `geq` uniA' of
1428+
Just Refl -> pure . fromValueOf uniListA $ x : xs
1429+
Nothing -> throwError $ structuralUnliftingError
14301430
"The type of the value does not match the type of elements in the list"
14311431
_ -> throwError $ structuralUnliftingError "Expected a list but got something else"
14321432
{-# INLINE mkConsDenotation #-}

plutus-core/plutus-core/src/PlutusCore/Default/Universe.hs

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ module PlutusCore.Default.Universe
4040
, pattern DefaultUniArray
4141
, pattern DefaultUniPair
4242
, noMoreTypeFunctions
43-
, geqLDefaultUni
4443
, module Export -- Re-exporting universes infrastructure for convenience.
4544
) where
4645

@@ -54,14 +53,12 @@ import PlutusCore.Crypto.BLS12_381.Pairing qualified as BLS12_381.Pairing
5453
import PlutusCore.Data (Data)
5554
import PlutusCore.Evaluation.Machine.ExMemoryUsage (IntegerCostedLiterally (..),
5655
NumBytesCostedAsNumWords (..))
57-
import PlutusCore.Evaluation.Result (EvaluationResult)
5856
import PlutusCore.Pretty.Extra (juxtRenderContext)
5957
import PlutusCore.Value (Value)
6058

6159
import Control.Monad.Except (throwError)
6260
import Data.ByteString (ByteString)
6361
import Data.Int (Int16, Int32, Int64, Int8)
64-
import Data.Kind qualified as GHC
6562
import Data.Proxy (Proxy (Proxy))
6663
import Data.Text (Text)
6764
import Data.Text qualified as Text
@@ -185,46 +182,23 @@ instance AllBuiltinArgs DefaultUni (GEqL DefaultUni) a => GEqL DefaultUni a wher
185182
pure Refl
186183
{-# INLINE geqL #-}
187184

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'.
211185
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.
212201
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.
228202
goStep, goRec :: DefaultUni a1 -> DefaultUni a2 -> Maybe (a1 :~: a2)
229203
goStep DefaultUniInteger a2 = do
230204
DefaultUniInteger <- pure a2

0 commit comments

Comments
 (0)