mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Fix handling for throw within handler (#14461)
changelog_begin changelog_end
This commit is contained in:
parent
ccc65d4da5
commit
c17c580b84
@ -2010,6 +2010,33 @@ class EngineTest
|
||||
case Left(Interpretation(DamlException(interpretation.Error.ContractNotFound(_)), _)) =>
|
||||
}
|
||||
}
|
||||
"ThrowInHandler" in {
|
||||
val command = ApiCommand.CreateAndExercise(
|
||||
tId,
|
||||
ValueRecord(None, ImmArray((None, ValueParty(party)))),
|
||||
"ThrowInHandler",
|
||||
ValueRecord(None, ImmArray.empty),
|
||||
)
|
||||
run(command) shouldBe a[Right[_, _]]
|
||||
}
|
||||
"ThrowPureInHandler" in {
|
||||
val command = ApiCommand.CreateAndExercise(
|
||||
tId,
|
||||
ValueRecord(None, ImmArray((None, ValueParty(party)))),
|
||||
"ThrowPureInHandler",
|
||||
ValueRecord(None, ImmArray.empty),
|
||||
)
|
||||
run(command) shouldBe a[Right[_, _]]
|
||||
}
|
||||
"ThrowPureInHandlerPattern" in {
|
||||
val command = ApiCommand.CreateAndExercise(
|
||||
tId,
|
||||
ValueRecord(None, ImmArray((None, ValueParty(party)))),
|
||||
"ThrowPureInHandlerPattern",
|
||||
ValueRecord(None, ImmArray.empty),
|
||||
)
|
||||
run(command) shouldBe a[Right[_, _]]
|
||||
}
|
||||
}
|
||||
|
||||
"action node seeds" should {
|
||||
|
@ -1651,15 +1651,11 @@ private[lf] object SBuiltin {
|
||||
val opt = getSOptional(args, 0)
|
||||
val excep = getSAny(args, 1)
|
||||
checkToken(args, 2)
|
||||
machine.withOnLedger("SBTryHandler") { onLedger =>
|
||||
opt match {
|
||||
case None =>
|
||||
onLedger.ptx = onLedger.ptx.abortTry
|
||||
unwindToHandler(machine, excep) // re-throw
|
||||
case Some(handler) =>
|
||||
onLedger.ptx = onLedger.ptx.rollbackTry(excep)
|
||||
machine.enterApplication(handler, Array(SEValue(SToken)))
|
||||
}
|
||||
opt match {
|
||||
case None =>
|
||||
unwindToHandler(machine, excep) // re-throw
|
||||
case Some(handler) =>
|
||||
machine.enterApplication(handler, Array(SEValue(SToken)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1558,6 +1558,9 @@ private[lf] object Speedy {
|
||||
} else {
|
||||
machine.popKont() match {
|
||||
case handler: KTryCatchHandler =>
|
||||
machine.withOnLedger("unwindToHandler/KTryCatchHandler") { onLedger =>
|
||||
onLedger.ptx = onLedger.ptx.rollbackTry(excep)
|
||||
}
|
||||
Some(handler)
|
||||
case _: KCloseExercise =>
|
||||
machine.withOnLedger("unwindToHandler/KCloseExercise") { onLedger =>
|
||||
|
@ -576,7 +576,7 @@ private[speedy] case class PartialTransaction(
|
||||
}
|
||||
|
||||
/** Open a Try context.
|
||||
* Must be closed by `endTry`, `abortTry`, or `rollbackTry`.
|
||||
* Must be closed by `endTry` or `rollbackTry`.
|
||||
*/
|
||||
def beginTry: PartialTransaction = {
|
||||
val nid = NodeId(nextNodeIdx)
|
||||
@ -608,13 +608,6 @@ private[speedy] case class PartialTransaction(
|
||||
)
|
||||
}
|
||||
|
||||
/** Close abruptly a try context, due to an uncaught exception,
|
||||
* i.e. an exception was thrown inside the context but the catch associated to the try context did not handle it.
|
||||
* Must match a `beginTry`.
|
||||
*/
|
||||
def abortTry: PartialTransaction =
|
||||
endTry
|
||||
|
||||
/** Close a try context, by catching an exception,
|
||||
* i.e. a exception was thrown inside the context, and the catch associated to the try context did handle it.
|
||||
*/
|
||||
@ -700,7 +693,7 @@ private[speedy] case class PartialTransaction(
|
||||
@tailrec
|
||||
def go(ptx: PartialTransaction): PartialTransaction = ptx.context.info match {
|
||||
case _: PartialTransaction.ExercisesContextInfo => go(ptx.abortExercises)
|
||||
case _: PartialTransaction.TryContextInfo => go(ptx.abortTry)
|
||||
case _: PartialTransaction.TryContextInfo => go(ptx.endTry)
|
||||
case _: PartialTransaction.RootContextInfo => ptx
|
||||
}
|
||||
go(this)
|
||||
|
@ -241,8 +241,7 @@ class ExceptionTest extends AnyWordSpec with Inside with Matchers with TableDriv
|
||||
("expression", "expected"),
|
||||
("M:innerCatch", 377),
|
||||
("M:outerCatch", 188),
|
||||
// TODO https://github.com/digital-asset/daml/issues/14431
|
||||
// ("M:throwWhileInnerHandlerDecides", 188),
|
||||
("M:throwWhileInnerHandlerDecides", 188),
|
||||
)
|
||||
|
||||
forEvery(testCases) { (exp: String, num: Long) =>
|
||||
@ -311,8 +310,7 @@ class ExceptionTest extends AnyWordSpec with Inside with Matchers with TableDriv
|
||||
("expression", "expected"),
|
||||
("M:maybeInnerCatch True False", 1377),
|
||||
("M:maybeInnerCatch False False", 1188),
|
||||
// TODO https://github.com/digital-asset/daml/issues/14431
|
||||
// ("M:maybeInnerCatch False True", 2188),
|
||||
("M:maybeInnerCatch False True", 2188),
|
||||
)
|
||||
|
||||
forEvery(testCases) { (exp: String, num: Long) =>
|
||||
|
@ -157,7 +157,7 @@ class PartialTransactionSpec extends AnyWordSpec with Matchers with Inside {
|
||||
.beginTry // open a second try context
|
||||
.insertCreate_ // create the contract cid_1_2
|
||||
// an exception is thrown
|
||||
.abortTry // the second try context does not handle the exception
|
||||
.rollbackTry_ // the second try context does not handle the exception
|
||||
.abortExercises // close abruptly the exercise due to an uncaught exception
|
||||
.rollbackTry_ // the first try context does handle the exception
|
||||
.insertCreate_ // create the contract cid_2
|
||||
|
@ -4,7 +4,7 @@
|
||||
module Exceptions where
|
||||
|
||||
import DA.Assert
|
||||
import DA.Exception (throw)
|
||||
import DA.Exception (throw,throwPure)
|
||||
|
||||
exception E
|
||||
where
|
||||
@ -103,6 +103,33 @@ template T
|
||||
throw (Ecid cid)
|
||||
catch (Ecid cid) -> archive cid
|
||||
|
||||
nonconsuming choice ThrowInHandler : ()
|
||||
controller p
|
||||
do
|
||||
try
|
||||
try throw E
|
||||
catch E -> throw E
|
||||
catch
|
||||
E -> pure ()
|
||||
|
||||
nonconsuming choice ThrowPureInHandler : ()
|
||||
controller p
|
||||
do
|
||||
try
|
||||
try throw E
|
||||
catch E -> throwPure E
|
||||
catch
|
||||
E -> pure ()
|
||||
|
||||
nonconsuming choice ThrowPureInHandlerPattern : ()
|
||||
controller p
|
||||
do
|
||||
try
|
||||
try throw E
|
||||
catch E | throwPure E -> pure ()
|
||||
catch
|
||||
E -> pure ()
|
||||
|
||||
-- This template is used to test that the
|
||||
-- engine only ever looks up a global key once.
|
||||
-- All choices should succeed under the assumption
|
||||
|
Loading…
Reference in New Issue
Block a user