Skip to content

add capture-checked scala.concurrent standard library classes #23089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

olhotak
Copy link
Contributor

@olhotak olhotak commented May 2, 2025

Adds a capture-checked version of the scala.concurrent standard library classes to scala2-library-cc.

Marked as draft for now because it fails separation checking.

@olhotak
Copy link
Contributor Author

olhotak commented May 2, 2025

Here are the separation checking errors:

[error] -- Error: /home/olhotak/git/dotty/scala2-library-cc/src/scala/concurrent/ExecutionContext.scala:291:77 
[error] 291 |  def fromExecutor(e: Executor): ExecutionContextExecutor^ = fromExecutor(e, defaultReporter)
[error]     |                                                                             ^^^^^^^^^^^^^^^
[error]     |Separation failure: Illegal access to cap which is hidden by the previous definition
[error]     |of method fromExecutorService with result type scala.concurrent.ExecutionContextExecutorService^.
[error]     |This type hides capabilities  {cap}
[error] -- Error: /home/olhotak/git/dotty/scala2-library-cc/src/scala/concurrent/impl/Promise.scala:74:39 
[error] 74 |      compressed(current = c, target = c, owner = owner)
[error]    |                                       ^
[error]    |Separation failure: argument of type  (c : scala.concurrent.impl.Promise.DefaultPromise[box T^?]^{Link.this.to})
[error]    |to method compressed: (current: scala.concurrent.impl.Promise.DefaultPromise[T]^{cap.rd, Link.this},
[error]    |  target: scala.concurrent.impl.Promise.DefaultPromise[T]^, owner:
[error]    |  scala.concurrent.impl.Promise.DefaultPromise[T]^):
[error]    |  scala.concurrent.impl.Promise.DefaultPromise[T]^{Link.this, current, target,
[error]    |    owner}
[error]    |corresponds to capture-polymorphic formal parameter target of type  scala.concurrent.impl.Promise.DefaultPromise[T]^
[error]    |and hides capabilities  {c}.
[error]    |Some of these overlap with the captures of the function prefix with type  (Link.this : scala.concurrent.impl.Promise.Link[T]^{Link.this.to}).
[error]    |
[error]    |  Hidden set of current argument        : {c}
[error]    |  Hidden footprint of current argument  : {c, Link.this.to}
[error]    |  Capture set of function prefix        : {Link.this}
[error]    |  Footprint set of function prefix      : {Link.this, Link.this.to}
[error]    |  The two sets overlap at               : {Link.this.to}
[error] -- Error: /home/olhotak/git/dotty/scala2-library-cc/src/scala/concurrent/impl/Promise.scala:167:45 
[error] 167 |              zipped.tryComplete(try Success(f(left.get, right.get)) catch { case e if NonFatal(e) => Failure(e) })
[error]     |                                             ^
[error]     |Separation failure: Illegal access to {f} which is hidden by the previous definition
[error]     |of value thisF with type scala.util.Try[T] => Unit.
[error]     |This type hides capabilities  {buffer, zipped, f}
[error] -- Error: /home/olhotak/git/dotty/scala2-library-cc/src/scala/concurrent/impl/Promise.scala:363:28 
[error] 363 |          } else linkRootOf(p, l)
[error]     |                            ^
[error]     |Separation failure: argument of type  (p :
[error]     |  scala.concurrent.impl.Promise.DefaultPromise[box T^?]^{l, DefaultPromise.this}
[error]     |  )
[error]     |to method linkRootOf: (target: scala.concurrent.impl.Promise.DefaultPromise[T]^, link:
[error]     |  scala.concurrent.impl.Promise.Link[T]^): Unit
[error]     |corresponds to capture-polymorphic formal parameter target of type  scala.concurrent.impl.Promise.DefaultPromise[T]^
[error]     |and hides capabilities  {p}.
[error]     |Some of these overlap with the captures of the second argument with type  scala.concurrent.impl.Promise.Link[box T^?]{
[error]     |  val to: scala.concurrent.impl.Promise.DefaultPromise[box T^?]^{l*}}^{l}.
[error]     |
[error]     |  Hidden set of current argument        : {p}
[error]     |  Hidden footprint of current argument  : {p, l, DefaultPromise.this, link, target}
[error]     |  Capture set of second argument        : {l*}
[error]     |  Footprint set of second argument      : {l*, link, target}
[error]     |  The two sets overlap at               : {link, target}
[error] four errors found

@olhotak
Copy link
Contributor Author

olhotak commented May 2, 2025

Compiles if we change useSepChecks to false in CaptureOps.scala.

val c = get()
compressed(current = c, target = c, owner = owner)
}

/**
* The combination of traversing and possibly unlinking of a given `target` DefaultPromise.
**/
@inline @tailrec private[this] final def compressed(current: DefaultPromise[T]^{cap.rd, this}, target: DefaultPromise[T]^, owner: DefaultPromise[T]^): DefaultPromise[T]^{this, current, target, owner} = {
@inline @tailrec private[this] final def compressed(current: DefaultPromise[T]^{this, to}, target: DefaultPromise[T]^{cap, this, current}, owner: DefaultPromise[T]^): DefaultPromise[T]^{to, target, owner} = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should look into this more, I tried simplifying this signature but it seems separation checker is not trying to shorten paths

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants