Skip to content

Commit 9c0a65c

Browse files
committed
Add unsafeBoxToArg operation.
We need an unsafe transform from {*} A => B to box {*} A => B I don't think this is expressible with `unsafeBox/unsafeUnbox` alone.
1 parent ab31b89 commit 9c0a65c

File tree

4 files changed

+22
-3
lines changed

4 files changed

+22
-3
lines changed

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,21 @@ class CheckCaptures extends Recheck, SymTransformer:
337337
override def recheckApply(tree: Apply, pt: Type)(using Context): Type =
338338
val meth = tree.fun.symbol
339339
includeCallCaptures(meth, tree.srcPos)
340-
if meth == defn.Caps_unsafeBox || meth == defn.Caps_unsafeUnbox then
340+
def mapArgUsing(f: Type => Type) =
341341
val arg :: Nil = tree.args: @unchecked
342-
val argType0 = recheckStart(arg, pt)
343-
.forceBoxStatus(boxed = meth == defn.Caps_unsafeBox)
342+
val argType0 = f(recheckStart(arg, pt))
344343
val argType = super.recheckFinish(argType0, arg, pt)
345344
super.recheckFinish(argType, tree, pt)
345+
346+
if meth == defn.Caps_unsafeBox then
347+
mapArgUsing(_.forceBoxStatus(true))
348+
else if meth == defn.Caps_unsafeUnbox then
349+
mapArgUsing(_.forceBoxStatus(false))
350+
else if meth == defn.Caps_unsafeBoxFunArg then
351+
mapArgUsing {
352+
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, isErased) =>
353+
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, isErased)
354+
}
346355
else
347356
super.recheckApply(tree, pt) match
348357
case appType @ CapturingType(appType1, refs) =>

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ class Definitions {
963963
@tu lazy val CapsModule: Symbol = requiredModule("scala.caps")
964964
@tu lazy val Caps_unsafeBox: Symbol = CapsModule.requiredMethod("unsafeBox")
965965
@tu lazy val Caps_unsafeUnbox: Symbol = CapsModule.requiredMethod("unsafeUnbox")
966+
@tu lazy val Caps_unsafeBoxFunArg: Symbol = CapsModule.requiredMethod("unsafeBoxFunArg")
966967
@tu lazy val captureRoot: TermSymbol = CapsModule.requiredValue("*")
967968

968969
// Annotation base classes

library/src/scala/caps.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import annotation.experimental
1717
*/
1818
extension [T](x: T) def unsafeUnbox: T = x
1919

20+
/** If argument is of type `box cs T`, converts to type `cs T`. This
21+
* avoids the error that would be raised when unboxing `*`.
22+
*/
23+
extension [T, U](f: T => U) def unsafeBoxFunArg: T => U = f
24+
2025
/** Mixing in this trait forces a trait or class to be pure, i.e.
2126
* have no capabilities retained in its self type.
2227
*/
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import caps.*
2+
def test =
3+
val tasks = new collection.mutable.ArrayBuffer[() => Unit]
4+
val _: Unit = tasks.foreach(((task: () => Unit) => task()).unsafeBoxFunArg)

0 commit comments

Comments
 (0)