Skip to content

Commit

Permalink
Add tests for capture checking, per lampepfl#67
Browse files Browse the repository at this point in the history
  • Loading branch information
natsukagami committed Apr 19, 2024
1 parent 401bb6d commit cfe85d2
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions shared/src/test/scala/CCBehavior.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import language.experimental.captureChecking

import gears.async.AsyncOperations.*
import gears.async.default.given
import gears.async.{Async, AsyncSupport, Future, uninterruptible}

import java.util.concurrent.CancellationException
import scala.annotation.capability
import scala.concurrent.duration.{Duration, DurationInt}
import scala.util.Success
import scala.util.boundary

type Result[+T, +E] = Either[E, T]
object Result:
@capability opaque type Label[-T, -E] = boundary.Label[Result[T, E]]
// ^ doesn't work?

def apply[T, E](body: Label[T, E] ?=> T): Result[T, E] =
boundary(Right(body))

extension [U, E](r: Result[U, E]^)(using Label[Nothing, E]^)
def ok: U = r match
case Left(value) => boundary.break(Left(value))
case Right(value) => value

class CaptureCheckingBehavior extends munit.FunSuite:
import Result.*

test("good") {
// don't do this in real code! capturing Async.blocking's Async context across functions is hard to track
Async.blocking: async ?=>
def good1[T, E](frs: List[Future[Result[T, E]]^]): Future[Result[List[T], E]]^{async} =
Future:
Result:
frs.map(_.await.ok)

def good2[T, E](rf: Result[Future[T]^, E]): Future[Result[T, E]]^{async} =
Future:
Result:
rf.ok.await // OK, Future argument has type Result[T]

def useless4[T, E](fr: Future[Result[T, E]]^) =
fr.await.map(Future(_))
}

test("very bad") {
Async.blocking: async ?=>
def fail3[T, E](fr: Future[Result[T, E]]^) =
Result: label ?=>
Future: fut ?=>
fr.await.ok // error, escaping label from Result

val fut = Future(Left(5))
val res = fail3(fut)
println(res.right.get.asInstanceOf[Future[Any]].awaitResult)
}

// test("bad") {
// Async.blocking: async ?=>
// def fail3[T, E](fr: Future[Result[T, E]]^): Result[Future[T]^{async}, E] =
// Result: label ?=>
// Future: fut ?=>
// fr.await.ok // error, escaping label from Result
// }

0 comments on commit cfe85d2

Please sign in to comment.