@@ -332,18 +332,27 @@ extension (tp: Type)
332332 /** The capture set consisting of all top-level captures of `tp` that appear under a box.
333333 * Unlike for `boxed` this also considers parents of capture types, unions and
334334 * intersections, and type proxies other than abstract types.
335+ * Furthermore, if the original type is a capture ref `x`, it replaces boxed universal sets
336+ * on the fly with x*.
335337 */
336338 def boxedCaptureSet (using Context ): CaptureSet =
337- def getBoxed (tp : Type ): CaptureSet = tp match
339+ def getBoxed (tp : Type , pre : Type ): CaptureSet = tp match
338340 case tp @ CapturingType (parent, refs) =>
339- val pcs = getBoxed(parent)
340- if tp.isBoxed then refs ++ pcs else pcs
341+ val pcs = getBoxed(parent, pre)
342+ if ! tp.isBoxed then
343+ pcs
344+ else if pre.exists && refs.containsRootCapability then
345+ val reachRef = if refs.isReadOnly then pre.reach.readOnly else pre.reach
346+ pcs ++ reachRef.singletonCaptureSet
347+ else
348+ pcs ++ refs
349+ case ref : CaptureRef if ref.isTracked && ! pre.exists => getBoxed(ref, ref)
341350 case tp : TypeRef if tp.symbol.isAbstractOrParamType => CaptureSet .empty
342- case tp : TypeProxy => getBoxed(tp.superType)
343- case tp : AndType => getBoxed(tp.tp1) ** getBoxed(tp.tp2)
344- case tp : OrType => getBoxed(tp.tp1) ++ getBoxed(tp.tp2)
351+ case tp : TypeProxy => getBoxed(tp.superType, pre )
352+ case tp : AndType => getBoxed(tp.tp1, pre ) ** getBoxed(tp.tp2, pre )
353+ case tp : OrType => getBoxed(tp.tp1, pre ) ++ getBoxed(tp.tp2, pre )
345354 case _ => CaptureSet .empty
346- getBoxed(tp)
355+ getBoxed(tp, NoType )
347356
348357 /** Is the boxedCaptureSet of this type nonempty? */
349358 def isBoxedCapturing (using Context ): Boolean =
0 commit comments