Skip to content

Commit bd324f6

Browse files
committed
Freshen all explicit arguments of type applications
Previously, we did not do that, which means that explicit arguments in TypeApply's could not contain `^`. This precaution shoul dnot longer be needed with level checking.
1 parent b1a5500 commit bd324f6

26 files changed

+201
-197
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
501501
var transformed =
502502
if tree.isInferred
503503
then transformInferredType(tree.tpe)
504-
else transformExplicitType(tree.tpe, sym, freshen = !boxed, tptToCheck = tree)
504+
else transformExplicitType(tree.tpe, sym, freshen = true, tptToCheck = tree)
505505
if boxed then transformed = transformed.boxDeeply
506506
tree.setNuType(
507507
if sym.hasAnnotation(defn.UncheckedCapturesAnnot) then makeUnchecked(transformed)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/boundary-homebrew.scala:19:19 ----------------------------
2+
19 | boundary[Int]: l2 ?=> // error
3+
| ^
4+
|Capability cap outlives its scope: it leaks into outer capture set 's1 of parameter l1.
5+
|The leakage occurred when trying to match the following types:
6+
|
7+
|Found: (l2: boundary.Label[Int]^'s2) ?->{l1} Int
8+
|Required: (boundary.Label[Int]^) ?=> Int
9+
|
10+
|where: ?=> refers to a fresh root capability created in anonymous function of type (using l1²: boundary.Label[boundary.Label[Int]^]^): boundary.Label[Int]^ when checking argument to parameter body of method apply
11+
| ^ refers to the universal root capability
12+
| cap is a fresh root capability created in anonymous function of type (using l2: boundary.Label[Int]^'s2): Int of parameter parameter l2² of method $anonfun
13+
20 | boundary.break(l2)(using l1)
14+
21 | 15
15+
|
16+
| longer explanation available when compiling with `-explain`
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
object boundary:
5+
class Label[-T]
6+
case class Break[T](private[boundary] label: Label[T]^{}, result: T) extends Throwable
7+
8+
def apply[T](body: Label[T]^ ?=> T): T =
9+
val label = Label()
10+
try
11+
body(using label)
12+
catch
13+
case Break[T @unchecked](l, res) if l eq label => res
14+
15+
def break[T](value: T)(using l: Label[T]) = throw Break(unsafe.unsafeAssumePure(l), value)
16+
17+
def test =
18+
boundary[boundary.Label[Int]^]: l1 ?=>
19+
boundary[Int]: l2 ?=> // error
20+
boundary.break(l2)(using l1)
21+
15
22+
???

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object test {
1111
f[Tree^](t) // error
1212
f[Tree](t) // error
1313
val c1 = C(t) // error
14-
val c2 = C[Tree^](t) // error
14+
val c2 = C[Tree^](t) // error // error
1515
val c3 = C[Tree](t) // error
1616

1717
val foo: C[Tree^] = ???

tests/neg-custom-args/captures/capt-test.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def handle[E <: Exception, R <: Top](op: (CT[E] @retains[caps.cap.type]) => R)(
2020
catch case ex: E => handler(ex)
2121

2222
def test: Unit =
23-
val b = handle[Exception, () => Nothing] { // error
23+
val b = handle[Exception, () => Nothing] {
2424
(x: CanThrow[Exception]) => () => raise(new Exception)(using x) // error
2525
} {
2626
(ex: Exception) => ???

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

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,46 +43,50 @@
4343
| Note that capability x is not included in capture set {}.
4444
|
4545
| longer explanation available when compiling with `-explain`
46-
-- Error: tests/neg-custom-args/captures/capt1.scala:36:16 -------------------------------------------------------------
47-
36 | val z2 = h[() -> Cap](() => x) // error // error
48-
| ^^^^^^^^^
49-
| Type variable X of method h cannot be instantiated to () -> C^ since
50-
| the part C^ of that type captures the root capability `cap`.
51-
|
52-
| where: ^ refers to the universal root capability
5346
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:36:24 ----------------------------------------
54-
36 | val z2 = h[() -> Cap](() => x) // error // error
47+
36 | val z2 = h[() -> Cap](() => x) // error
5548
| ^^^^^^^
56-
|Found: () ->'s2 C^
57-
|Required: () -> C^²
49+
| Found: () ->'s2 C^
50+
| Required: () -> C^²
5851
|
59-
|Note that capability cap is not included in capture set {cap²}
60-
|because cap is not visible from cap² in value z2.
52+
| Note that capability cap is not included in capture set {cap²}
53+
| because cap is not visible from cap² in value z2.
6154
|
62-
|where: ^ and cap refer to a root capability associated with the result type of (): C^
63-
| ^² and cap² refer to a fresh root capability created in value z2 when checking argument to parameter a of method h
55+
| where: ^ and cap refer to a root capability associated with the result type of (): C^
56+
| ^² and cap² refer to a fresh root capability created in value z2
6457
|
6558
| longer explanation available when compiling with `-explain`
6659
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:37:5 -----------------------------------------
6760
37 | (() => C()) // error
6861
| ^^^^^^^^^
69-
|Found: () ->'s3 C^
70-
|Required: () -> C^²
62+
| Found: () ->'s3 C^
63+
| Required: () -> C^²
7164
|
72-
|Note that capability cap is not included in capture set {cap²}
73-
|because cap is not visible from cap² in value z2.
65+
| Note that capability cap is not included in capture set {cap²}
66+
| because cap is not visible from cap² in value z2.
7467
|
75-
|where: ^ and cap refer to a root capability associated with the result type of (): C^
76-
| ^² and cap² refer to a fresh root capability created in value z2 when checking argument to parameter b of method h
68+
| where: ^ and cap refer to a root capability associated with the result type of (): C^
69+
| ^² and cap² refer to a fresh root capability created in value z2
7770
|
7871
| longer explanation available when compiling with `-explain`
79-
-- Error: tests/neg-custom-args/captures/capt1.scala:38:13 -------------------------------------------------------------
72+
-- Error: tests/neg-custom-args/captures/capt1.scala:38:51 -------------------------------------------------------------
8073
38 | val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error
81-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82-
| Type variable X of method h cannot be instantiated to () ->{x} C^ since
83-
| the part C^ of that type captures the root capability `cap`.
84-
|
85-
| where: ^ refers to the universal root capability
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
| Separation failure: Illegal access to {x} which is hidden by the previous definition
76+
| of value z2 with type () ->{} C^.
77+
| This type hides capabilities {cap, x}
78+
|
79+
| where: ^ refers to a fresh root capability in the type of value z2
80+
| cap is a fresh root capability created in value z2
81+
-- Error: tests/neg-custom-args/captures/capt1.scala:40:25 -------------------------------------------------------------
82+
40 | val z1: () => Cap = f1(x) // error
83+
| ^
84+
| Separation failure: Illegal access to {x} which is hidden by the previous definition
85+
| of value z3 with type () ->{x} C^.
86+
| This type hides capabilities {cap, x}
87+
|
88+
| where: ^ refers to a fresh root capability in the type of value z3
89+
| cap is a fresh root capability created in value z3
8690
-- Error: tests/neg-custom-args/captures/capt1.scala:43:7 --------------------------------------------------------------
8791
43 | if x == null then // error: separation
8892
| ^

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def foo() =
3333
val x: C @retains[caps.cap.type] = ???
3434
def h[X](a: X)(b: X) = a
3535

36-
val z2 = h[() -> Cap](() => x) // error // error
36+
val z2 = h[() -> Cap](() => x) // error
3737
(() => C()) // error
3838
val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error
3939

40-
val z1: () => Cap = f1(x)
40+
val z1: () => Cap = f1(x) // error
4141

4242
val z4 =
4343
if x == null then // error: separation

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
-- Error: tests/neg-custom-args/captures/class-level-attack.scala:12:24 ------------------------------------------------
2-
12 | val r: Ref[IO^] = Ref[IO^](io) // error:
3-
| ^^^
4-
| Type variable X of constructor Ref cannot be instantiated to IO^ since
5-
| that type captures the root capability `cap`.
6-
|
7-
| where: ^ refers to the universal root capability
81
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/class-level-attack.scala:17:26 ---------------------------
92
17 | def set(x: IO^) = r.put(x) // error
103
| ^

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Ref[X](init: X):
99
def put(y: X): Unit = x = y
1010

1111
class C(io: IO^):
12-
val r: Ref[IO^] = Ref[IO^](io) // error:
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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ class Foo:
77
def Test: Unit =
88
val f = new Foo
99
f.withSession(s => s).request // error
10-
f.withSession[Session^](t => t) // error // error
10+
f.withSession[Session^](t => t) // error

0 commit comments

Comments
 (0)