| 
1 | 1 | import language.experimental.captureChecking  | 
2 | 2 | import language.experimental.separationChecking  | 
 | 3 | +import language.experimental.erasedDefinitions  | 
 | 4 | + | 
3 | 5 | import caps.*  | 
4 | 6 | 
 
  | 
5 | 7 | // Test inspired by the "Gentrification Gone too Far?" paper  | 
6 | 8 | object Levels:  | 
7 | 9 | 
 
  | 
 | 10 | + /* User-defined capability classifiers */  | 
8 | 11 |  trait Read extends Classifier, SharedCapability  | 
9 | 12 |  trait ReadWrite extends Classifier, SharedCapability  | 
10 | 13 | 
 
  | 
11 | 14 |  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  | 
15 | 19 |  val read: () ->{r} Int  | 
16 | 20 |  val write: Int ->{rw} Unit  | 
17 | 21 | 
 
  | 
18 | 22 |  object File:  | 
19 | 23 |  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 {}  | 
22 | 26 |  val read = () =>  | 
23 | 27 |  println(s"Reading from $name with capability $r")  | 
24 | 28 |  42  | 
25 | 29 |  val write = (i: Int) =>  | 
26 | 30 |  println(s"Writing $i to $name with capability $rw")  | 
27 | 31 |  }  | 
28 | 32 | 
 
  | 
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  | 
34 | 34 |  def parReduce[U](xs: Seq[U])(op: (U, U) ->{cap.only[Read]} U): U = xs.reduce(op) // only Read-classified allowed  | 
35 | 35 | 
 
  | 
36 | 36 |  @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  | 
47 | 45 | 
 
  | 
48 | 46 |  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  | 
67 | 61 | 
 
  | 
0 commit comments