Skip to content

Commit e05e3a3

Browse files
authored
Flatten nested capture sets in retainedElementsRaw (#23571)
Without the added clause, i23570 looks like this after typer: ```scala [[syntax trees at end of typer]] // i23570.scala package <empty> { final lazy module val i23570$package: i23570$package = new i23570$package() final module class i23570$package() extends Object() { this: i23570$package.type => def f[C >: scala.caps.CapSet <: scala.caps.CapSet^{cap}]( xs: List[(() -> Unit)^{C}]): List[(() -> Unit)^{C}] = xs.reverse def test(io: Object^{cap}, async: Object^{cap}): Unit = { val ok: List[() ->{scala.caps.CapSet^{io}} Unit] = f[_root_.scala.caps.CapSet^{io}](Nil) val x: List[() ->{scala.caps.CapSet^{io}} Unit] -> List[() ->{scala.caps.CapSet^{io}} Unit] = (xs: List[() ->{scala.caps.CapSet^{io}} Unit]) => f[_root_.scala.caps.CapSet^{io}](xs) val y: List[() ->{scala.caps.CapSet^{io, async}} Unit] -> List[() ->{scala.caps.CapSet^{io, async}} Unit] = (xs: List[() ->{scala.caps.CapSet^{io, async}} Unit]) => f[_root_.scala.caps.CapSet^{io, async}](xs) () } } } ``` Note the nested capture sets in the types of `x` and `y`. Fixes #23570
2 parents 42fdd76 + 5a440b4 commit e05e3a3

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ extension (tp: Type)
9494
def retainedElementsRaw(using Context): List[Type] = tp match
9595
case OrType(tp1, tp2) =>
9696
tp1.retainedElementsRaw ++ tp2.retainedElementsRaw
97+
case AnnotatedType(tp1, ann) if tp1.derivesFrom(defn.Caps_CapSet) && ann.symbol.isRetains =>
98+
ann.tree.retainedSet.retainedElementsRaw
9799
case tp =>
98100
// Nothing is a special type to represent the empty set
99101
if tp.isNothingType then Nil
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def f[C^](xs: List[() ->{C} Unit]): List[() ->{C} Unit] =
2+
xs.reverse
3+
4+
def test(io: Object^, async: Object^): Unit =
5+
val ok = f[{io}](Nil)
6+
val x = f[{io}] // was error
7+
val y = f[{io, async}] // was error

tests/pos/cc-use-alternatives.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import language.experimental.captureChecking
2+
// no separation checking
3+
import caps.{cap, use}
4+
5+
def foo1(@use xs: List[() => Unit]): Unit =
6+
var x: () ->{xs*} Unit = xs.head
7+
var ys = xs
8+
while ys.nonEmpty do
9+
ys = ys.tail
10+
x = ys.head
11+
12+
def foo2(@use xs: List[() => Unit]): Unit =
13+
var x: () => Unit = xs.head // note: this would fail separation checking
14+
var ys = xs
15+
while ys.nonEmpty do
16+
ys = ys.tail
17+
x = ys.head
18+
19+
def foo3[@use C^](xs: List[() ->{C} Unit]): Unit =
20+
var x: () ->{C} Unit = xs.head
21+
var ys = xs
22+
while ys.nonEmpty do
23+
ys = ys.tail
24+
x = ys.head

0 commit comments

Comments
 (0)