@@ -388,23 +388,25 @@ class CheckCaptures extends Recheck, SymTransformer:
388
388
// should be included.
389
389
val included = cs.filter: c =>
390
390
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 =>
394
392
val refSym = ref.symbol
395
393
val refOwner = refSym.owner
396
394
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))
408
410
isVisible
409
411
case ref : ThisType => isVisibleFromEnv(ref.cls)
410
412
case _ => false
@@ -674,7 +676,29 @@ class CheckCaptures extends Recheck, SymTransformer:
674
676
i " Sealed type variable $pname" , " be instantiated to" ,
675
677
i " This is often caused by a local capability $where\n leaking as part of its result. " ,
676
678
tree.srcPos)
677
- handleCall(meth, tree, () => Existential .toCap(super .recheckTypeApply(tree, pt)))
679
+ val res = handleCall(meth, tree, () => Existential .toCap(super .recheckTypeApply(tree, pt)))
680
+ if meth == defn.Caps_containsImpl then checkContains(tree)
681
+ res
682
+ end recheckTypeApply
683
+
684
+ /** Faced with a tree of form `caps.contansImpl[CS, r.type]`, check that `R` is a tracked
685
+ * capability and assert that `{r} <:CS`.
686
+ */
687
+ def checkContains (tree : TypeApply )(using Context ): Unit =
688
+ tree.fun.knownType.widen match
689
+ case fntpe : PolyType =>
690
+ tree.args match
691
+ case csArg :: refArg :: Nil =>
692
+ val cs = csArg.knownType.captureSet
693
+ val ref = refArg.knownType
694
+ capt.println(i " check contains $cs , $ref" )
695
+ ref match
696
+ case ref : CaptureRef if ref.isTracked =>
697
+ checkElem(ref, cs, tree.srcPos)
698
+ case _ =>
699
+ report.error(em " $refArg is not a tracked capability " , refArg.srcPos)
700
+ case _ =>
701
+ case _ =>
678
702
679
703
override def recheckBlock (tree : Block , pt : Type )(using Context ): Type =
680
704
inNestedLevel(super .recheckBlock(tree, pt))
0 commit comments