Skip to content

Commit 6d9dbf6

Browse files
committed
Tighten subsumption checking of Fresh instances
Fresh instances cannot subsume TermParamRefs since that would be a level violation.
1 parent d8a8084 commit 6d9dbf6

File tree

16 files changed

+85
-16
lines changed

16 files changed

+85
-16
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,11 @@ trait CaptureRef extends TypeProxy, ValueType:
256256
|| this.match
257257
case root.Fresh(hidden) =>
258258
vs.ifNotSeen(this)(hidden.elems.exists(_.subsumes(y)))
259-
|| !y.stripReadOnly.isCap && !yIsExistential && canAddHidden && vs.addHidden(hidden, y)
259+
|| !y.stripReadOnly.isCap
260+
&& !yIsExistential
261+
&& !y.isInstanceOf[TermParamRef]
262+
&& canAddHidden
263+
&& vs.addHidden(hidden, y)
260264
case x @ root.Result(binder) =>
261265
val result = y match
262266
case y @ root.Result(_) => vs.unify(x, y)

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)) => R)(handl
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] { // error // error
2424
(x: CanThrow[Exception]) => () => raise(new Exception)(using x)
2525
} {
2626
(ex: Exception) => ???

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
10+
f.withSession[Session^](t => t) // error // error
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i16226.scala:13:4 ----------------------------------------
2+
13 | (ref1, f1) => map[A, B](ref1, f1) // error
3+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
| Found: (ref1: LazyRef[box A^?]{val elem: () ->{cap, fresh} A^?}^{io}, f1: (x$0: A^?) => B^?) ->?
5+
| LazyRef[box B^?]{val elem: () ->{localcap} B^?}^{f1, ref1}
6+
| Required: (ref1: LazyRef[A]^{io}, f1: A => B) ->{fresh} LazyRef[B]^{fresh}
7+
|
8+
| longer explanation available when compiling with `-explain`
9+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i16226.scala:15:4 ----------------------------------------
10+
15 | (ref1, f1) => map[A, B](ref1, f1) // error
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
| Found: (ref1: LazyRef[box A^?]{val elem: () ->{cap, fresh} A^?}^{io}, f1: (x$0: A^?) => B^?) ->?
13+
| LazyRef[box B^?]{val elem: () ->{localcap} B^?}^{f1, ref1}
14+
| Required: (ref: LazyRef[A]^{io}, f: A => B) ->{fresh} LazyRef[B]^{localcap}
15+
|
16+
| Note that the existential capture root in LazyRef[B]^
17+
| cannot subsume the capability f1.type since that capability is not a SharedCapability
18+
|
19+
| longer explanation available when compiling with `-explain`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Cap extends caps.Capability
2+
3+
class LazyRef[T](val elem: () => T):
4+
val get: () ->{elem} T = elem
5+
def map[U](f: T => U): LazyRef[U]^{f, this} =
6+
new LazyRef(() => f(elem()))
7+
8+
def map[A, B](ref: LazyRef[A]^, f: A => B): LazyRef[B]^{f, ref} =
9+
new LazyRef(() => f(ref.elem()))
10+
11+
def main(io: Cap) = {
12+
def mapc[A, B]: (LazyRef[A]^{io}, A => B) => LazyRef[B]^ =
13+
(ref1, f1) => map[A, B](ref1, f1) // error
14+
def mapd[A, B]: (ref: LazyRef[A]^{io}, f: A => B) => LazyRef[B]^ =
15+
(ref1, f1) => map[A, B](ref1, f1) // error
16+
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44
| Type variable T of object Boxed cannot be instantiated to box IO^ since
55
| that type captures the root capability `cap`.
66
-- Error: tests/neg-custom-args/captures/i21401.scala:15:18 ------------------------------------------------------------
7-
15 | val a = usingIO[IO^](x => x) // error
7+
15 | val a = usingIO[IO^](x => x) // error // error
88
| ^^^
99
| Type variable R of method usingIO cannot be instantiated to box IO^ since
1010
| that type captures the root capability `cap`.
11+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i21401.scala:15:23 ---------------------------------------
12+
15 | val a = usingIO[IO^](x => x) // error // error
13+
| ^^^^^^
14+
| Found: (x: IO^) ->? box IO^{x}
15+
| Required: (x: IO^) ->{fresh} box IO^{fresh}
16+
|
17+
| longer explanation available when compiling with `-explain`
1118
-- Error: tests/neg-custom-args/captures/i21401.scala:16:66 ------------------------------------------------------------
1219
16 | val leaked: [R, X <: Boxed[IO^] -> R] -> (op: X) -> R = usingIO[Res](mkRes) // error
1320
| ^^^

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def mkRes(x: IO^): Res =
1212
val op1: Boxed[IO^] -> R = op
1313
op1(Boxed[IO^](x)) // error
1414
def test2() =
15-
val a = usingIO[IO^](x => x) // error
15+
val a = usingIO[IO^](x => x) // error // 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
1818
val y: IO^{x*} = x.unbox // was error

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@
4444
| ^
4545
| Type variable A of constructor Id cannot be instantiated to box () => Unit since
4646
| that type captures the root capability `cap`.
47+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:59:27 --------------------------------------
48+
59 | val id: File^ -> File^ = x => x // error
49+
| ^^^^^^
50+
| Found: (x: File^) ->? File^{x}
51+
| Required: (x: File^) -> File^{fresh}
52+
|
53+
| longer explanation available when compiling with `-explain`
4754
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:62:38 --------------------------------------
4855
62 | val leaked = usingFile[File^{id*}]: f => // error // error
4956
| ^

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def test =
5656
id(() => f.write()) // was error
5757

5858
def attack2 =
59-
val id: File^ -> File^ = x => x
59+
val id: File^ -> File^ = x => x // error
6060
// val id: File^ -> File^{fresh}
6161

6262
val leaked = usingFile[File^{id*}]: f => // error // error

tests/neg-custom-args/captures/refine-reach-shallow.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import language.experimental.captureChecking
22
trait IO
33
def test1(): Unit =
4-
val f: IO^ => IO^ = x => x
4+
val f: IO^ => IO^ = x => x // error
55
val g: IO^ => IO^{f*} = f // error
66
def test2(): Unit =
77
val f: [R] -> (IO^ => R) -> R = ???

0 commit comments

Comments
 (0)