Skip to content

Commit c1036bf

Browse files
committed
Fix captureSet computations for false reach capabilities
Fix the capture set computation of a type T @reachCapability where T is not a singleton captureRef. Such types can be the results of typemaps. The capture set in this case should be the deep capture set of T.
1 parent 7db1d43 commit c1036bf

File tree

6 files changed

+40
-11
lines changed

6 files changed

+40
-11
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ extension (tp: Type)
204204
case tp: TypeParamRef =>
205205
tp.derivesFrom(defn.Caps_CapSet)
206206
case AnnotatedType(parent, annot) =>
207-
annot.symbol == defn.ReachCapabilityAnnot
207+
(annot.symbol == defn.ReachCapabilityAnnot
208208
|| annot.symbol == defn.MaybeCapabilityAnnot
209+
) && parent.isTrackableRef
209210
case _ =>
210211
false
211212

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ object CaptureSet:
10571057
/** Capture set of a type */
10581058
def ofType(tp: Type, followResult: Boolean)(using Context): CaptureSet =
10591059
def recur(tp: Type): CaptureSet = trace(i"ofType $tp, ${tp.getClass} $followResult", show = true):
1060-
tp.dealias match
1060+
tp.dealiasKeepAnnots match
10611061
case tp: TermRef =>
10621062
tp.captureSet
10631063
case tp: TermParamRef =>
@@ -1068,6 +1068,12 @@ object CaptureSet:
10681068
empty
10691069
case CapturingType(parent, refs) =>
10701070
recur(parent) ++ refs
1071+
case tp @ AnnotatedType(parent, ann) if ann.hasSymbol(defn.ReachCapabilityAnnot) =>
1072+
parent match
1073+
case parent: SingletonCaptureRef if parent.isTrackableRef =>
1074+
tp.singletonCaptureSet
1075+
case _ =>
1076+
CaptureSet.deepCaptureSet(parent)
10711077
case tpd @ defn.RefinedFunctionOf(rinfo: MethodType) if followResult =>
10721078
ofType(tpd.parent, followResult = false) // pick up capture set from parent type
10731079
++ (recur(rinfo.resType) // add capture set of result
@@ -1083,7 +1089,7 @@ object CaptureSet:
10831089
case tparams @ (LambdaParam(tl, _) :: _) => cs.substParams(tl, args)
10841090
case _ => cs
10851091
case tp: TypeProxy =>
1086-
recur(tp.underlying)
1092+
recur(tp.superType)
10871093
case AndType(tp1, tp2) =>
10881094
recur(tp1) ** recur(tp2)
10891095
case OrType(tp1, tp2) =>

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import config.{Config, Feature}
2727

2828
import dotty.tools.dotc.util.SourcePosition
2929
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
30-
import cc.{CaptureSet, CapturingType, toCaptureSet, IllegalCaptureRef, isRetains}
30+
import cc.{CaptureSet, CapturingType, toCaptureSet, IllegalCaptureRef, isRetains, ReachCapability, MaybeCapability}
3131
import dotty.tools.dotc.parsing.JavaParsers
3232

3333
class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
@@ -330,7 +330,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
330330
"?" ~ (("(ignored: " ~ toText(ignored) ~ ")") provided printDebug)
331331
case tp @ PolyProto(targs, resType) =>
332332
"[applied to [" ~ toTextGlobal(targs, ", ") ~ "] returning " ~ toText(resType)
333-
case tp: AnnotatedType if tp.isReach || tp.isMaybe =>
333+
case ReachCapability(_) | MaybeCapability(_) =>
334334
toTextCaptureRef(tp)
335335
case _ =>
336336
super.toText(tp)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/leak-problem-2.scala:8:8 ---------------------------------
2+
8 | = race(Seq(src1, src2)) // error
3+
| ^^^^^^^^^^^^^^^^^^^^^
4+
| Found: Source[box T^?]^{src1, src2}
5+
| Required: Source[T]
6+
|
7+
| longer explanation available when compiling with `-explain`
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import language.experimental.captureChecking
2+
3+
trait Source[+T]
4+
5+
def race[T](@caps.unboxed sources: Seq[Source[T]^]): Source[T]^{sources*} = ???
6+
7+
def raceTwo[T](src1: Source[T]^, src2: Source[T]^): Source[T]^{}
8+
= race(Seq(src1, src2)) // error
9+
// this compiled and returned a Source that does not capture src1 and src2.

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
| ^^^^^^^^^^^^
2626
| The expression's type box () => Unit is not allowed to capture the root capability `cap`.
2727
| This usually means that a capability persists longer than its allowed lifetime.
28+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:53:2 ---------------------------------------
29+
53 | val id: Id[Proc, Proc] = new Id[Proc, () -> Unit] // error
30+
| ^
31+
| Found: box () => Unit
32+
| Required: () => Unit
33+
|
34+
| Note that box () => Unit cannot be box-converted to () => Unit
35+
| since at least one of their capture sets contains the root capability `cap`
36+
54 | usingFile: f =>
37+
55 | id(() => f.write())
38+
|
39+
| longer explanation available when compiling with `-explain`
2840
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:62:27 --------------------------------------
2941
62 | val f1: File^{id*} = id(f) // error, since now id(f): File^
3042
| ^^^^^
@@ -40,9 +52,3 @@
4052
79 | ps.map((x, y) => compose1(x, y)) // error // error
4153
| ^
4254
| Local reach capability ps* leaks into capture scope of method mapCompose
43-
-- [E057] Type Mismatch Error: tests/neg-custom-args/captures/reaches.scala:53:51 --------------------------------------
44-
53 | val id: Id[Proc, Proc] = new Id[Proc, () -> Unit] // error
45-
| ^
46-
| Type argument () -> Unit does not conform to lower bound () => Unit
47-
|
48-
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)