Skip to content

Commit 618bbc5

Browse files
committed
Handle local type parameters in markFree
These need to be handled like reach capabilities. Fixes #21347
1 parent 02b1b6d commit 618bbc5

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

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

+16-14
Original file line numberDiff line numberDiff line change
@@ -388,23 +388,25 @@ class CheckCaptures extends Recheck, SymTransformer:
388388
// should be included.
389389
val included = cs.filter: c =>
390390
c.stripReach match
391-
case ref: TermRef =>
392-
//if c.isReach then println(i"REACH $c in ${env.owner}")
393-
//assert(!env.owner.isAnonymousFunction)
391+
case ref: NamedType =>
394392
val refSym = ref.symbol
395393
val refOwner = refSym.owner
396394
val isVisible = isVisibleFromEnv(refOwner)
397-
if !isVisible && c.isReach && refSym.is(Param) && refOwner == env.owner then
398-
if refSym.hasAnnotation(defn.UnboxAnnot) then
399-
capt.println(i"exempt: $ref in $refOwner")
400-
else
401-
// Reach capabilities that go out of scope have to be approximated
402-
// by their underlying capture set, which cannot be universal.
403-
// Reach capabilities of @unboxed parameters are exempted.
404-
val cs = CaptureSet.ofInfo(c)
405-
cs.disallowRootCapability: () =>
406-
report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", pos)
407-
checkSubset(cs, env.captured, pos, provenance(env))
395+
if !isVisible
396+
&& (c.isReach || ref.isType)
397+
&& refSym.is(Param)
398+
&& refOwner == env.owner
399+
then
400+
if refSym.hasAnnotation(defn.UnboxAnnot) then
401+
capt.println(i"exempt: $ref in $refOwner")
402+
else
403+
// Reach capabilities that go out of scope have to be approximated
404+
// by their underlying capture set, which cannot be universal.
405+
// Reach capabilities of @unboxed parameters are exempted.
406+
val cs = CaptureSet.ofInfo(c)
407+
cs.disallowRootCapability: () =>
408+
report.error(em"Local reach capability $c leaks into capture scope of ${env.ownerString}", pos)
409+
checkSubset(cs, env.captured, pos, provenance(env))
408410
isVisible
409411
case ref: ThisType => isVisibleFromEnv(ref.cls)
410412
case _ => false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- Error: tests/neg-custom-args/captures/i21347.scala:4:15 -------------------------------------------------------------
2+
4 | ops.foreach: op => // error
3+
| ^
4+
| Local reach capability C leaks into capture scope of method runOps
5+
5 | op()
6+
-- Error: tests/neg-custom-args/captures/i21347.scala:8:14 -------------------------------------------------------------
7+
8 | () => runOps(f :: Nil) // error
8+
| ^^^^^^^^^^^^^^^^
9+
| reference (caps.cap : caps.Capability) is not included in the allowed capture set {}
10+
| of an enclosing function literal with expected type () -> Unit
11+
-- Error: tests/neg-custom-args/captures/i21347.scala:11:15 ------------------------------------------------------------
12+
11 | ops.foreach: op => // error
13+
| ^
14+
| Local reach capability ops* leaks into capture scope of method runOpsAlt
15+
12 | op()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import language.experimental.captureChecking
2+
3+
def runOps[C^](ops: List[() ->{C^} Unit]): Unit =
4+
ops.foreach: op => // error
5+
op()
6+
7+
def boom(f: () => Unit): () -> Unit =
8+
() => runOps(f :: Nil) // error
9+
10+
def runOpsAlt(ops: List[() => Unit]): Unit =
11+
ops.foreach: op => // error
12+
op()

0 commit comments

Comments
 (0)