Skip to content

Commit 2ae29fb

Browse files
committed
Fix box adaptation
1 parent 88b328c commit 2ae29fb

File tree

3 files changed

+34
-6
lines changed

3 files changed

+34
-6
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -991,13 +991,23 @@ class CheckCaptures extends Recheck, SymTransformer:
991991
}
992992

993993
// Capture set of the term after adaptation
994-
val cs1 = cs ++ leaked
994+
val cs1 = if covariant then cs ++ leaked else cs
995+
996+
def checkLeaked: Boolean =
997+
covariant || leaked.subCaptures(cs1, frozen = false).isOK || {
998+
report.error(
999+
em"""$expected cannot be box-converted to $actual
1000+
|since the additional capture set $leaked resulted from box conversion is not allowed in $actual""", pos)
1001+
false
1002+
}
9951003

9961004
// Compute the adapted type
9971005
def adaptedType(resultBoxed: Boolean) =
9981006
if (styp1 eq styp) && leaked.isAlwaysEmpty && boxed == resultBoxed then actual
9991007
else styp1.capturing(if alwaysConst then CaptureSet(cs1.elems) else cs1).forceBoxStatus(resultBoxed)
10001008

1009+
checkLeaked
1010+
10011011
if needsAdaptation then
10021012
val criticalSet = // the set which is not allowed to have `cap`
10031013
if covariant then cs1 // can't box with `cap`
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import language.experimental.captureChecking
2+
3+
trait Cap
4+
5+
def useCap[X](x: X): (X -> Unit) -> Unit = ???
6+
7+
def test1(c: Cap^): Unit =
8+
val f: (Cap^{c} -> Unit) -> Unit = useCap[Cap^{c}](c) // error
9+
10+
def test2(c: Cap^, d: Cap^): Unit =
11+
def useCap1[X](x: X): (X => Unit) -> Unit = ???
12+
val f1: (Cap^{c} => Unit) ->{c} Unit = useCap1[Cap^{c}](c) // ok
13+
14+
def useCap2[X](x: X): (X ->{c} Unit) -> Unit = ???
15+
val f2: (Cap^{c} -> Unit) ->{c} Unit = useCap2[Cap^{c}](c) // ok
16+
17+
def useCap3[X](x: X): (X ->{d} Unit) -> Unit = ???
18+
val f3: (Cap^{c} -> Unit) ->{cap} Unit = useCap3[Cap^{c}](c) // error

tests/neg-custom-args/captures/box-unsoundness.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
class CanIO { def use(): Unit = () }
33
def use[X](x: X): (op: X -> Unit) -> Unit = op => op(x)
44
def test(io: CanIO^): Unit =
5-
val f: (CanIO^ => Unit) -> Unit = use[CanIO^](io) //
6-
val _: (CanIO^ => Unit) -> Unit = f // error
5+
val f: (CanIO^ => Unit) -> Unit = use[CanIO^](io) // error
6+
val _: (CanIO^ => Unit) -> Unit = f
77

8-
val g1 = () => f(x => x.use()) // error
8+
val g1 = () => f(x => x.use())
99

1010
val a1 = f(x => x.use())
1111
val a2 = () => f(x => x.use())
12-
val g2: () -> Unit = a2 // error
13-
// was UNSOUND: g uses the capability io but has an empty capture set
12+
val g2: () -> Unit = a2
13+
// was UNSOUND: g uses the capability io but has an empty capture set

0 commit comments

Comments
 (0)