Skip to content

Commit e2b91bf

Browse files
committed
Have explicit boundary/suspend capture sets
1 parent 80d09d3 commit e2b91bf

File tree

3 files changed

+21
-18
lines changed

3 files changed

+21
-18
lines changed

jvm/src/main/scala/async/VThreadSupport.scala

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ object VThreadScheduler extends Scheduler:
5050
object VThreadSupport extends AsyncSupport:
5151
type Scheduler = VThreadScheduler.type
5252

53-
private final class VThreadLabel[R]():
53+
private final class VThreadLabel[R]() extends caps.Capability:
5454
private var result: Option[R] = None
5555
private val lock = ReentrantLock()
5656
private val cond = lock.newCondition()
@@ -74,11 +74,11 @@ object VThreadSupport extends AsyncSupport:
7474
result.get
7575
finally lock.unlock()
7676

77-
override opaque type Label[R] = VThreadLabel[R]
77+
override opaque type Label[R, Cap^] <: caps.Capability = VThreadLabel[R]
7878

7979
// outside boundary: waiting on label
8080
// inside boundary: waiting on suspension
81-
private final class VThreadSuspension[-T, +R](using private[VThreadSupport] val l: Label[R] @uncheckedVariance)
81+
private final class VThreadSuspension[-T, +R](using private[VThreadSupport] val l: VThreadLabel[R] @uncheckedVariance)
8282
extends gears.async.Suspension[T, R]:
8383
private var nextInput: Option[T] = None
8484
private val lock = ReentrantLock()
@@ -107,25 +107,28 @@ object VThreadSupport extends AsyncSupport:
107107

108108
override opaque type Suspension[-T, +R] <: gears.async.Suspension[T, R] = VThreadSuspension[T, R]
109109

110-
override def boundary[R](body: (Label[R]) ?=> R): R =
110+
override def boundary[R, Cap^](body: Label[R, Cap]^ ?->{Cap^} R): R =
111111
val label = VThreadLabel[R]()
112112
VThreadScheduler.execute: () =>
113113
val result = body(using label)
114114
label.setResult(result)
115115

116116
label.waitResult()
117117

118-
override private[async] def resumeAsync[T, R](suspension: Suspension[T, R])(arg: T)(using Scheduler): Unit =
118+
override private[async] def resumeAsync[T, R](suspension: Suspension[T, R]^)(arg: T)(using Scheduler): Unit =
119119
suspension.l.clearResult()
120120
suspension.setInput(arg)
121121

122-
override def scheduleBoundary(body: (Label[Unit]) ?=> Unit)(using Scheduler): Unit =
122+
override def scheduleBoundary[Cap^](body: Label[Unit, Cap] ?->{Cap^} Unit)(using Scheduler): Unit =
123123
VThreadScheduler.execute: () =>
124124
val label = VThreadLabel[Unit]()
125125
body(using label)
126126

127-
override def suspend[T, R](body: Suspension[T, R] => R)(using l: Label[R]): T =
128-
val sus = new VThreadSuspension[T, R]()
127+
override def suspend[T, R, Cap^](body: Suspension[T, R]^{Cap^} => R^{Cap^})(using l: Label[R, Cap]^): T =
128+
val sus = new VThreadSuspension[T, R](using caps.unsafe.unsafeAssumePure(l))
129129
val res = body(sus)
130-
l.setResult(res)
130+
l.setResult(
131+
// SAFETY: will only be stored and returned by the Suspension resumption mechanism
132+
caps.unsafe.unsafeAssumePure(res)
133+
)
131134
sus.waitInput()

shared/src/main/scala/async/AsyncSupport.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,27 @@ trait Suspension[-T, +R]:
1414
/** Support for suspension capabilities through a delimited continuation interface. */
1515
trait SuspendSupport:
1616
/** A marker for the "limit" of "delimited continuation". */
17-
type Label[R]
17+
type Label[R, Cap^] <: caps.Capability
1818

1919
/** The provided suspension type. */
2020
type Suspension[-T, +R] <: gears.async.Suspension[T, R]
2121

2222
/** Set the suspension marker as the body's caller, and execute `body`. */
23-
def boundary[R](body: Label[R] ?=> R): R
23+
def boundary[R, Cap^](body: Label[R, Cap] ?->{Cap^} R): R^{Cap^}
2424

2525
/** Should return immediately if resume is called from within body */
26-
def suspend[T, R](body: Suspension[T, R] => R)(using Label[R]): T
26+
def suspend[T, R, Cap^](body: Suspension[T, R]^{Cap^} => R^{Cap^})(using Label[R, Cap]): T
2727

2828
/** Extends [[SuspendSupport]] with "asynchronous" boundary/resume functions, in the presence of a [[Scheduler]] */
2929
trait AsyncSupport extends SuspendSupport:
3030
type Scheduler <: gears.async.Scheduler
3131

3232
/** Resume a [[Suspension]] at some point in the future, scheduled by the scheduler. */
33-
private[async] def resumeAsync[T, R](suspension: Suspension[T, R])(arg: T)(using s: Scheduler): Unit =
33+
private[async] def resumeAsync[T, R](suspension: Suspension[T, R]^)(arg: T)(using s: Scheduler): Unit =
3434
s.execute(() => suspension.resume(arg))
3535

3636
/** Schedule a computation with the suspension boundary already created. */
37-
private[async] def scheduleBoundary(body: Label[Unit] ?=> Unit)(using s: Scheduler): Unit =
37+
private[async] def scheduleBoundary[Cap^](body: Label[Unit, Cap] ?->{Cap^} Unit)(using s: Scheduler): Unit =
3838
s.execute(() => boundary(body))
3939

4040
/** A scheduler implementation, with the ability to execute a computation immediately or after a delay. */

shared/src/main/scala/async/futures.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ object Future:
123123
private def checkCancellation(): Unit =
124124
if cancelRequest.get() then throw new CancellationException()
125125

126-
private class FutureAsync(val group: CompletionGroup)(using label: acSupport.Label[Unit])
126+
private class FutureAsync[Cap^](val group: CompletionGroup)(using label: acSupport.Label[Unit, Cap])
127127
extends Async(using acSupport, acScheduler):
128128
/** Await a source first by polling it, and, if that fails, by suspending in a onComplete call.
129129
*/
130130
override def await[U](src: Async.Source[U]^): U =
131131
class CancelSuspension extends Cancellable:
132-
var suspension: acSupport.Suspension[Try[U], Unit] = uninitialized
133-
var listener: Listener[U]^{this} = uninitialized
132+
var suspension: acSupport.Suspension[Try[U], Unit]^{Cap^} = uninitialized
133+
var listener: Listener[U]^{this, Cap^} = uninitialized
134134
var completed = false
135135

136136
def complete() = synchronized:
@@ -150,7 +150,7 @@ object Future:
150150
.poll()
151151
.getOrElse:
152152
val cancellable = CancelSuspension()
153-
val res = acSupport.suspend[Try[U], Unit](k =>
153+
val res = acSupport.suspend[Try[U], Unit, Cap](k =>
154154
val listener = Listener.acceptingListener[U]: (x, _) =>
155155
val completedBefore = cancellable.complete()
156156
if !completedBefore then acSupport.resumeAsync(k)(Success(x))

0 commit comments

Comments
 (0)