Skip to content

Commit 44e235c

Browse files
committed
Two fixes to make tests pass as before
- Avoid creating capture sets of untrackable references - Refine disallowRootCapability to consider only explicit captures
1 parent e580166 commit 44e235c

File tree

8 files changed

+59
-21
lines changed

8 files changed

+59
-21
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,9 @@ object CaptureSet:
10371037

10381038
/** The capture set of the type underlying CaptureRef */
10391039
def ofInfo(ref: CaptureRef)(using Context): CaptureSet = ref match
1040-
case ref: (TermRef | TermParamRef) if ref.isMaxCapability => ref.singletonCaptureSet
1040+
case ref: (TermRef | TermParamRef) if ref.isMaxCapability =>
1041+
if ref.isTrackableRef then ref.singletonCaptureSet
1042+
else CaptureSet.universal
10411043
case ReachCapability(ref1) => deepCaptureSet(ref1.widen)
10421044
.showing(i"Deep capture set of $ref: ${ref1.widen} = $result", capt)
10431045
case _ => ofType(ref.underlying, followResult = true)

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,17 @@ object CheckCaptures:
157157
case _ =>
158158
case AnnotatedType(_, ann) if ann.symbol == defn.UncheckedCapturesAnnot =>
159159
()
160-
case t =>
160+
case CapturingType(parent, refs) =>
161161
if variance >= 0 then
162-
t.captureSet.disallowRootCapability: () =>
162+
refs.disallowRootCapability: () =>
163163
def part = if t eq tp then "" else i"the part $t of "
164164
report.error(
165165
em"""$what cannot $have $tp since
166166
|${part}that type captures the root capability `cap`.
167167
|$addendum""",
168168
pos)
169+
traverse(parent)
170+
case t =>
169171
traverseChildren(t)
170172
check.traverse(tp)
171173
end disallowRootCapabilitiesIn

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@
4949
34 | val z3 = h[(() -> Cap) @retains(x)](() => x)(() => C()) // error
5050
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
5151
| Sealed type variable X cannot be instantiated to box () ->{x} Cap since
52-
| the part C^ of that type captures the root capability `cap`.
52+
| the part Cap of that type captures the root capability `cap`.
5353
| This is often caused by a local capability in an argument of method h
5454
| leaking as part of its result.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ def useWrappedIO(wrapper: Wrapper[IO]): () -> Unit =
1010
wrapper: io =>
1111
io.brewCoffee()
1212
def main(): Unit =
13-
val escaped = usingIO(io => useWrappedIO(mk(io))) // error // error
13+
val escaped = usingIO(io => useWrappedIO(mk(io))) // error
1414
escaped() // boom
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import language.experimental.captureChecking
2+
import compiletime.uninitialized
3+
4+
object test1:
5+
class File:
6+
def write(x: String): Unit = ???
7+
8+
class Service(f: File^):
9+
def log = f.write("log")
10+
11+
def withFile[T](op: (f: File^) => T): T =
12+
op(new File)
13+
14+
def test =
15+
withFile: f =>
16+
val o = Service(f)
17+
o.log
18+
19+
object test2:
20+
class IO
21+
22+
class File:
23+
def write(x: String): Unit = ???
24+
25+
class Service(io: IO^):
26+
var file: File^{io} = uninitialized
27+
def log = file.write("log")
28+
29+
def withFile[T](io2: IO^)(op: (f: File^{io2}) => T): T =
30+
op(new File)
31+
32+
def test(io3: IO^) =
33+
withFile(io3): f =>
34+
val o = Service(io3)
35+
o.file = f
36+
o.log

tests/pos-custom-args/captures/filevar.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import language.experimental.captureChecking
2-
import language.experimental.modularity
3-
import annotation.capability
42
import compiletime.uninitialized
53

64
object test1:
@@ -19,19 +17,19 @@ object test1:
1917
o.log
2018

2119
object test2:
22-
class IO
20+
class IO extends caps.Capability
2321

2422
class File:
2523
def write(x: String): Unit = ???
2624

27-
class Service(io: IO^):
25+
class Service(io: IO):
2826
var file: File^{io} = uninitialized
2927
def log = file.write("log")
3028

31-
def withFile[T](io2: IO^)(op: (f: File^{io2}) => T): T =
29+
def withFile[T](io2: IO)(op: (f: File^{io2}) => T): T =
3230
op(new File)
3331

34-
def test(io3: IO^) =
32+
def test(io3: IO) =
3533
withFile(io3): f =>
3634
val o = Service(io3)
3735
o.file = f

tests/pos-custom-args/captures/logger.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import annotation.capability
22
import language.experimental.saferExceptions
33
import language.experimental.modularity
44

5-
class FileSystem // does not work with extends caps.Capability
5+
class FileSystem extends caps.Capability
66

7-
class Logger(using fs: FileSystem^):
7+
class Logger(using fs: FileSystem):
88
def log(s: String): Unit = ???
99

10-
def test(using fs: FileSystem^) =
10+
def test(using fs: FileSystem) =
1111
val l: Logger^{fs} = Logger(using fs)
1212
l.log("hello world!")
1313
val xs: LazyList[Int]^{l} =
@@ -50,7 +50,7 @@ class Pair[+A, +B](x: A, y: B):
5050
def fst: A = x
5151
def snd: B = y
5252

53-
def test2(ct: CanThrow[Exception], fs: FileSystem^) =
53+
def test2(ct: CanThrow[Exception], fs: FileSystem) =
5454
def x: Int ->{ct} String = ???
5555
def y: Logger^{fs} = ???
5656
def p = Pair[Int ->{ct} String, Logger^{fs}](x, y)

tests/pos-custom-args/captures/nested-classes.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ import language.experimental.captureChecking
22
import language.experimental.modularity
33
import annotation.{capability, constructorOnly}
44

5-
class IO // does not work with extends caps.Capability
5+
class IO extends caps.Capability
66
class Blah
7-
class Pkg(using io: IO^):
7+
class Pkg(using io: IO):
88
class Foo:
99
def m(foo: Blah^{io}) = ???
10-
class Pkg2(using io: IO^):
10+
class Pkg2(using io: IO):
1111
class Foo:
1212
def m(foo: Blah^{io}): Any = io; ???
1313

14-
def main(using io: IO^) =
14+
def main(using io: IO) =
1515
val pkg = Pkg()
1616
val f = pkg.Foo()
17-
f.m(???)
17+
val x1 = f.m(???)
1818
val pkg2 = Pkg2()
1919
val f2 = pkg2.Foo()
20-
f2.m(???)
20+
val x2 = f2.m(???)
2121

2222

0 commit comments

Comments
 (0)