@@ -402,15 +402,16 @@ class CheckCaptures extends Recheck, SymTransformer:
402
402
&& (! ccConfig.useSealed || refSym.is(Param ))
403
403
&& refOwner == env.owner
404
404
then
405
- if refSym.hasAnnotation(defn.UnboxAnnot )
406
- || ref.info.hasAnnotation(defn.UseAnnot )
407
- || c.isUnderUse
408
- then
405
+ if ref.info.hasAnnotation(defn.UseAnnot )|| c.isUnderUse then
409
406
capt.println(i " exempt: $ref in $refOwner" )
410
407
else
411
408
// Reach capabilities that go out of scope have to be approximated
412
409
// by their underlying capture set, which cannot be universal.
413
- // Reach capabilities of @unboxed parameters are exempted.
410
+ // Reach capabilities are exempted if
411
+ // - they are under-use capabilties that were generated from a cap
412
+ // appearing under a @use, or
413
+ // - their reference has a type thar carries a @use annotation. In that
414
+ // case callers will charge the deep capture set of the argument.
414
415
val cs = CaptureSet .ofInfo(c)
415
416
cs.disallowRootCapability: () =>
416
417
def kind = if c.isReach then " reach capability" else " capture set variable"
@@ -428,48 +429,14 @@ class CheckCaptures extends Recheck, SymTransformer:
428
429
end markFree
429
430
430
431
/** Include references captured by the called method in the current environment stack */
431
- def includeCallCaptures (sym : Symbol , pos : SrcPos )(using Context ): Unit =
432
- if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), pos)
433
-
434
- private val prefixCalls = util.EqHashSet [GenericApply ]()
435
- private val unboxedArgs = util.EqHashSet [Tree ]()
436
-
437
- def handleCall (meth : Symbol , call : GenericApply , eval : () => Type )(using Context ): Type =
438
- if prefixCalls.remove(call) then return eval()
439
-
440
- val unboxedParamNames =
441
- meth.rawParamss.flatMap: params =>
442
- params.collect:
443
- case param if param.hasAnnotation(defn.UnboxAnnot ) =>
444
- param.name
445
- .toSet
446
-
447
- def markUnboxedArgs (call : GenericApply ): Unit = call.fun.tpe.widen match
448
- case MethodType (pnames) =>
449
- for (pname, arg) <- pnames.lazyZip(call.args) do
450
- if unboxedParamNames.contains(pname) then
451
- unboxedArgs.add(arg)
452
- case _ =>
453
-
454
- def markPrefixCalls (tree : Tree ): Unit = tree match
455
- case tree : GenericApply =>
456
- prefixCalls.add(tree)
457
- markUnboxedArgs(tree)
458
- markPrefixCalls(tree.fun)
459
- case _ =>
460
-
461
- markUnboxedArgs(call)
462
- markPrefixCalls(call.fun)
463
- val res = eval()
464
- includeCallCaptures(meth, call.srcPos)
465
- res
466
- end handleCall
432
+ def includeCallCaptures (sym : Symbol , resType : Type , pos : SrcPos )(using Context ): Unit = resType match
433
+ case _ : MethodOrPoly => // wait until method is fully applied
434
+ case _ =>
435
+ if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), pos)
467
436
468
437
override def recheckIdent (tree : Ident , pt : Type )(using Context ): Type =
469
438
if tree.symbol.is(Method ) then
470
- if tree.symbol.info.isParameterless then
471
- // there won't be an apply; need to include call captures now
472
- includeCallCaptures(tree.symbol, tree.srcPos)
439
+ includeCallCaptures(tree.symbol, tree.symbol.info, tree.srcPos)
473
440
else if ! tree.symbol.isStatic then
474
441
// debugShowEnvs()
475
442
def addSelects (ref : TermRef , pt : Type ): TermRef = pt match
@@ -574,16 +541,15 @@ class CheckCaptures extends Recheck, SymTransformer:
574
541
tp.derivedCapturingType(forceBox(parent), refs)
575
542
mapArgUsing(forceBox)
576
543
else
577
- handleCall(meth, tree, () => super .recheckApply(tree, pt))
544
+ val res = super .recheckApply(tree, pt)
545
+ includeCallCaptures(meth, res, tree.srcPos)
546
+ res
578
547
end recheckApply
579
548
580
549
protected override
581
550
def recheckArg (arg : Tree , formal : Type )(using Context ): Type =
582
551
val argType = recheck(arg, formal)
583
552
accountForUses(arg, argType, formal)
584
- if unboxedArgs.contains(arg) then
585
- capt.println(i " charging deep capture set of $arg: ${argType} = ${argType.deepCaptureSet}" )
586
- markFree(argType.deepCaptureSet, arg.srcPos)
587
553
argType
588
554
589
555
class MapUses (deep : Boolean )(using Context ) extends TypeMap :
@@ -620,27 +586,18 @@ class CheckCaptures extends Recheck, SymTransformer:
620
586
* ---------------------
621
587
* E |- f(a): Tr^C
622
588
*
623
- * If the function `f` does not have an `@unboxed` parameter, then
624
- * any unboxing it does would be charged to the environment of the function
625
- * so they have to appear in Cq. Since any capabilities of the result of the
626
- * application must already be present in the application, an upper
627
- * approximation of the result capture set is Cq \union Ca, where `Ca`
628
- * is the capture set of the argument.
629
- * If the function `f` does have an `@unboxed` parameter, then it could in addition
630
- * unbox reach capabilities over its formal parameter. Therefore, the approximation
631
- * would be `Cq \union dcs(Ca)` instead.
589
+ * If the type of the function `f` does not mention any formal parameters
590
+ * any capabilities of the result of the application must already be present in
591
+ * the application. So an upper approximation of the result capture set is Cq \union Ca,
592
+ * where `Ca` is the capture set of the argument.
632
593
* If the approximation is known to subcapture the declared result Cr, we pick it for C
633
594
* otherwise we pick Cr.
634
595
*/
635
596
protected override
636
597
def recheckApplication (tree : Apply , qualType : Type , funType : MethodType , argTypes : List [Type ])(using Context ): Type =
637
598
val appType = Existential .toCap(super .recheckApplication(tree, qualType, funType, argTypes))
638
599
val qualCaptures = qualType.captureSet
639
- val argCaptures =
640
- for (arg, argType) <- tree.args.lazyZip(argTypes) yield
641
- if unboxedArgs.remove(arg) // need to ensure the remove happens, that's why argCaptures is computed even if not needed.
642
- then argType.deepCaptureSet
643
- else argType.captureSet
600
+ val argCaptures = argTypes.map(_.captureSet)
644
601
appType match
645
602
case appType @ CapturingType (appType1, refs)
646
603
if qualType.exists
@@ -735,8 +692,10 @@ class CheckCaptures extends Recheck, SymTransformer:
735
692
i " Sealed type variable $pname" , " be instantiated to" ,
736
693
i " This is often caused by a local capability $where\n leaking as part of its result. " ,
737
694
tree.srcPos)
738
- try handleCall(meth, tree, () => Existential .toCap(super .recheckTypeApply(tree, pt)))
739
- finally checkContains(tree)
695
+ val res = Existential .toCap(super .recheckTypeApply(tree, pt))
696
+ includeCallCaptures(meth, res, tree.srcPos)
697
+ checkContains(tree)
698
+ res
740
699
end recheckTypeApply
741
700
742
701
/** Faced with a tree of form `caps.contansImpl[CS, r.type]`, check that `R` is a tracked
@@ -1423,21 +1382,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1423
1382
! setup.isPreCC(overriding) && ! setup.isPreCC(overridden)
1424
1383
1425
1384
override def checkInheritedTraitParameters : Boolean = false
1426
-
1427
- /** Check that overrides don't change the @unbox status of their parameters */
1428
- override def additionalChecks (member : Symbol , other : Symbol )(using Context ): Unit =
1429
- for
1430
- (params1, params2) <- member.rawParamss.lazyZip(other.rawParamss)
1431
- (param1, param2) <- params1.lazyZip(params2)
1432
- do
1433
- if param1.hasAnnotation(defn.UnboxAnnot ) != param2.hasAnnotation(defn.UnboxAnnot ) then
1434
- report.error(
1435
- OverrideError (
1436
- i " has a parameter ${param1.name} with different @unbox status than the corresponding parameter in the overridden definition " ,
1437
- self, member, other, self.memberInfo(member), self.memberInfo(other)
1438
- ),
1439
- if member.owner == clazz then member.srcPos else clazz.srcPos
1440
- )
1441
1385
end OverridingPairsCheckerCC
1442
1386
1443
1387
def traverse (t : Tree )(using Context ) =
0 commit comments