Skip to content

Commit 8be4451

Browse files
committed
Fix recording of use sets under mutability
- whether we record x or x.rd also depends on the exclusivity in context - fix issue of missing updates for denotations when recording use of a path
1 parent 7e30b27 commit 8be4451

File tree

5 files changed

+82
-13
lines changed

5 files changed

+82
-13
lines changed

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -680,12 +680,20 @@ class CheckCaptures extends Recheck, SymTransformer:
680680
if pt.select.symbol.isReadOnlyMethod then
681681
markFree(ref.readOnly, tree)
682682
else
683-
markPathFree(ref.select(pt.select.symbol).asInstanceOf[TermRef], pt.pt, pt.select)
683+
val sel = ref.select(pt.select.symbol).asInstanceOf[TermRef]
684+
sel.recomputeDenot()
685+
// We need to do a recomputeDenot here since we have not yet properly
686+
// computed the type of the full path. This means that we erroneously
687+
// think the denotation is the same as in the previous phase so no
688+
// member computation is performed. A test case where this matters is
689+
// read-only-use.scala, where the error on r3 goes unreported.
690+
markPathFree(sel, pt.pt, pt.select)
684691
case _ =>
685-
if ref.derivesFromMutable && pt.isValueType && !pt.isMutableType then
686-
markFree(ref.readOnly, tree)
687-
else
688-
markFree(ref, tree)
692+
if ref.derivesFromMutable then
693+
if pt.isValueType && !pt.isMutableType || ref.exclusivityInContext != Exclusivity.OK
694+
then markFree(ref.readOnly, tree)
695+
else markFree(ref, tree)
696+
else markFree(ref, tree)
689697

690698
/** The expected type for the qualifier of a selection. If the selection
691699
* could be part of a capability path or is a a read-only method, we return

tests/neg-custom-args/captures/mutability.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
-- Error: tests/neg-custom-args/captures/mutability.scala:14:12 --------------------------------------------------------
2626
14 | self3().set(x) // error
2727
| ^^^^^^^^^^^
28-
| Cannot call update method set of Ref[T^{}]^{Ref.this.rd}
29-
| since its capture set {Ref.this.rd} of value self3 is read-only.
28+
| Cannot call update method set of Ref[T^{}]^{self3}
29+
| since its capture set {self3} is read-only.
3030
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutability.scala:15:31 -----------------------------------
3131
15 | val self4: () => Ref[T]^ = () => this // error
3232
| ^^^^^^^^^^
33-
| Found: () ->{Ref.this} Ref[T^'s1]^{Ref.this.rd}
33+
| Found: () ->{Ref.this.rd} Ref[T^'s1]^{Ref.this.rd}
3434
| Required: () => Ref[T]^
3535
|
3636
| Note that capability Ref.this.rd is not included in capture set {}.
@@ -79,7 +79,7 @@
7979
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutability.scala:42:29 -----------------------------------
8080
42 | val r5: () => Ref2[Int]^ = () => ref2 // error
8181
| ^^^^^^^^^^
82-
| Found: () ->{ref2} Ref2[Int]^{ref2}
82+
| Found: () ->{ref2.rd} Ref2[Int]^{ref2}
8383
| Required: () => Ref2[Int]^
8484
|
8585
| Note that capability ref2 is not included in capture set {}.

tests/neg-custom-args/captures/mutvars.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
-- Error: tests/neg-custom-args/captures/mutvars.scala:13:16 -----------------------------------------------------------
2626
13 | self3().fld = x // error
2727
| ^^^^^^^^^^^^^^^
28-
| Cannot assign to field fld of Ref[T^{}]^{Ref.this.rd}
29-
| since its capture set {Ref.this.rd} of value self3 is read-only.
28+
| Cannot assign to field fld of Ref[T^{}]^{self3}
29+
| since its capture set {self3} is read-only.
3030
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutvars.scala:14:31 --------------------------------------
3131
14 | val self4: () => Ref[T]^ = () => this // error
3232
| ^^^^^^^^^^
33-
| Found: () ->{Ref.this} Ref[T^'s1]^{Ref.this.rd}
33+
| Found: () ->{Ref.this.rd} Ref[T^'s1]^{Ref.this.rd}
3434
| Required: () => Ref[T]^
3535
|
3636
| Note that capability Ref.this.rd is not included in capture set {}.
@@ -79,7 +79,7 @@
7979
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutvars.scala:41:29 --------------------------------------
8080
41 | val r5: () => Ref2[Int]^ = () => ref2 // error
8181
| ^^^^^^^^^^
82-
| Found: () ->{ref2} Ref2[Int]^{ref2}
82+
| Found: () ->{ref2.rd} Ref2[Int]^{ref2}
8383
| Required: () => Ref2[Int]^
8484
|
8585
| Note that capability ref2 is not included in capture set {}.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/read-only-use.scala:21:21 --------------------------------
2+
21 | val _: () -> Int = f // error
3+
| ^
4+
| Found: (f : () ->{r.rd} Int)
5+
| Required: () -> Int
6+
|
7+
| Note that capability r.rd is not included in capture set {}.
8+
|
9+
| longer explanation available when compiling with `-explain`
10+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/read-only-use.scala:26:21 --------------------------------
11+
26 | val _: () -> Int = g // error
12+
| ^
13+
| Found: (g : () ->{r2.x.rd} Int)
14+
| Required: () -> Int
15+
|
16+
| Note that capability r2.x.rd is not included in capture set {}.
17+
|
18+
| longer explanation available when compiling with `-explain`
19+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/read-only-use.scala:31:21 --------------------------------
20+
31 | val _: () -> Int = h // error
21+
| ^
22+
| Found: (h : () ->{r3.xx.rd} Int)
23+
| Required: () -> Int
24+
|
25+
| Note that capability r3.xx.rd is not included in capture set {}.
26+
|
27+
| longer explanation available when compiling with `-explain`
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Ref[T](init: T) extends caps.Mutable:
2+
var fld: T = init
3+
update def set(x: T) = this.fld = x
4+
def f(x: T) =
5+
val self3 = () => this
6+
val _: () ->{this.rd} Ref[T]^{this.rd} = self3
7+
8+
class Ref2[T](init: T) extends caps.Mutable:
9+
val x: Ref[T]^ = Ref[T](init)
10+
update def set(x: T) = this.x.set(x)
11+
12+
class Ref3[T](init: T) extends caps.Mutable:
13+
val xx = Ref[T](init)
14+
update def set(x: T) = this.xx.set(x)
15+
16+
def test =
17+
val r: Ref[Int] = Ref(22)
18+
val f = () => r.fld
19+
val _: () ->{r.rd} Int = f
20+
val f2: () ->{r.rd} Int = () => r.fld
21+
val _: () -> Int = f // error
22+
23+
val r2: Ref2[Int] = Ref2(22)
24+
val g = () => r2.x.fld
25+
val _: () ->{r2.x.rd} Int = g
26+
val _: () -> Int = g // error
27+
28+
val r3: Ref3[Int] = Ref3(22)
29+
val h = () => r3.xx.fld
30+
val _: () ->{r3.xx.rd} Int = h
31+
val _: () -> Int = h // error
32+
33+
34+

0 commit comments

Comments
 (0)