Skip to content

Commit 202e26e

Browse files
authored
Freshen all explicit arguments of type applications (#24354)
Map all `^`s in explicit type arguments of TypeApply's to fresh caps. Previously, we did not do that, which means that explicit arguments in TypeApply's could not contain `^`. This precaution should no longer be needed with level checking. Inferred arguments were already freshened before.
2 parents 0ff1734 + f778333 commit 202e26e

28 files changed

+214
-211
lines changed

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
167167
def mappedInfo =
168168
if toBeUpdated.contains(sym)
169169
then symd.info // don't transform symbols that will anyway be updated
170-
else transformExplicitType(symd.info, sym, freshen = true)
170+
else transformExplicitType(symd.info, sym)
171171
if Synthetics.needsTransform(symd) then
172172
Synthetics.transform(symd, mappedInfo)
173173
else if isPreCC(sym) then
@@ -349,7 +349,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
349349
* 5. Schedule deferred well-formed tests for types with retains annotations.
350350
* 6. Perform normalizeCaptures
351351
*/
352-
private def transformExplicitType(tp: Type, sym: Symbol, freshen: Boolean, tptToCheck: Tree = EmptyTree)(using Context): Type =
352+
private def transformExplicitType(tp: Type, sym: Symbol, tptToCheck: Tree = EmptyTree)(using Context): Type =
353353

354354
def fail(msg: Message) =
355355
if !tptToCheck.isEmpty then report.error(msg, tptToCheck.srcPos)
@@ -483,9 +483,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
483483
val tp3 =
484484
if sym.isType then stripImpliedCaptureSet(tp2)
485485
else tp2
486-
if freshen then
487-
capToFresh(tp3, Origin.InDecl(sym))
488-
else tp3
486+
capToFresh(tp3, Origin.InDecl(sym))
489487
end transformExplicitType
490488

491489
/** Update info of `sym` for CheckCaptures phase only */
@@ -516,7 +514,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
516514
var transformed =
517515
if tree.isInferred
518516
then transformInferredType(tree.tpe)
519-
else transformExplicitType(tree.tpe, sym, freshen = !boxed, tptToCheck = tree)
517+
else transformExplicitType(tree.tpe, sym, tptToCheck = tree)
520518
if boxed then transformed = transformed.boxDeeply
521519
tree.setNuType(
522520
if sym.hasAnnotation(defn.UncheckedCapturesAnnot) then makeUnchecked(transformed)
@@ -747,7 +745,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
747745

748746
// Compute new parent types
749747
val ps1 = inContext(ctx.withOwner(cls)):
750-
ps.mapConserve(transformExplicitType(_, NoSymbol, freshen = false))
748+
ps.mapConserve(transformExplicitType(_, NoSymbol))
751749

752750
// Install new types and if it is a module class also update module object
753751
if (selfInfo1 ne selfInfo) || (ps1 ne ps) then
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/hk-param.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** Concrete collection type: View */
22
trait View[+A] extends Itable[A], ILike[A, [X] =>> View[X]^]: // error
3-
override def fromIterable[B](c: Itable[B]^): View[B]^{c} = ???
3+
override def fromIterable[B](c: Itable[B]^): View[B]^{c} = ??? // error
44

55
trait IPolyTransforms[+A, +C[A]] extends Any:
66
def fromIterable[B](coll: Itable[B]^): C[B]

0 commit comments

Comments
 (0)