Skip to content

Commit 6642e08

Browse files
committed
Fix mutability computation for DerivedVars
Need to disable `associateWithMutable` for them.
1 parent f080ad0 commit 6642e08

File tree

4 files changed

+101
-11
lines changed

4 files changed

+101
-11
lines changed

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,15 @@ sealed abstract class CaptureSet extends Showable:
6060
def mutability_=(x: Mutability): Unit =
6161
myMut = x
6262

63-
/** Mark this capture set as belonging to a Mutable type. */
64-
def setMutable()(using Context): Unit
63+
/** Mark this capture set as belonging to a Mutable type. Called when a new
64+
* CapturingType is formed. This is different from the setter `mutability_=`
65+
* in that it be defined with different behaviors:
66+
*
67+
* - set mutability to Mutable (for normal Vars)
68+
* - take mutability from the set's sources (for DerivedVars)
69+
* - compute mutability on demand based on mutability of elements (for Consts)
70+
*/
71+
def associateWithMutable()(using Context): Unit
6572

6673
/** Is this capture set constant (i.e. not an unsolved capture variable)?
6774
* Solved capture variables count as constant.
@@ -613,7 +620,7 @@ object CaptureSet:
613620

614621
private var isComplete = true
615622

616-
def setMutable()(using Context): Unit =
623+
def associateWithMutable()(using Context): Unit =
617624
if !elems.isEmpty then
618625
isComplete = false // delay computation of Mutability status
619626

@@ -708,7 +715,7 @@ object CaptureSet:
708715
*/
709716
var deps: Deps = SimpleIdentitySet.empty
710717

711-
def setMutable()(using Context): Unit =
718+
def associateWithMutable()(using Context): Unit =
712719
mutability = Mutable
713720

714721
def isConst(using Context) = solved >= ccState.iterationId
@@ -1031,6 +1038,9 @@ object CaptureSet:
10311038

10321039
addAsDependentTo(source)
10331040

