Skip to content

Commit e180507

Browse files
committed
Recompute denotations when computing ofInfo of reach capabilities
Fixes scala#23582 But it is quite a hack. We should try to find a more principled solution.
1 parent 4689288 commit e180507

File tree

4 files changed

+51
-0
lines changed

4 files changed

+51
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,10 @@ object CaptureSet:
15731573
/** The capture set of the type underlying the capability `c` */
15741574
def ofInfo(c: Capability)(using Context): CaptureSet = c match
15751575
case Reach(c1) =>
1576+
c1 match
1577+
case c1: TermRef => c1.safeRecomputeDenot()
1578+
// following widen would be wrong otherwise
1579+
case _ =>
15761580
c1.widen.computeDeepCaptureSet(includeTypevars = true)
15771581
.showing(i"Deep capture set of $c: ${c1.widen} = ${result}", capt)
15781582
case Restricted(c1, cls) =>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,10 @@ object Types extends TypeUtils {
26012601
def recomputeDenot()(using Context): Unit =
26022602
setDenot(memberDenot(name, allowPrivate = !symbol.exists || symbol.is(Private)))
26032603

2604+
def safeRecomputeDenot()(using Context): Unit =
2605+
val newDenot = memberDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))
2606+
if newDenot.exists then setDenot(newDenot)
2607+
26042608
private def setDenot(denot: Denotation)(using Context): Unit = {
26052609
if ctx.base.checkNoDoubleBindings then
26062610
checkSymAssign(denot.symbol)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23582.scala:27:26 ---------------------------------------
2+
27 | parReduce(1 to 1000): (x, y) => // error
3+
| ^
4+
|Found: (x: Int, y: Int) ->{write, read} Int
5+
|Required: (Int, Int) ->{cap.only[Read]} Int
6+
|
7+
|Note that capability write is not included in capture set {cap.only[Read]}.
8+
|
9+
|where: cap is a fresh root capability created in method test when checking argument to parameter op of method parReduce
10+
28 | write(x)
11+
29 | x + y + read()
12+
|
13+
| longer explanation available when compiling with `-explain`
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import caps.*
2+
object Levels:
3+
4+
trait Read extends Classifier, SharedCapability
5+
trait ReadWrite extends Classifier, SharedCapability
6+
7+
class Box[T](acc: T):
8+
val access: T = acc
9+
10+
def parReduce(xs: Seq[Int])(op: (Int, Int) ->{cap.only[Read]} Int): Int = xs.reduce(op)
11+
12+
@main def test =
13+
val r: Box[Read^] = ???
14+
val rw: Box[ReadWrite^] = ???
15+
val read: () ->{r.access*} Int = ???
16+
val write: Int ->{rw.access*} Unit = ???
17+
val checkRead: () ->{cap.only[Read]} Int = read
18+
19+
//read() // causes error with and without the println below
20+
parReduce(1 to 1000): (x, y) =>
21+
//println(r.access) // ok only if this is uncommented
22+
read() + read() // should be ok
23+
24+
parReduce(1 to 1000): (x, y) =>
25+
x + y + read() // should be ok
26+
27+
parReduce(1 to 1000): (x, y) => // error
28+
write(x)
29+
x + y + read()
30+

0 commit comments

Comments
 (0)