|
| 1 | +import annotation.capability |
| 2 | + |
| 3 | +object boundary: |
| 4 | + |
| 5 | + @capability final class Label[-T] |
| 6 | + |
| 7 | + /** Abort current computation and instead return `value` as the value of |
| 8 | + * the enclosing `boundary` call that created `label`. |
| 9 | + */ |
| 10 | + def break[T](value: T)(using label: Label[T]): Nothing = ??? |
| 11 | + |
| 12 | + def apply[T](body: Label[T] ?=> T): T = ??? |
| 13 | +end boundary |
| 14 | + |
| 15 | +import boundary.{Label, break} |
| 16 | + |
| 17 | +@capability trait Async |
| 18 | +object Async: |
| 19 | + def blocking[T](body: Async ?=> T): T = ??? |
| 20 | + |
| 21 | +class Future[+T]: |
| 22 | + this: Future[T]^ => |
| 23 | + def await(using Async): T = ??? |
| 24 | +object Future: |
| 25 | + def apply[T](op: Async ?=> T)(using Async): Future[T]^{op} = ??? |
| 26 | + |
| 27 | +enum Result[+T, +E]: |
| 28 | + case Ok[+T](value: T) extends Result[T, Nothing] |
| 29 | + case Err[+E](error: E) extends Result[Nothing, E] |
| 30 | + |
| 31 | + |
| 32 | +object Result: |
| 33 | + extension [T, E](r: Result[T, E]^)(using Label[Err[E]]) |
| 34 | + |
| 35 | + /** `_.ok` propagates Err to current Label */ |
| 36 | + def ok: T = r match |
| 37 | + case Ok(value) => value |
| 38 | + case Err(value) => break[Err[E]](Err(value)) |
| 39 | + |
| 40 | + transparent inline def apply[T, E](inline body: Label[Result[T, E]] ?=> T): Result[T, E] = |
| 41 | + boundary(Ok(body)) |
| 42 | + |
| 43 | + // same as apply, but not an inline method |
| 44 | + def make[T, E](body: Label[Result[T, E]] ?=> T): Result[T, E] = |
| 45 | + boundary(Ok(body)) |
| 46 | + |
| 47 | +end Result |
| 48 | + |
| 49 | +def test[T, E](using Async) = |
| 50 | + import Result.* |
| 51 | + Async.blocking: async ?=> |
| 52 | + val good1: List[Future[Result[T, E]]] => Future[Result[List[T], E]] = frs => |
| 53 | + Future: |
| 54 | + Result: |
| 55 | + frs.map(_.await.ok) // OK |
| 56 | + |
| 57 | + val good2: Result[Future[T], E] => Future[Result[T, E]] = rf => |
| 58 | + Future: |
| 59 | + Result: |
| 60 | + rf.ok.await // OK, Future argument has type Result[T] |
| 61 | + |
| 62 | + def fail3(fr: Future[Result[T, E]]^) = |
| 63 | + Result: |
| 64 | + Future: // error, escaping label from Result |
| 65 | + fr.await.ok |
| 66 | + |
| 67 | + def fail4[T, E](fr: Future[Result[T, E]]^) = |
| 68 | + Result.make: //lbl ?=> // error, escaping label from Result |
| 69 | + Future: fut ?=> |
| 70 | + fr.await.ok |
0 commit comments