Skip to content

Commit 77c30e5

Browse files
authored
CC Language Reference Improvements v2 (#23818)
2 parents 17f1803 + 6e6cf79 commit 77c30e5

File tree

3 files changed

+113
-39
lines changed

3 files changed

+113
-39
lines changed

docs/_docs/reference/experimental/capture-checking/how-to-use.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,48 @@ nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/capture-che
66

77
## Enabling Capture Checking
88

9-
TODO
9+
Use Scala 3 nightly for the latest features and fixes.
10+
11+
Add this import in any file that uses capture checking:
12+
```scala
13+
import language.experimental.captureChecking
14+
```
15+
16+
### Separation Checking
17+
18+
Requires the import above:
19+
```scala
20+
import language.experimental.captureChecking
21+
import language.experimental.separationChecking
22+
```
23+
24+
### SBT Project Template
25+
26+
Alternatively, you can clone a pre-defined SBT project to get
27+
started: https://github.com/lampepfl/scala3-cc-template
28+
29+
### The REPL/Scala-CLI
30+
31+
Using the command line through explicit parameters:
32+
```bash
33+
scala -S 3.nightly -language:experimental.captureChecking
34+
```
35+
or when reading from a file:
36+
```scala
37+
// foo.scala:
38+
//> using scala 3.nightly
39+
import language.experimental.captureChecking
40+
...
41+
```
42+
Then, it suffices to run
43+
```bash
44+
scala foo.scala
45+
```
46+
47+
## API Documentation
48+
49+
Scaladoc supports capture checking. The nightly standard library API docs have it enabled by default:
50+
https://nightly.scala-lang.org/api/
1051

1152
## Compilation Options
1253

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/classifiers-secondclass.scala:41:28 ----------------------
2+
41 | parReduce(1 to 1000): (a, b) => // error
3+
| ^
4+
|Found: (a: Int, b: Int) ->{f.write, f.read} Int
5+
|Required: (Int, Int) ->{cap.only[Read]} Int
6+
|
7+
|Note that capability f.write is not included in capture set {cap.only[Read]}.
8+
|
9+
|where: cap is a fresh root capability created in anonymous function of type (f²: Levels.File^): Unit when checking argument to parameter op of method parReduce
10+
42 | f.write(42) // the error stems from here
11+
43 | a + b + f.read() // ok
12+
|
13+
| longer explanation available when compiling with `-explain`
14+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/classifiers-secondclass.scala:53:30 ----------------------
15+
53 | parReduce(1 to 1000): (a, b) => // error
16+
| ^
17+
|Found: (a: Int, b: Int) ->{f.write, f.read, g.read} Int
18+
|Required: (Int, Int) ->{cap.only[Read]} Int
19+
|
20+
|Note that capability f.write is not included in capture set {cap.only[Read]}.
21+
|
22+
|where: cap is a fresh root capability created in anonymous function of type (g²: Levels.File^): Unit when checking argument to parameter op of method parReduce
23+
54 | f.write(42) // the error stems from here
24+
55 | a + b + f.read() + g.read() // ok
25+
|
26+
| longer explanation available when compiling with `-explain`
27+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/classifiers-secondclass.scala:56:30 ----------------------
28+
56 | parReduce(1 to 1000): (a, b) => // error
29+
| ^
30+
|Found: (a: Int, b: Int) ->{g.write} Int
31+
|Required: (Int, Int) ->{cap.only[Read]} Int
32+
|
33+
|Note that capability g.write is not included in capture set {cap.only[Read]}.
34+
|
35+
|where: cap is a fresh root capability created in anonymous function of type (g²: Levels.File^): Unit when checking argument to parameter op of method parReduce
36+
57 | g.write(42) // the error stems from here
37+
58 | 0
38+
|
39+
| longer explanation available when compiling with `-explain`
Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,61 @@
11
import language.experimental.captureChecking
22
import language.experimental.separationChecking
3+
import language.experimental.erasedDefinitions
4+
35
import caps.*
46

57
// Test inspired by the "Gentrification Gone too Far?" paper
68
object Levels:
79

10+
/* User-defined capability classifiers */
811
trait Read extends Classifier, SharedCapability
912
trait ReadWrite extends Classifier, SharedCapability
1013

1114
trait File(val name: String):
12-
val r: Read^
13-
val rw: ReadWrite^
14-
// operations guarded by boxed capability members
15+
// file-specific capability members, these are ensured to be erased
16+
erased val r: Read^
17+
erased val rw: ReadWrite^
18+
// operations guarded by capability members
1519
val read: () ->{r} Int
1620
val write: Int ->{rw} Unit
1721

1822
object File:
1923
def apply(s: String): File^ = new File(s) {
20-
val r = new Read {}
21-
val rw = new ReadWrite {}
24+
erased val r = new Read {}
25+
erased val rw = new ReadWrite {}
2226
val read = () =>
2327
println(s"Reading from $name with capability $r")
2428
42
2529
val write = (i: Int) =>
2630
println(s"Writing $i to $name with capability $rw")
2731
}
2832

29-
// Unfortunately, we do not have @use lambdas yet
30-
trait UseFunction[U]:
31-
def apply[C^](f: File^{C}): U
32-
33-
def withFile[U](name: String)(block: UseFunction[U]): U = block(File(name)) // unrestricted use of files & other capabilities
33+
def withFile[U](name: String)(block: File^ => U): U = block(File(name)) // unrestricted use of files & other capabilities
3434
def parReduce[U](xs: Seq[U])(op: (U, U) ->{cap.only[Read]} U): U = xs.reduce(op) // only Read-classified allowed
3535

3636
@main def test =
37-
withFile("foo.txt"):
38-
new UseFunction[Unit]:
39-
def apply[C^](f: File^{C}): Unit =
40-
f.read() // ok
41-
parReduce(1 to 1000): (a, b) =>
42-
a * b * f.read() // ok
43-
parReduce(1 to 1000): (a, b) => // error
44-
f.write(42) // the error stems from here
45-
a + b + f.read() // ok
46-
f.write(42) // ok, unrestricted access to file
37+
withFile("foo.txt"): f =>
38+
f.read() // ok
39+
parReduce(1 to 1000): (a, b) =>
40+
a * b * f.read() // ok
41+
parReduce(1 to 1000): (a, b) => // error
42+
f.write(42) // the error stems from here
43+
a + b + f.read() // ok
44+
f.write(42) // ok, unrestricted access to file
4745

4846
def testMulti =
49-
withFile("foo.txt"):
50-
new UseFunction[Unit]:
51-
def apply[C^](f: File^{C}): Unit =
52-
withFile("bar.txt"):
53-
new UseFunction[Unit]:
54-
def apply[C^](g: File^{C}): Unit =
55-
f.read() // ok
56-
g.read() // ok
57-
parReduce(1 to 1000): (a, b) =>
58-
a * b * f.read() + g.read() // ok
59-
parReduce(1 to 1000): (a, b) => // error
60-
f.write(42) // the error stems from here
61-
a + b + f.read() + g.read() // ok
62-
parReduce(1 to 1000): (a, b) => // error
63-
g.write(42) // the error stems from here
64-
0
65-
f.write(42) // ok, unrestricted access to file
66-
g.write(42) // ok, unrestricted access to file
47+
withFile("foo.txt"): f =>
48+
withFile("bar.txt"): g =>
49+
f.read() // ok
50+
g.read() // ok
51+
parReduce(1 to 1000): (a, b) =>
52+
a * b * f.read() + g.read() // ok
53+
parReduce(1 to 1000): (a, b) => // error
54+
f.write(42) // the error stems from here
55+
a + b + f.read() + g.read() // ok
56+
parReduce(1 to 1000): (a, b) => // error
57+
g.write(42) // the error stems from here
58+
0
59+
f.write(42) // ok, unrestricted access to file
60+
g.write(42) // ok, unrestricted access to file
6761

0 commit comments

Comments
 (0)