Skip to content

Commit 4e04b19

Browse files
committed
Don't flag local fresh capabilities as errors in markFree
1 parent c658e3c commit 4e04b19

18 files changed

+56
-73
lines changed

Diff for: compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

+9-3
Original file line numberDiff line numberDiff line change
@@ -486,9 +486,15 @@ class CheckCaptures extends Recheck, SymTransformer:
486486
// The path-use.scala neg test contains an example.
487487
val underlying = CaptureSet.ofTypeDeeply(c1.widen)
488488
capt.println(i"Widen reach $c to $underlying in ${env.owner}")
489-
underlying.disallowRootCapability: () =>
490-
report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", tree.srcPos)
491-
recur(underlying, env, null)
489+
if ccConfig.useSepChecks then
490+
recur(underlying.filter(!_.isMaxCapability), env, null)
491+
// we don't want to disallow underlying Fresh.Cap, since these are typically locally created
492+
// fresh capabilities. We don't need to also follow the hidden set since separation
493+
// checking makes ure that locally hidden references need to go to @consume parameters.
494+
else
495+
underlying.disallowRootCapability: () =>
496+
report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", tree.srcPos)
497+
recur(underlying, env, null)
492498
case c: TypeRef if c.isParamPath =>
493499
checkUseDeclared(c, env, null)
494500
case _ =>

Diff for: tests/neg-custom-args/captures/delayedRunops.check

-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
| ^^^^
44
| reference ops* is not included in the allowed capture set {}
55
| of an enclosing function literal with expected type () -> Unit
6-
-- Error: tests/neg-custom-args/captures/delayedRunops.scala:23:13 -----------------------------------------------------
7-
23 | runOps(ops1) // error
8-
| ^^^^
9-
| Local reach capability ops1* leaks into capture scope of enclosing function
106
-- Error: tests/neg-custom-args/captures/delayedRunops.scala:29:13 -----------------------------------------------------
117
29 | runOps(ops1) // error
128
| ^^^^

Diff for: tests/neg-custom-args/captures/delayedRunops.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import caps.{use, consume}
2020
def delayedRunOps2(@consume ops: List[() => Unit]): () ->{} Unit =
2121
() =>
2222
val ops1: List[() => Unit] = ops // error
23-
runOps(ops1) // error
23+
runOps(ops1) // was error
2424

2525
// unsound: impure operation pretended pure
2626
def delayedRunOps3(ops: List[() => Unit]): () ->{} Unit =

Diff for: tests/neg-custom-args/captures/i21401.check

-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,3 @@
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^
2424
|Type variable X of value leaked cannot be instantiated to Boxed[box IO^] -> (ex$20: caps.Exists) -> Boxed[box IO^{ex$20}] since
2525
|the part box IO^{ex$20} of that type captures the root capability `cap`.
26-
-- Error: tests/neg-custom-args/captures/i21401.scala:18:21 ------------------------------------------------------------
27-
18 | val y: IO^{x*} = x.unbox // error
28-
| ^^^^^^^
29-
| Local reach capability x* leaks into capture scope of method test2

Diff for: tests/neg-custom-args/captures/i21401.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ def test2() =
1515
val a = usingIO[IO^](x => x) // error
1616
val leaked: [R, X <: Boxed[IO^] -> R] -> (op: X) -> R = usingIO[Res](mkRes) // error
1717
val x: Boxed[IO^] = leaked[Boxed[IO^], Boxed[IO^] -> Boxed[IO^]](x => x) // error // error
18-
val y: IO^{x*} = x.unbox // error
18+
val y: IO^{x*} = x.unbox // was error
1919
y.println("boom")

Diff for: tests/neg-custom-args/captures/i21442.check

-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
| ^^^^^^^
44
| Local reach capability x* leaks into capture scope of method foo.
55
| To allow this, the parameter x should be declared with a @use annotation
6-
-- Error: tests/neg-custom-args/captures/i21442.scala:18:14 ------------------------------------------------------------
7-
18 | val io = x1.unbox // error
8-
| ^^^^^^^^
9-
| Local reach capability x1* leaks into capture scope of method bar
106
-- Error: tests/neg-custom-args/captures/i21442.scala:17:10 ------------------------------------------------------------
117
17 | val x1: Boxed[IO^] = x // error
128
| ^^^^^^^^^^

Diff for: tests/neg-custom-args/captures/i21442.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ def foo(x: Boxed[IO^]): Unit =
1515
// But, no type error reported.
1616
def bar(x: Boxed[IO^]): Unit =
1717
val x1: Boxed[IO^] = x // error
18-
val io = x1.unbox // error
18+
val io = x1.unbox // was error
1919
io.use()

Diff for: tests/neg-custom-args/captures/leak-problem.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test(): Unit =
2525
def useBoxedAsync1(@use x: Box[Async^]): Unit = x.get.read()
2626

2727
val xs: Box[Async^] = ???
28-
val xsLambda = () => useBoxedAsync(xs) // error
28+
val xsLambda = () => useBoxedAsync(xs) // was error now ok
2929
val _: () ->{xs*} Unit = xsLambda
3030
val _: () -> Unit = xsLambda // error
3131

Diff for: tests/neg-custom-args/captures/path-use.check

-4
This file was deleted.

Diff for: tests/neg-custom-args/captures/path-use.scala

-25
This file was deleted.

