16
16
{-# LANGUAGE StrictData #-}
17
17
18
18
module PlutusCore.Builtin.KnownType
19
- ( KnownTypeError
20
- , throwKnownTypeErrorWithCause
19
+ ( BuiltinError
20
+ , throwBuiltinErrorWithCause
21
21
, KnownBuiltinTypeIn
22
22
, KnownBuiltinType
23
- , MakeKnownM (.. )
23
+ , BuiltinResult (.. )
24
24
, ReadKnownM
25
+ , MakeKnownIn (.. )
25
26
, liftReadKnownM
26
27
, readKnownConstant
27
- , MakeKnownIn (.. )
28
28
, MakeKnown
29
29
, ReadKnownIn (.. )
30
30
, ReadKnown
@@ -37,17 +37,15 @@ import PlutusPrelude
37
37
import PlutusCore.Builtin.Emitter
38
38
import PlutusCore.Builtin.HasConstant
39
39
import PlutusCore.Builtin.Polymorphism
40
+ import PlutusCore.Builtin.Result
40
41
import PlutusCore.Core
41
- import PlutusCore.Evaluation.Machine.Exception
42
+ import PlutusCore.Evaluation.ErrorWithCause
42
43
import PlutusCore.Evaluation.Result
43
44
import PlutusCore.Pretty
44
45
45
- import Control.Lens.TH (makeClassyPrisms )
46
46
import Control.Monad.Except
47
- import Data.DList (DList )
48
47
import Data.Either.Extras
49
48
import Data.String
50
- import Data.Text (Text )
51
49
import GHC.Exts (inline , oneShot )
52
50
import GHC.TypeLits
53
51
import Universe
@@ -67,7 +65,7 @@ It's critically important that 'readKnown' runs in the concrete 'Either' rather
67
65
https://github.com/IntersectMBO/plutus/pull/4307
68
66
69
67
Replacing the @AsUnliftingError err, AsEvaluationFailure err@ constraints with the dedicated
70
- 'KnownTypeError ' data type gave us a speedup of up to 4%.
68
+ 'BuiltinError ' data type gave us a speedup of up to 4%.
71
69
72
70
All the same considerations apply to 'makeKnown':
73
71
https://github.com/IntersectMBO/plutus/pull/4421
@@ -241,16 +239,16 @@ Lifting is allowed to the following classes of types:
241
239
one, and for another example define an instance for 'Void' in tests
242
240
-}
243
241
244
- -- | Attach a @cause@ to a 'KnownTypeError ' and throw that.
242
+ -- | Attach a @cause@ to a 'BuiltinError ' and throw that.
245
243
-- Note that an evaluator might require the cause to be computed lazily for best performance on the
246
244
-- happy path, hence this function must not force its first argument.
247
245
-- TODO: wrap @cause@ in 'Lazy' once we have it.
248
- throwKnownTypeErrorWithCause
246
+ throwBuiltinErrorWithCause
249
247
:: (MonadError (ErrorWithCause err cause ) m , AsUnliftingError err , AsEvaluationFailure err )
250
- => cause -> KnownTypeError -> m void
251
- throwKnownTypeErrorWithCause cause = \ case
252
- KnownTypeUnliftingError unlErr -> throwingWithCause _UnliftingError unlErr $ Just cause
253
- KnownTypeEvaluationFailure -> throwingWithCause _EvaluationFailure () $ Just cause
248
+ => cause -> BuiltinError -> m void
249
+ throwBuiltinErrorWithCause cause = \ case
250
+ BuiltinUnliftingError unlErr -> throwingWithCause _UnliftingError unlErr $ Just cause
251
+ BuiltinEvaluationFailure -> throwingWithCause _EvaluationFailure () $ Just cause
254
252
255
253
typeMismatchError
256
254
:: PrettyParens (SomeTypeIn uni )
@@ -266,89 +264,19 @@ typeMismatchError uniExp uniAct = fromString $ concat
266
264
-- failure message and evaluation is about to be shut anyway.
267
265
{-# NOINLINE typeMismatchError #-}
268
266
269
- -- | The monad that 'makeKnown' runs in.
270
- -- Equivalent to @ExceptT KnownTypeError Emitter@, except optimized in two ways:
271
- --
272
- -- 1. everything is strict
273
- -- 2. has the 'MakeKnownSuccess' constructor that is used for returning a value with no logs
274
- -- attached, which is the most common case for us, so it helps a lot not to construct and
275
- -- deconstruct a redundant tuple
276
- --
277
- -- Moving from @ExceptT KnownTypeError Emitter@ to this data type gave us a speedup of 8% of total
278
- -- evaluation time.
279
- --
280
- -- Logs are represented as a 'DList', because we don't particularly care about the efficiency of
281
- -- logging, since there's no logging on the chain and builtins don't emit much anyway. Otherwise
282
- -- we'd have to use @text-builder@ or @text-builder-linear@ or something of this sort.
283
- data MakeKnownM a
284
- = MakeKnownFailure (DList Text ) KnownTypeError
285
- | MakeKnownSuccess a
286
- | MakeKnownSuccessWithLogs (DList Text ) a
287
-
288
- makeClassyPrisms ''MakeKnownM
289
-
290
- instance AsEvaluationFailure (MakeKnownM a ) where
291
- _EvaluationFailure = _MakeKnownFailure . _EvaluationFailureVia (pure KnownTypeEvaluationFailure )
292
- {-# INLINE _EvaluationFailure #-}
293
-
294
- -- | Prepend logs to a 'MakeKnownM' computation.
295
- withLogs :: DList Text -> MakeKnownM a -> MakeKnownM a
296
- withLogs logs1 = \ case
297
- MakeKnownFailure logs2 err -> MakeKnownFailure (logs1 <> logs2) err
298
- MakeKnownSuccess x -> MakeKnownSuccessWithLogs logs1 x
299
- MakeKnownSuccessWithLogs logs2 x -> MakeKnownSuccessWithLogs (logs1 <> logs2) x
300
- {-# INLINE withLogs #-}
301
-
302
- instance Functor MakeKnownM where
303
- fmap _ (MakeKnownFailure logs err) = MakeKnownFailure logs err
304
- fmap f (MakeKnownSuccess x) = MakeKnownSuccess (f x)
305
- fmap f (MakeKnownSuccessWithLogs logs x) = MakeKnownSuccessWithLogs logs (f x)
306
- {-# INLINE fmap #-}
307
-
308
- -- Written out explicitly just in case (see @fmap@ above for what the case might be).
309
- _ <$ MakeKnownFailure logs err = MakeKnownFailure logs err
310
- x <$ MakeKnownSuccess _ = MakeKnownSuccess x
311
- x <$ MakeKnownSuccessWithLogs logs _ = MakeKnownSuccessWithLogs logs x
312
- {-# INLINE (<$) #-}
313
-
314
- instance Applicative MakeKnownM where
315
- pure = MakeKnownSuccess
316
- {-# INLINE pure #-}
317
-
318
- MakeKnownFailure logs err <*> _ = MakeKnownFailure logs err
319
- MakeKnownSuccess f <*> a = fmap f a
320
- MakeKnownSuccessWithLogs logs f <*> a = withLogs logs $ fmap f a
321
- {-# INLINE (<*>) #-}
322
-
323
- -- Better than the default implementation, because the value in the 'MakeKnownSuccess' case
324
- -- doesn't need to be retained.
325
- MakeKnownFailure logs err *> _ = MakeKnownFailure logs err
326
- MakeKnownSuccess _ *> a = a
327
- MakeKnownSuccessWithLogs logs _ *> a = withLogs logs a
328
- {-# INLINE (*>) #-}
329
-
330
- instance Monad MakeKnownM where
331
- MakeKnownFailure logs err >>= _ = MakeKnownFailure logs err
332
- MakeKnownSuccess x >>= f = f x
333
- MakeKnownSuccessWithLogs logs x >>= f = withLogs logs $ f x
334
- {-# INLINE (>>=) #-}
335
-
336
- (>>) = (*>)
337
- {-# INLINE (>>) #-}
338
-
339
267
-- Normally it's a good idea for an exported abstraction not to be a type synonym, since a @newtype@
340
268
-- is cheap, looks good in error messages and clearly emphasize an abstraction barrier. However we
341
269
-- make 'ReadKnownM' a type synonym for convenience: that way we don't need to derive all the
342
270
-- instances (and add new ones whenever we need them), wrap and unwrap all the time (including in
343
271
-- user code), which can be non-trivial for such performance-sensitive code (see e.g. 'coerceVia'
344
272
-- and 'coerceArg') and there is no abstraction barrier anyway.
345
273
-- | The monad that 'readKnown' runs in.
346
- type ReadKnownM = Either KnownTypeError
274
+ type ReadKnownM = Either BuiltinError
347
275
348
- -- | Lift a 'ReadKnownM' computation into 'MakeKnownM '.
349
- liftReadKnownM :: ReadKnownM a -> MakeKnownM a
350
- liftReadKnownM (Left err) = MakeKnownFailure mempty err
351
- liftReadKnownM (Right x) = MakeKnownSuccess x
276
+ -- | Lift a 'ReadKnownM' computation into 'BuiltinResult '.
277
+ liftReadKnownM :: ReadKnownM a -> BuiltinResult a
278
+ liftReadKnownM (Left err) = BuiltinFailure mempty err
279
+ liftReadKnownM (Right x) = BuiltinSuccess x
352
280
{-# INLINE liftReadKnownM #-}
353
281
354
282
-- See Note [Unlifting values of built-in types].
@@ -363,15 +291,15 @@ readKnownConstant val = asConstant val >>= oneShot \case
363
291
-- optimize some of the matching away.
364
292
case uniExp `geq` uniAct of
365
293
Just Refl -> pure x
366
- Nothing -> Left . KnownTypeUnliftingError $ typeMismatchError uniExp uniAct
294
+ Nothing -> throwing _UnliftingError $ typeMismatchError uniExp uniAct
367
295
{-# INLINE readKnownConstant #-}
368
296
369
297
-- See Note [Performance of ReadKnownIn and MakeKnownIn instances].
370
298
class uni ~ UniOf val => MakeKnownIn uni val a where
371
299
-- | Convert a Haskell value to the corresponding PLC value.
372
300
-- The inverse of 'readKnown'.
373
- makeKnown :: a -> MakeKnownM val
374
- default makeKnown :: KnownBuiltinType val a => a -> MakeKnownM val
301
+ makeKnown :: a -> BuiltinResult val
302
+ default makeKnown :: KnownBuiltinType val a => a -> BuiltinResult val
375
303
-- Everything on evaluation path has to be strict in production, so in theory we don't need to
376
304
-- force anything here. In practice however all kinds of weird things happen in tests and @val@
377
305
-- can be non-strict enough to cause trouble here, so we're forcing the argument. Looking at the
@@ -400,9 +328,9 @@ type ReadKnown val = ReadKnownIn (UniOf val) val
400
328
-- | Same as 'makeKnown', but allows for neither emitting nor storing the cause of a failure.
401
329
makeKnownOrFail :: MakeKnownIn uni val a => a -> EvaluationResult val
402
330
makeKnownOrFail x = case makeKnown x of
403
- MakeKnownFailure _ _ -> EvaluationFailure
404
- MakeKnownSuccess val -> EvaluationSuccess val
405
- MakeKnownSuccessWithLogs _ val -> EvaluationSuccess val
331
+ BuiltinFailure _ _ -> EvaluationFailure
332
+ BuiltinSuccess val -> EvaluationSuccess val
333
+ BuiltinSuccessWithLogs _ val -> EvaluationSuccess val
406
334
{-# INLINE makeKnownOrFail #-}
407
335
408
336
-- | Same as 'readKnown', but the cause of a potential failure is the provided term itself.
@@ -411,14 +339,18 @@ readKnownSelf
411
339
, AsUnliftingError err , AsEvaluationFailure err
412
340
)
413
341
=> val -> Either (ErrorWithCause err val ) a
414
- readKnownSelf val = fromRightM (throwKnownTypeErrorWithCause val) $ readKnown val
342
+ readKnownSelf val = fromRightM (throwBuiltinErrorWithCause val) $ readKnown val
415
343
{-# INLINE readKnownSelf #-}
416
344
417
345
instance MakeKnownIn uni val a => MakeKnownIn uni val (EvaluationResult a ) where
418
346
makeKnown EvaluationFailure = evaluationFailure
419
347
makeKnown (EvaluationSuccess x) = makeKnown x
420
348
{-# INLINE makeKnown #-}
421
349
350
+ instance MakeKnownIn uni val a => MakeKnownIn uni val (BuiltinResult a ) where
351
+ makeKnown res = res >>= makeKnown
352
+ {-# INLINE makeKnown #-}
353
+
422
354
-- Catching 'EvaluationFailure' here would allow *not* to short-circuit when 'readKnown' fails
423
355
-- to read a Haskell value of type @a@. Instead, in the denotation of the builtin function
424
356
-- the programmer would be given an explicit 'EvaluationResult' value to handle, which means
0 commit comments