diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureSet.scala b/compiler/src/dotty/tools/dotc/cc/CaptureSet.scala index a53c4f041a1d..876730dbfc51 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureSet.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureSet.scala @@ -1644,7 +1644,8 @@ object CaptureSet: else this(acc, parent) def abstractTypeCase(acc: CaptureSet, t: TypeRef, upperBound: Type) = - if includeTypevars && upperBound.isExactlyAny then fresh(Origin.DeepCS(t)) + if t.derivesFrom(defn.Caps_CapSet) then t.singletonCaptureSet + else if includeTypevars && upperBound.isExactlyAny then fresh(Origin.DeepCS(t)) else this(acc, upperBound) collect(CaptureSet.empty, tp) diff --git a/tests/neg-custom-args/captures/i24309-region-orig.check b/tests/neg-custom-args/captures/i24309-region-orig.check new file mode 100644 index 000000000000..31a1af06b6b9 --- /dev/null +++ b/tests/neg-custom-args/captures/i24309-region-orig.check @@ -0,0 +1,9 @@ +-- Error: tests/neg-custom-args/captures/i24309-region-orig.scala:17:36 ------------------------------------------------ +17 | val x = r1.subregion[Ref^{r1.R}]: r2 => // error, limitation + | ^ + | Local reach capability r1.R leaks into capture scope of enclosing function. + | You could try to abstract the capabilities referred to by r1.R in a capset variable. +18 | var a: Ref^{r1.R} = r1.alloc(0) +19 | var b: Ref^{r2.R} = r2.alloc(0) +20 | val c: Ref^{r1.R} = b +21 | a diff --git a/tests/neg-custom-args/captures/i24309-region-orig.scala b/tests/neg-custom-args/captures/i24309-region-orig.scala new file mode 100644 index 000000000000..d12eb1f98c39 --- /dev/null +++ b/tests/neg-custom-args/captures/i24309-region-orig.scala @@ -0,0 +1,22 @@ +import language.experimental.captureChecking +import caps.* +class Ref(private var x: Int): + def get = x + def set(y: Int) = x = y +trait Region extends SharedCapability: + r: Region^ => + type R^ + def alloc(x: Int): Ref^{R} = Ref(x) + def subregion[T](f: (Region { type R >: r.R }) => T): T = + class R2 extends Region: + type R = r.R + f(new R2) +def withRegion[T](f: Region => T): T = f(new Region {}) +@main def main() = + withRegion: r1 => + val x = r1.subregion[Ref^{r1.R}]: r2 => // error, limitation + var a: Ref^{r1.R} = r1.alloc(0) + var b: Ref^{r2.R} = r2.alloc(0) + val c: Ref^{r1.R} = b + a + 0 diff --git a/tests/neg-custom-args/captures/i24309a.check b/tests/neg-custom-args/captures/i24309a.check new file mode 100644 index 000000000000..251d9bac3ccb --- /dev/null +++ b/tests/neg-custom-args/captures/i24309a.check @@ -0,0 +1,4 @@ +-- Error: tests/neg-custom-args/captures/i24309a.scala:4:34 ------------------------------------------------------------ +4 |def runOps2[C^](): Unit = runOps[{C}](???) // error + | ^ + | Capture set parameter C leaks into capture scope of method runOps2. diff --git a/tests/neg-custom-args/captures/i24309a.scala b/tests/neg-custom-args/captures/i24309a.scala new file mode 100644 index 000000000000..9f626f90eb10 --- /dev/null +++ b/tests/neg-custom-args/captures/i24309a.scala @@ -0,0 +1,4 @@ +import language.experimental.captureChecking +def runOps[C^](ops: List[() ->{C} Unit]): Unit = ??? +def runOps1[C^](xs: Object^{C}): Unit = runOps[{C}](???) // ok +def runOps2[C^](): Unit = runOps[{C}](???) // error diff --git a/tests/pos-custom-args/captures/i24309-region.scala b/tests/pos-custom-args/captures/i24309-region.scala new file mode 100644 index 000000000000..37d25702a6c8 --- /dev/null +++ b/tests/pos-custom-args/captures/i24309-region.scala @@ -0,0 +1,34 @@ +import language.experimental.captureChecking +import language.experimental.separationChecking + +import caps.* + +object Regions: + class Ref(private var x: Int): + def get = x + def set(y: Int) = x = y + + trait Region[R^] extends SharedCapability: + region: Region[R]^ => + def alloc(value: Int): Ref^{R} = Ref(value) + + def subregion[T](f: [R2^ >: R] => (Region[R2]) => T): T = + val r = new Region[R] {} + f(r) + + + object Region: + def apply[T](f: [R^] => Region[R] => T): T = + val r = new Region[{}] {} + f(r) + + @main def main() = + import Region.* + Region: [R^] => + r1 => + val x = r1.subregion: [R2^ >: R] => + r2 => + val a = r1.alloc(0) + val b = r2.alloc(0) + a + 0 diff --git a/tests/pos-custom-args/captures/i24309.scala b/tests/pos-custom-args/captures/i24309.scala new file mode 100644 index 000000000000..8847037c9499 --- /dev/null +++ b/tests/pos-custom-args/captures/i24309.scala @@ -0,0 +1,5 @@ +import language.experimental.captureChecking +trait Region[R^] +def id[T](x: T): T = ??? +def foo[R^](r: Region[R]): Unit = + val t2 = () => id[Object^{R}](???) // was error, now ok diff --git a/tests/pos-custom-args/captures/i24309b.scala b/tests/pos-custom-args/captures/i24309b.scala new file mode 100644 index 000000000000..3648c9c00409 --- /dev/null +++ b/tests/pos-custom-args/captures/i24309b.scala @@ -0,0 +1,6 @@ +import language.experimental.captureChecking +def runOps[C^](ops: List[() ->{C} Unit]): Unit = ops.foreach(_()) // ok +trait Ops[C^] { def toList: List[() ->{C} Unit] } +def runOpsAlt1[C1^](ops: Ops[C1]): Unit = runOps[{C1}](???) // was error, now ok +def runOpsAlt2[C2^](ops: Ops[{}]^{C2}): Unit = runOps[{C2}](???) // ok +def runOpsAlt3[C3^](ops: Ops[C3]^{C3}): Unit = runOps[{C3}](???) // was error, no ok