Diff for: tests/neg-custom-args/captures/reaches.check

-4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@
4444
| ^
4545
| Type variable A of constructor Id cannot be instantiated to box () => Unit since
4646
| that type captures the root capability `cap`.
47-
-- Error: tests/neg-custom-args/captures/reaches.scala:56:6 ------------------------------------------------------------
48-
56 | id(() => f.write()) // error
49-
| ^^^^^^^^^^^^^^^^^^^
50-
| Local reach capability id* leaks into capture scope of method test
5147
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:63:27 --------------------------------------
5248
63 | val f1: File^{id*} = id(f) // error, since now id(f): File^ // error
5349
| ^^^^^

Diff for: tests/neg-custom-args/captures/reaches.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Id[-A, +B >: A]():
5353
def test =
5454
val id: Id[Proc, Proc] = new Id[Proc, () -> Unit] // error
5555
usingFile: f =>
56-
id(() => f.write()) // error
56+
id(() => f.write()) // was error
5757

5858
def attack2 =
5959
val id: File^ -> File^ = x => x

Diff for: tests/neg-custom-args/captures/unsound-reach-4.check

-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
| Required: Foo[box File^]
1111
|
1212
| longer explanation available when compiling with `-explain`
13-
-- Error: tests/neg-custom-args/captures/unsound-reach-4.scala:25:22 ---------------------------------------------------
14-
25 | escaped = boom.use(f) // error
15-
| ^^^^^^^^^^^
16-
| Local reach capability backdoor* leaks into capture scope of method bad
1713
-- [E164] Declaration Error: tests/neg-custom-args/captures/unsound-reach-4.scala:17:6 ---------------------------------
1814
17 | def use(@consume x: F): File^ = x // error @consume override
1915
| ^

Diff for: tests/neg-custom-args/captures/unsound-reach-4.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ def bad(): Unit =
2222

2323
var escaped: File^{backdoor*} = null
2424
withFile("hello.txt"): f =>
25-
escaped = boom.use(f) // error
25+
escaped = boom.use(f) // was error

Diff for: tests/neg-custom-args/captures/unsound-reach.check

-5
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,3 @@
1515
| Required: Foo[box File^]
1616
|
1717
| longer explanation available when compiling with `-explain`
18-
-- Error: tests/neg-custom-args/captures/unsound-reach.scala:23:21 -----------------------------------------------------
19-
23 | boom.use(f): (f1: File^{backdoor*}) => // error
20-
| ^
21-
| Local reach capability backdoor* leaks into capture scope of method bad
22-
24 | escaped = f1

Diff for: tests/neg-custom-args/captures/unsound-reach.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ def bad(): Unit =
2020

2121
var escaped: File^{backdoor*} = null
2222
withFile("hello.txt"): f =>
23-
boom.use(f): (f1: File^{backdoor*}) => // error
23+
boom.use(f): (f1: File^{backdoor*}) => // was error
2424
escaped = f1
2525

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import caps.Mutable
2+
import caps.cap
3+
4+
class Ref extends Mutable:
5+
var x = 0
6+
def get: Int = x
7+
mut def put(y: Int): Unit = x = y
8+
9+
case class Pair[+X, +Y](val fst: X, val snd: Y)
10+
11+
def twoRefs(): Pair[Ref^, Ref^] =
12+
val r1 = Ref()
13+
val r2 = Ref()
14+
Pair(r1, r2)
15+
16+
def twoRefsBad(): Pair[Ref^, Ref^] =
17+
Pair(Ref(), Ref()) // error: universal capability cannot be included in capture set
18+
// even though this is morally equivalent to `twoRefs`
19+
20+
21+
def test(io: Object^): Unit =
22+
val two = twoRefs()
23+
val fst = two.fst // error: local reach capability two* leaks into test
24+
// first, the leakage makes no sense
25+
// second, the capture should be two.fst, not two*
26+
val snd = two.snd
27+
val three: Pair[Ref^{io}, Ref^{io}] = ???
28+
val bad = three.fst

Diff for: tests/pos-custom-args/captures/path-use.scala

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import language.experimental.namedTuples
2-
import caps.use
32

43
class IO
54

@@ -9,14 +8,18 @@ class C(val f: IO^):
98
type Proc = () => Unit
109

1110
def test(io: IO^) =
12-
def test1(@use c: C { val f: IO^{io}}^{io}) =
13-
val f = () => println(c.f)
14-
val _: () ->{c.f} Unit = f
11+
val c = C(io)
12+
val f = () => println(c.f)
13+
val _: () ->{c.f} Unit = f
1514

16-
val x = c.procs
17-
val _: List[() ->{c.procs*} Unit] = x
15+
val x = c.procs
16+
val _: List[() ->{c.procs*} Unit] = x
1817

19-
val g = () => println(c.procs.head)
20-
val _: () ->{c.procs*} Unit = g
21-
test1(C(io))
18+
val g = () => println(c.procs.head) // was error, local reach capability c.procs* leaks
19+
val _: () ->{c.procs*} Unit = g
2220

21+
val cc: C { val f: IO^{io}; val procs: List[() ->{io} Unit] }^{io} =
22+
???
23+
24+
val gg = () => println(cc.procs.head) // OK, since cc.procs* has {io} as underlying capture set
25+
val _: () ->{io} Unit = gg

0 commit comments

Comments
 (0)