Skip to content

Commit 5a35160

Browse files
committed
Tweak deep capture set computations
1 parent c1036bf commit 5a35160

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,20 @@ extension (tp: Type)
223223
case tp: SingletonCaptureRef => tp.captureSetOfInfo
224224
case _ => CaptureSet.ofType(tp, followResult = false)
225225

226+
/** The deep capture set of a type.
227+
* For singleton capabilities `x` and reach capabilities `x*`, this is `{x*}`, provided
228+
* the underlying capture set resulting from traversing the type is non-empty.
229+
* For other types this is the union of all covariant capture sets embedded
230+
* in the type, as computed by `CaptureSet.ofTypeDeeply`.
231+
*/
232+
def deepCaptureSet(using Context): CaptureSet =
233+
val dcs = CaptureSet.ofTypeDeeply(tp)
234+
if dcs.isAlwaysEmpty then dcs
235+
else tp match
236+
case tp @ ReachCapability(_) => tp.singletonCaptureSet
237+
case tp: SingletonCaptureRef => tp.reach.singletonCaptureSet
238+
case _ => dcs
239+
226240
/** A type capturing `ref` */
227241
def capturing(ref: CaptureRef)(using Context): Type =
228242
if tp.captureSet.accountsFor(ref) then tp
@@ -587,7 +601,7 @@ extension (sym: Symbol)
587601
}
588602

589603
def hasTrackedParts(using Context): Boolean =
590-
!CaptureSet.deepCaptureSet(sym.info).isAlwaysEmpty
604+
!CaptureSet.ofTypeDeeply(sym.info).isAlwaysEmpty
591605

592606
extension (tp: AnnotatedType)
593607
/** Is this a boxed capturing type? */

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ object CaptureSet:
10731073
case parent: SingletonCaptureRef if parent.isTrackableRef =>
10741074
tp.singletonCaptureSet
10751075
case _ =>
1076-
CaptureSet.deepCaptureSet(parent)
1076+
CaptureSet.ofTypeDeeply(parent)
10771077
case tpd @ defn.RefinedFunctionOf(rinfo: MethodType) if followResult =>
10781078
ofType(tpd.parent, followResult = false) // pick up capture set from parent type
10791079
++ (recur(rinfo.resType) // add capture set of result
@@ -1099,12 +1099,17 @@ object CaptureSet:
10991099
recur(tp)
11001100
//.showing(i"capture set of $tp = $result", captDebug)
11011101

1102-
def deepCaptureSet(tp: Type)(using Context): CaptureSet =
1102+
/** The deep capture set of a type is the union of all covariant occurrences of
1103+
* capture sets. Nested existential sets are approximated with `cap`.
1104+
*/
1105+
def ofTypeDeeply(tp: Type)(using Context): CaptureSet =
11031106
val collect = new TypeAccumulator[CaptureSet]:
11041107
def apply(cs: CaptureSet, t: Type) = t.dealias match
11051108
case t @ CapturingType(p, cs1) =>
11061109
val cs2 = apply(cs, p)
11071110
if variance > 0 then cs2 ++ cs1 else cs2
1111+
case t @ Existential(_, _) =>
1112+
apply(cs, Existential.toCap(t))
11081113
case _ =>
11091114
foldOver(cs, t)
11101115
collect(CaptureSet.empty, tp)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@ class CheckCaptures extends Recheck, SymTransformer:
548548
def recheckArg(arg: Tree, formal: Type)(using Context): Type =
549549
val argType = recheck(arg, formal)
550550
if unboxedArgs.contains(arg) && ccConfig.useUnboxedParams then
551-
capt.println(i"charging deep capture set of $arg: ${argType} = ${CaptureSet.deepCaptureSet(argType)}")
552-
markFree(CaptureSet.deepCaptureSet(argType), arg.srcPos)
551+
capt.println(i"charging deep capture set of $arg: ${argType} = ${argType.deepCaptureSet}")
552+
markFree(argType.deepCaptureSet, arg.srcPos)
553553
argType
554554

555555
/** A specialized implementation of the apply rule.
@@ -579,7 +579,7 @@ class CheckCaptures extends Recheck, SymTransformer:
579579
val argCaptures =
580580
for (arg, argType) <- tree.args.lazyZip(argTypes) yield
581581
if unboxedArgs.remove(arg) // need to ensure the remove happens, that's why argCaptures is computed even if not needed.
582-
then CaptureSet.deepCaptureSet(argType)
582+
then argType.deepCaptureSet
583583
else argType.captureSet
584584
appType match
585585
case appType @ CapturingType(appType1, refs)

0 commit comments

Comments
 (0)