Skip to content

Commit

Permalink
Correctly handle exceptions in the TailRec with the help of Fence
Browse files Browse the repository at this point in the history
  • Loading branch information
Atry committed Dec 26, 2021
1 parent 239cc22 commit 704d680
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 52 deletions.
11 changes: 2 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ lazy val `keywords-Match` =
lazy val `keywords-TryCatch` =
crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
.dependsOn(Dsl, `keywords-Shift`, `keywords-Match`)
.dependsOn(Dsl, `keywords-Shift`, `keywords-Fence`, `keywords-Match`)

lazy val `keywords-TryCatchFinally` =
crossProject(JSPlatform, JVMPlatform)
Expand All @@ -92,14 +92,7 @@ lazy val `keywords-Suspend` =
lazy val `keywords-Fence` =
crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
.dependsOn(
Dsl,
`macros-Reset` % Test,
`domains-Continuation` % Test,
`keywords-Yield` % Test,
`keywords-Get` % Test,
`keywords-Put` % Test
)
.dependsOn(Dsl)

lazy val `keywords-Return` =
crossProject(JSPlatform, JVMPlatform)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
a[MyException] should be thrownBy task1
}

"rethrow" ignore Task.toFuture(Task {
"rethrow" in Task.toFuture(Task {
class MyException extends Exception
val task1: Task[Int] = Task {
throw new MyException
Expand All @@ -133,7 +133,7 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
case myException: MyException =>
throw myException
}
} catch {
} catch {
case myException: MyException =>
"my exception"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ object TryCatch extends TryCatch.LowPriority0 {
given [
LeftDomain,
Value
]: DslComposer[LeftDomain !! Throwable, Value, LeftDomain !! Throwable] =
](using
fenceDsl: Dsl.Searching[Fence.type, LeftDomain, Unit]
): DslComposer[LeftDomain !! Throwable, Value, LeftDomain !! Throwable] =
DslComposer {
[BlockKeyword, CaseKeyword] =>
(
Expand All @@ -116,50 +118,40 @@ object TryCatch extends TryCatch.LowPriority0 {
outerSuccessHandler: (Value => LeftDomain !! Throwable)
) =>
outerFailureHandler =>
// TODO: Simplify the implementation. We should allow it to throw native unhandled exceptions instead of handling it, assuming there will be another exception handler for it
def innerFailureHandler(e: Throwable): LeftDomain = {
catcher.lift(e) match {
case None =>
def success(a: Value): LeftDomain !! Throwable = {
failureHandler =>
try {
// TODO: Trampoline
fenceDsl(
Fence,
_ => outerSuccessHandler(a)(outerFailureHandler)
)
} catch {
case NonFatal(nativeThrown) =>
outerFailureHandler(nativeThrown)
}
}
def innerFailureHandler(e: Throwable) = {
e match {
case catcher(recovered) =>
caseDsl(recovered, success)(outerFailureHandler)
case e =>
outerFailureHandler(e)
case Some(recovered) =>
@inline
def recoveredHandler(): LeftDomain = {
locally {
try {
recovered.cpsApply(outerSuccessHandler)
} catch {
case NonFatal(nativeThrown) =>
return outerFailureHandler(nativeThrown)
}
}(outerFailureHandler)
}
recoveredHandler()
}
}

def runBlock(): LeftDomain = {
(try {
block().cpsApply { a => hookedFailureHandler =>
@inline
def successHandler(): LeftDomain = {
locally {
try {
outerSuccessHandler(a)
} catch {
case NonFatal(nativeThrown) =>
return outerFailureHandler(nativeThrown)
}
}(outerFailureHandler)
}

successHandler()
}
} catch {
case NonFatal(e) =>
return innerFailureHandler(e)
})(innerFailureHandler)
try {
fenceDsl(
Fence,
_ =>
blockDsl(
block(),
success
)(innerFailureHandler)
)
} catch {
case NonFatal(e) =>
innerFailureHandler(e)
}
runBlock()
}
}

Expand Down

0 comments on commit 704d680

Please sign in to comment.