diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 5af57c31e05f..dbf01915122d 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -388,23 +388,25 @@ class CheckCaptures extends Recheck, SymTransformer: // should be included. val included = cs.filter: c => c.stripReach match - case ref: TermRef => - //if c.isReach then println(i"REACH $c in ${env.owner}") - //assert(!env.owner.isAnonymousFunction) + case ref: NamedType => val refSym = ref.symbol val refOwner = refSym.owner val isVisible = isVisibleFromEnv(refOwner) - if !isVisible && c.isReach && refSym.is(Param) && refOwner == env.owner then - if refSym.hasAnnotation(defn.UnboxAnnot) then - capt.println(i"exempt: $ref in $refOwner") - else - // Reach capabilities that go out of scope have to be approximated - // by their underlying capture set, which cannot be universal. - // Reach capabilities of @unboxed parameters are exempted. - val cs = CaptureSet.ofInfo(c) - cs.disallowRootCapability: () => - report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", pos) - checkSubset(cs, env.captured, pos, provenance(env)) + if !isVisible + && (c.isReach || ref.isType) + && refSym.is(Param) + && refOwner == env.owner + then + if refSym.hasAnnotation(defn.UnboxAnnot) then + capt.println(i"exempt: $ref in $refOwner") + else + // Reach capabilities that go out of scope have to be approximated + // by their underlying capture set, which cannot be universal. + // Reach capabilities of @unboxed parameters are exempted. + val cs = CaptureSet.ofInfo(c) + cs.disallowRootCapability: () => + report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", pos) + checkSubset(cs, env.captured, pos, provenance(env)) isVisible case ref: ThisType => isVisibleFromEnv(ref.cls) case _ => false diff --git a/tests/neg-custom-args/captures/i21347.check b/tests/neg-custom-args/captures/i21347.check new file mode 100644 index 000000000000..c680a54d3efc --- /dev/null +++ b/tests/neg-custom-args/captures/i21347.check @@ -0,0 +1,15 @@ +-- Error: tests/neg-custom-args/captures/i21347.scala:4:15 ------------------------------------------------------------- +4 | ops.foreach: op => // error + | ^ + | Local reach capability C leaks into capture scope of method runOps +5 | op() +-- Error: tests/neg-custom-args/captures/i21347.scala:8:14 ------------------------------------------------------------- +8 | () => runOps(f :: Nil) // error + | ^^^^^^^^^^^^^^^^ + | reference (caps.cap : caps.Capability) is not included in the allowed capture set {} + | of an enclosing function literal with expected type () -> Unit +-- Error: tests/neg-custom-args/captures/i21347.scala:11:15 ------------------------------------------------------------ +11 | ops.foreach: op => // error + | ^ + | Local reach capability ops* leaks into capture scope of method runOpsAlt +12 | op() diff --git a/tests/neg-custom-args/captures/i21347.scala b/tests/neg-custom-args/captures/i21347.scala new file mode 100644 index 000000000000..41887be6a78a --- /dev/null +++ b/tests/neg-custom-args/captures/i21347.scala @@ -0,0 +1,12 @@ +import language.experimental.captureChecking + +def runOps[C^](ops: List[() ->{C^} Unit]): Unit = + ops.foreach: op => // error + op() + +def boom(f: () => Unit): () -> Unit = + () => runOps(f :: Nil) // error + +def runOpsAlt(ops: List[() => Unit]): Unit = + ops.foreach: op => // error + op() \ No newline at end of file