1041+
/** Mutability is same as in source, except for readOnly */
1042+
override def associateWithMutable()(using Context): Unit = ()
1043+
10341044
override def mutableToReader(origin: CaptureSet)(using Context): Boolean =
10351045
super.mutableToReader(origin)
10361046
&& ((origin eq source) || source.mutableToReader(this))

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ object CapturingType:
3939
case parent @ CapturingType(parent1, refs1) if boxed || !parent.isBoxed =>
4040
apply(parent1, refs ++ refs1, boxed)
4141
case _ =>
42-
if parent.derivesFromMutable then refs.setMutable()
42+
if parent.derivesFromMutable then refs.associateWithMutable()
4343
refs.adoptClassifier(parent.classifier)
4444
AnnotatedType(parent, CaptureAnnotation(refs, boxed)(defn.RetainsAnnot))
4545

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

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,83 @@
2424
| where: ^ and cap refer to a fresh root capability classified as Mutable in the type of value self2
2525
|
2626
| longer explanation available when compiling with `-explain`
27-
-- Error: tests/neg-custom-args/captures/mutability.scala:15:25 --------------------------------------------------------
28-
15 | def set(x: T) = this.x.set(x) // error
27+
-- Error: tests/neg-custom-args/captures/mutability.scala:14:12 --------------------------------------------------------
28+
14 | self3().set(x) // error
29+
| ^^^^^^^^^^^
30+
| cannot call update method set from Ref[T^{}]^{Ref.this.rd},
31+
| since its capture set {Ref.this.rd} of value self3 is read-only
32+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutability.scala:15:31 -----------------------------------
33+
15 | val self4: () => Ref[T]^ = () => this // error
34+
| ^^^^^^^^^^
35+
| Found: () ->{Ref.this} Ref[T^'s1]^{Ref.this.rd}
36+
| Required: () => Ref[T]^
37+
|
38+
| Note that capability Ref.this.rd is not included in capture set {}.
39+
|
40+
| Note that {cap} is an exclusive capture set of the mutable type Ref[T]^,
41+
| it cannot subsume a read-only capture set of the mutable type Ref[T^'s1]^{Ref.this.rd}.
42+
|
43+
| where: => refers to a fresh root capability in the type of value self4
44+
| ^ and cap refer to a fresh root capability classified as Mutable in the type of value self4
45+
|
46+
| longer explanation available when compiling with `-explain`
47+
-- Error: tests/neg-custom-args/captures/mutability.scala:19:12 --------------------------------------------------------
48+
19 | self5().set(x) // error
49+
| ^^^^^^^^^^^
50+
| cannot call update method set from Ref[T^{}]^{Ref.this.rd},
51+
| since its capture set {Ref.this.rd} of method self5 is read-only
52+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutability.scala:20:27 -----------------------------------
53+
20 | def self6(): Ref[T]^ = this // error
54+
| ^^^^
55+
| Found: Ref[T]^{Ref.this.rd}
56+
| Required: Ref[T]^
57+
|
58+
| Note that capability Ref.this.rd is not included in capture set {}.
59+
|
60+
| Note that {cap} is an exclusive capture set of the mutable type Ref[T]^,
61+
| it cannot subsume a read-only capture set of the mutable type Ref[T]^{Ref.this.rd}.
62+
|
63+
| where: ^ and cap refer to a fresh root capability classified as Mutable in the result type of method self6
64+
|
65+
| longer explanation available when compiling with `-explain`
66+
-- Error: tests/neg-custom-args/captures/mutability.scala:25:25 --------------------------------------------------------
67+
25 | def set(x: T) = this.x.set(x) // error
2968
| ^^^^^^^^^^
3069
| cannot call update method set from (Ref2.this.x : Ref[T^{}]^),
3170
| since the access is in method set, which is not an update method
3271
|
3372
| where: ^ refers to a fresh root capability classified as Mutable in the type of value x
34-
-- Error: tests/neg-custom-args/captures/mutability.scala:22:5 ---------------------------------------------------------
35-
22 | r1.set(33) // error
73+
-- Error: tests/neg-custom-args/captures/mutability.scala:32:5 ---------------------------------------------------------
74+
32 | r1.set(33) // error
3675
| ^^^^^^
3776
| cannot call update method set from (r1 : Ref[Int]),
3877
| since its capture set {r1} is read-only
39-
-- Error: tests/neg-custom-args/captures/mutability.scala:27:7 ---------------------------------------------------------
40-
27 | r3.x.set(33) // error
78+
-- Error: tests/neg-custom-args/captures/mutability.scala:37:7 ---------------------------------------------------------
79+
37 | r3.x.set(33) // error
4180
| ^^^^^^^^
4281
| cannot call update method set from (r3.x : Ref[Int]^),
4382
| since the capture set {r3} of its prefix (r3 : Ref2[Int]) is read-only
4483
|
4584
| where: ^ refers to a fresh root capability classified as Mutable in the type of value x
85+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mutability.scala:42:29 -----------------------------------
86+
42 | val r5: () => Ref2[Int]^ = () => ref2 // error
87+
| ^^^^^^^^^^
88+
| Found: () ->{ref2} Ref2[Int]^{ref2}
89+
| Required: () => Ref2[Int]^
90+
|
91+
| Note that capability ref2 is not included in capture set {}.
92+
|
93+
| Note that {cap} is an exclusive capture set of the mutable type Ref2[Int]^,
94+
| it cannot subsume a read-only capture set of the mutable type Ref2[Int]^{ref2}.
95+
|
96+
| where: => refers to a fresh root capability in the type of value r5
97+
| ^ and cap refer to a fresh root capability classified as Mutable in the type of value r5
98+
|
99+
| longer explanation available when compiling with `-explain`
100+
-- Error: tests/neg-custom-args/captures/mutability.scala:45:9 ---------------------------------------------------------
101+
45 | r6().x.set(33) // error
102+
| ^^^^^^^^^^
103+
| cannot call update method set from Ref[Int]^{cap.rd},
104+
| since its capture set {cap.rd} is read-only
105+
|
106+
| where: cap is a fresh root capability classified as Mutable in the type of value r6

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ class Ref[T](init: T) extends caps.Mutable:
1010
val self2: Ref[T]^ = this // error
1111
self2.set(x)
1212

13+
val self3 = () => this
14+
self3().set(x) // error
15+
val self4: () => Ref[T]^ = () => this // error
16+
self4().set(x)
17+
18+
def self5() = this
19+
self5().set(x) // error
20+
def self6(): Ref[T]^ = this // error
21+
self6().set(x)
22+
1323
class Ref2[T](init: T) extends caps.Mutable:
1424
val x = Ref[T](init)
1525
def set(x: T) = this.x.set(x) // error
@@ -26,4 +36,13 @@ def test =
2636
val r3: Ref2[Int] = Ref2(22)
2737
r3.x.set(33) // error
2838

39+
val r4 = () => Ref2(22)
40+
r4().x.set(33) // ok
41+
val ref2: Ref2[Int] = Ref2(22)
42+
val r5: () => Ref2[Int]^ = () => ref2 // error
43+
r5().x.set(33)
44+
val r6: () => Ref2[Int] = () => ref2
45+
r6().x.set(33) // error
46+
47+
2948

0 commit comments

Comments
 (0)