Skip to content

Commit 3edb4bf

Browse files
committed
Enforce mutable field restrictions under separation checking.
Fields are only allowed in stateful classes unless marked with @untrackedCaptures.
1 parent d27544a commit 3edb4bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+171
-157
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ class CheckCaptures extends Recheck, SymTransformer:
11701170
""
11711171
disallowBadRootsIn(
11721172
tree.tpt.nuType, NoSymbol, i"Mutable $sym", "have type", addendum, sym.srcPos)
1173-
if ccConfig.noUnsafeMutableFields
1173+
if ccConfig.strictMutability
11741174
&& sym.owner.isClass
11751175
&& !sym.owner.derivesFrom(defn.Caps_Stateful)
11761176
&& !sym.hasAnnotation(defn.UntrackedCapturesAnnot) then

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ object ccConfig:
4848
*/
4949
inline val useSpanCapset = false
5050

51-
/** If true force all mutable fields to be in Stateful classes, unless they
52-
* are annotated with @untrackedCaptures
53-
*/
54-
inline val noUnsafeMutableFields = false
55-
5651
/** If true, do level checking for FreshCap instances */
5752
def useFreshLevels(using Context): Boolean =
5853
Feature.sourceVersion.stable.isAtLeast(SourceVersion.`3.7`)
@@ -65,7 +60,10 @@ object ccConfig:
6560
def allowUse(using Context): Boolean =
6661
Feature.sourceVersion.stable.isAtMost(SourceVersion.`3.7`)
6762

68-
/** Treat arrays as mutable types. Enabled under separation checking */
63+
/** Treat arrays as mutable types and force all mutable fields to be in Stateful
64+
* classes, unless they are annotated with @untrackedCaptures.
65+
* Enabled under separation checking
66+
*/
6967
def strictMutability(using Context): Boolean =
7068
Feature.enabled(Feature.separationChecking)
7169

tests/neg-custom-args/captures/cc-poly-source.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import caps.use
1010
class Listener
1111

1212
class Source[X^]:
13-
private var listeners: Set[Listener^{X}] = Set.empty
13+
@caps.unsafe.untrackedCaptures private var listeners: Set[Listener^{X}] = Set.empty
1414
def register(x: Listener^{X}): Unit =
1515
listeners += x
1616

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/class-level-attack.scala:17:26 ---------------------------
2-
17 | def set(x: IO^) = r.put(x) // error
3-
| ^
4-
| Found: IO^{x}
5-
| Required: IO^
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/class-level-attack.scala:17:33 ---------------------------
2+
17 | update def set(x: IO^) = r.put(x) // error
3+
| ^
4+
| Found: IO^{x}
5+
| Required: IO^
66
|
7-
| Note that capability x is not included in capture set {cap}
8-
| because (x : IO^²) in method set is not visible from cap in value r.
7+
| Note that capability x is not included in capture set {cap}
8+
| because (x : IO^²) in method set is not visible from cap in value r.
99
|
10-
| where: ^ and cap refer to a fresh root capability in the type of value r
11-
| ^² refers to a fresh root capability in the type of parameter x
10+
| where: ^ and cap refer to a fresh root capability in the type of value r
11+
| ^² refers to a fresh root capability in the type of parameter x
1212
|
1313
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/class-level-attack.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ import caps.*
33

44
class IO
55

6-
class Ref[X](init: X):
6+
class Ref[X](init: X) extends caps.Stateful:
77
var x = init
88
def get: X = x
9-
def put(y: X): Unit = x = y
9+
update def put(y: X): Unit = x = y
1010

11-
class C(io: IO^):
12-
val r: Ref[IO^] = Ref[IO^](io)
11+
class C(io: IO^) extends caps.Stateful:
12+
val r: Ref[IO^]^ = Ref[IO^](io)
1313
//Type variable X of constructor Ref cannot be instantiated to box IO^ since
1414
//that type captures the root capability `cap`.
1515
// where: ^ refers to the universal root capability
1616
val r2: Ref[IO^] = Ref(io)
17-
def set(x: IO^) = r.put(x) // error
17+
update def set(x: IO^) = r.put(x) // error
1818

1919
def outer(outerio: IO^) =
2020
val c = C(outerio)

tests/neg-custom-args/captures/filevar-expanded.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object test2:
2323
class File:
2424
def write(x: String): Unit = ???
2525

26-
class Service(tracked val io: IO^):
26+
class Service(tracked val io: IO^) extends caps.Stateful:
2727
var file: File^{io} = uninitialized
2828
def log = file.write("log")
2929

tests/neg-custom-args/captures/filevar-multi-ios.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class File:
88

99
object test1:
1010

11-
class Service(val io: IO, val io2: IO):
11+
class Service(val io: IO, val io2: IO) extends caps.Stateful:
1212
var file: File^{io} = uninitialized
1313
var file2: File^{io2} = uninitialized
1414
def log = file.write("log")
@@ -25,7 +25,7 @@ object test1:
2525

2626
object test2:
2727

28-
class Service(tracked val io: IO, tracked val io2: IO):
28+
class Service(tracked val io: IO, tracked val io2: IO) extends caps.Stateful:
2929
var file: File^{io} = uninitialized
3030
var file2: File^{io2} = uninitialized
3131
def log = file.write("log")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import compiletime.uninitialized
44
class File:
55
def write(x: String): Unit = ???
66

7-
class Service:
7+
class Service extends caps.Stateful:
88
var file: File^ = uninitialized //OK, was error under sealed
99
def log = file.write("log") // OK, was error under unsealed
1010

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ final class Cell[A](head: () => IterableOnce[A]^):
1111
def headIterator: Iterator[A]^{this} = head().iterator
1212

1313
class File private ():
14-
private var closed = false
14+
@caps.unsafe.untrackedCaptures private var closed = false
1515

1616
def close() = closed = true
1717

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

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)