Skip to content

Commit 67708cb

Browse files
committed
Tests for the new capture-variable syntax
1 parent ff068c6 commit 67708cb

19 files changed

+287
-1
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4086,7 +4086,7 @@ object Parsers {
40864086
* TypeDefRHS ::= Type
40874087
* | CaptureSet -- under captureChecking
40884088
*/
4089-
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = { // FIXME: ^-qualified members should automatically receive the CapSet interval!
4089+
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = {
40904090

40914091
def typeDefRHS(): Tree =
40924092
if Feature.ccEnabled && in.token == LBRACE && !isDclIntroNext then
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
5+
def main() =
6+
trait Channel[T] extends caps.Capability:
7+
def send(msg: T): Unit
8+
def recv(): T
9+
10+
trait Logger extends caps.Capability:
11+
def log(msg: String): Unit
12+
13+
// we can close over anything subsumed by the 'trusted' brand capability, but nothing else
14+
def runSecure[C >: {trusted} <: {trusted}](block: () ->{C} Unit): Unit = block()
15+
16+
// This is a 'brand" capability to mark what can be mentioned in trusted code
17+
object trusted extends caps.Capability
18+
19+
val trustedLogger: Logger^{trusted} = ???
20+
val trustedChannel: Channel[String]^{trusted} = ???
21+
22+
val untrustedLogger: Logger^ = ???
23+
val untrustedChannel: Channel[String]^ = ???
24+
25+
runSecure: () =>
26+
trustedLogger.log("Hello from trusted code") // ok
27+
28+
runSecure: () =>
29+
trustedChannel.send("I can send")
30+
trustedLogger.log(trustedChannel.recv()) // ok
31+
32+
runSecure: () =>
33+
"I am pure" // ok
34+
35+
runSecure: () => // error
36+
untrustedLogger.log("I can't be used here")
37+
38+
runSecure: () => // error
39+
untrustedChannel.send("I can't be used here")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
5+
def main() =
6+
trait Channel[T] extends caps.Capability:
7+
def send(msg: T): Unit
8+
def recv(): T
9+
10+
trait Logger extends caps.Capability:
11+
def log(msg: String): Unit
12+
13+
// we can close over anything subsumed by the 'trusted' brand capability, but nothing else
14+
def runSecure(block: () ->{trusted} Unit): Unit = block()
15+
16+
// This is a 'brand" capability to mark what can be mentioned in trusted code
17+
object trusted extends caps.Capability
18+
19+
val trustedLogger: Logger^{trusted} = ???
20+
val trustedChannel: Channel[String]^{trusted} = ???
21+
22+
val untrustedLogger: Logger^ = ???
23+
val untrustedChannel: Channel[String]^ = ???
24+
25+
runSecure: () =>
26+
trustedLogger.log("Hello from trusted code") // ok
27+
28+
runSecure: () =>
29+
trustedChannel.send("I can send")
30+
trustedLogger.log(trustedChannel.recv()) // ok
31+
32+
runSecure: () =>
33+
"I am pure" : Unit // ok
34+
35+
runSecure: () => // error
36+
untrustedLogger.log("I can't be used here")
37+
38+
runSecure: () => // error
39+
untrustedChannel.send("I can't be used here")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg-custom-args/captures/capset-members2.scala:5:9 -----------------------------------------------------
2+
5 | type C^[T] // error
3+
| ^
4+
| capture-set member declarations cannot have type parameters
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
trait Foo:
5+
type C^[T] // error
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E095] Syntax Error: tests/neg-custom-args/captures/capset-members3.scala:5:10 --------------------------------------
2+
5 | type C^ _ // error
3+
| ^
4+
| =, >:, or <: expected, but '_' found
5+
|
6+
| longer explanation available when compiling with `-explain`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
trait Foo:
5+
type C^ _ // error
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import language.experimental.captureChecking
2+
import language.experimental.modularity
3+
import caps.*
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
val z: Any^ = ???
9+
def onlyWithZ[C^](using c: Contains[C, z.type]) = ???
10+
11+
trait IncludesZ[C^]:
12+
val c: Contains[C, z.type]
13+
14+
trait Foo:
15+
type C >: {x} <: {x,y,z} : IncludesZ
16+
17+
val foo: Foo = ???
18+
/* new Foo {
19+
override given IncludesZ[C]: // FIXME: doesn't work yet
20+
val c: Contains[C, z.type] = summon
21+
cap type C = {x,z}
22+
} */
23+
onlyWithZ(using foo.C.c)
24+
onlyWithZ[{z}]
25+
onlyWithZ[{x,z}]
26+
onlyWithZ[{x,y,z}]
27+
onlyWithZ[{x,y}] // error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
trait Label extends Capability:
5+
type Fv^ // the capability set occurring freely in the `block` passed to `boundary` below.
6+
7+
def boundary[T, C^](block: Label{type Fv = {C} } ->{C} T): T = ??? // link label and block capture set
8+
def suspend[U](label: Label)[D^ <: {label.Fv}](handler: () ->{D} U): U = ??? // note the path
9+
10+
def test =
11+
val x = 1
12+
boundary: outer =>
13+
val y = 2
14+
boundary: inner =>
15+
val z = 3
16+
val w = suspend(outer) {() => z} // ok
17+
val v = suspend(inner) {() => y} // ok
18+
val u = suspend(inner): () =>
19+
suspend(outer) {() => y} // ok
20+
suspend(outer) {() => y} // ok
21+
y
22+
suspend(outer) { () => // error
23+
suspend(outer) {() => y }
24+
}
25+
suspend(outer): () => // error (leaks the inner label)
26+
println(inner)
27+
x + y + z
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
def foo[A >: {y} <: {x},
11+
B^,
12+
C^ <: {x},
13+
D^ : Ctx,
14+
E^ <: {C},
15+
F^ <: {C},
16+
G^ <: {x, y},
17+
H >: {x} <: {x,y} : Ctx, T, U]()[I^ <: {y, G, H},
18+
J^ <: {O.z},
19+
K^ <: {x, O.z},
20+
L^ <: {x, y, O.z},
21+
M^ >: {x, y, O.z} <: {C} : Ctx,
22+
N^ >: {x} <: {x},
23+
O^ >: {O.z} <: {O.z}] = ???
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import language.experimental.captureChecking
2+
3+
trait Bar:
4+
type C^
5+
6+
def useFoo[D^](x: Bar { type C = {D} } ): Any^{x.C} = ???
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
val bar = [C^, D <: {C}, E^ <: {C,x}, F >: {x,y} <: {C,E}] => (x: Int) => 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import language.experimental.captureChecking
2+
3+
trait Foo[U^, V^, W^]:
4+
type C = {caps.cap}
5+
type D = {caps.cap}
6+
type E >: {V,W} <: {U}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import language.experimental.captureChecking
2+
import language.experimental.namedTypeArguments
3+
4+
def test2 =
5+
val x: Any^ = ???
6+
def foo[A^, B^ >: {A}, T, U](x: Int) = 1
7+
foo[{x}, {x}, Int, String](0)
8+
foo[{}, {}, { def bar: Int }, { type D^ = {x} }](0)
9+
trait Foo { type D^ }
10+
foo[{}, {}, Foo, Foo](0)
11+
foo[A = {x}, B = {x}](0)
12+
foo[A = {x}](0)
13+
foo[T = Int](0)
14+
foo[T = Int, A = {x}](1)
15+
foo[A = {x}, T = Int](1)
16+
foo[B = {}, U = String, A = {}](1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
val baz = () => [C^, D^ <: {C}, E^ <: {C,x}, F^ >: {x,y} <: {C,E} : Ctx] => (x: Int) => 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
val baz2 = (i: Int) => [C^, D^ <: {C}, E^ <: {C,x}, F^ >: {x,y} <: {C,E} : Ctx] => (x: Int) => 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
val baz3 = (i: Int) => [C^, D^ <: {C}, E^ <: {C,x}] => () => [F^ >: {x,y} <: {C,E} : Ctx] => (x: Int) => 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
trait CaptureSet:
11+
type A^ >: {y} <: {x}
12+
type B^ = {x}
13+
type C^ <: {x}
14+
type D^ : Ctx
15+
type E^ <: {C}
16+
type F^ <: {C}
17+
type G^ <: {x, y}
18+
type H^ >: {x} <: {x,y} : Ctx
19+
type I^ = {y, G, H}
20+
type J^ = {O.z}
21+
type K^ = {x, O.z}
22+
type L^ <: {x, y, O.z}
23+
type M^ >: {x, y, O.z} <: {C}
24+
type N^ >: {x} <: {x}
25+
type O^ >: {O.z} <: {O.z}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import language.experimental.captureChecking
2+
3+
trait Ctx[T]
4+
5+
def test =
6+
val x: Any^ = ???
7+
val y: Any^ = ???
8+
object O:
9+
val z: Any^ = ???
10+
11+
abstract class Foo[A^, T]:
12+
type C^ <: {A}
13+
abstract class Bar extends Foo[{x,y,O.z}, String]:
14+
override type C^ <: {x,y}
15+
class Baz extends Bar:
16+
final override type C = {y}

0 commit comments

Comments
 (0)