@@ -180,18 +180,19 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
180
180
extension (refs : Refs )
181
181
182
182
/** The footprint of a set of references `refs` the smallest set `F` such that
183
- * - no maximal capability is in `F`
184
- * - all non-maximal capabilities in `refs` are in `F`
185
- * - if `f in F` then the footprint of `f`'s info is also in `F`.
183
+ * 1. if includeMax is false then no maximal capability is in `F`
184
+ * 2. all capabilities in `refs` satisfying (1) are in `F`
185
+ * 3. if `f in F` then the footprint of `f`'s info is also in `F`.
186
186
*/
187
- private def footprint (using Context ): Refs =
187
+ private def footprint (includeMax : Boolean = false )(using Context ): Refs =
188
+ def retain (ref : CaptureRef ) = includeMax || ! ref.isMaxCapability
188
189
def recur (elems : Refs , newElems : List [CaptureRef ]): Refs = newElems match
189
190
case newElem :: newElems1 =>
190
191
val superElems = newElem.captureSetOfInfo.elems.filter: superElem =>
191
- ! superElem.isMaxCapability && ! elems.contains(superElem)
192
+ retain( superElem) && ! elems.contains(superElem)
192
193
recur(elems ++ superElems, newElems1 ++ superElems.toList)
193
194
case Nil => elems
194
- val elems : Refs = refs.filter(! _.isMaxCapability )
195
+ val elems : Refs = refs.filter(retain )
195
196
recur(elems, elems.toList)
196
197
197
198
private def peaks (using Context ): Refs =
@@ -269,7 +270,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
269
270
val seen : util.EqHashSet [CaptureRef ] = new util.EqHashSet
270
271
271
272
def hiddenByElem (elem : CaptureRef ): Refs = elem match
272
- case Fresh .Cap (hcs) => hcs.elems.filter( ! _.isRootCapability) ++ recur(hcs.elems)
273
+ case Fresh .Cap (hcs) => hcs.elems ++ recur(hcs.elems)
273
274
case ReadOnlyCapability (ref1) => hiddenByElem(ref1).map(_.readOnly)
274
275
case _ => emptyRefs
275
276
@@ -280,20 +281,6 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
280
281
recur(refs)
281
282
end hiddenSet
282
283
283
- /** Same as !refs.hidden.isEmpty but more efficient */
284
- private def containsHidden (using Context ): Boolean =
285
- val seen : util.EqHashSet [CaptureRef ] = new util.EqHashSet
286
-
287
- def recur (refs : Refs ): Boolean = refs.exists: ref =>
288
- seen.add(ref) && ref.stripReadOnly.match
289
- case Fresh .Cap (hcs) =>
290
- hcs.elems.exists(! _.isRootCapability) || recur(hcs.elems)
291
- case _ =>
292
- false
293
-
294
- recur(refs)
295
- end containsHidden
296
-
297
284
/** Subtract all elements that are covered by some element in `others` from this set. */
298
285
private def deduct (others : Refs )(using Context ): Refs =
299
286
refs.filter: ref =>
@@ -302,7 +289,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
302
289
/** Deduct the footprint of `sym` and `sym*` from `refs` */
303
290
private def deductSymFootprint (sym : Symbol )(using Context ): Refs =
304
291
val ref = sym.termRef
305
- if ref.isTrackableRef then refs.deduct(CaptureSet (ref, ref.reach).elems.footprint)
292
+ if ref.isTrackableRef then refs.deduct(CaptureSet (ref, ref.reach).elems.footprint() )
306
293
else refs
307
294
308
295
/** Deduct `sym` and `sym*` from `refs` */
@@ -314,7 +301,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
314
301
/** Deduct the footprint of all captures of trees in `deps` from `refs` */
315
302
private def deductCapturesOf (deps : List [Tree ])(using Context ): Refs =
316
303
deps.foldLeft(refs): (refs, dep) =>
317
- refs.deduct(captures(dep).footprint)
304
+ refs.deduct(captures(dep).footprint() )
318
305
end extension
319
306
320
307
/** The deep capture set of an argument or prefix widened to the formal parameter, if
@@ -333,16 +320,19 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
333
320
shared.nth(0 ) match
334
321
case fresh @ Fresh .Cap (hidden) =>
335
322
if hidden.owner.exists then i " $fresh of ${hidden.owner}" else i " $fresh"
323
+ case other =>
324
+ i " $other"
336
325
337
326
def overlapStr (hiddenSet : Refs , clashSet : Refs )(using Context ): String =
338
- val hiddenFootprint = hiddenSet.footprint
339
- val clashFootprint = clashSet.footprint
327
+ val hiddenFootprint = hiddenSet.footprint()
328
+ val clashFootprint = clashSet.footprint()
340
329
// The overlap of footprints, or, of this empty the set of shared peaks.
341
330
// We prefer footprint overlap since it tends to be more informative.
342
331
val overlap = hiddenFootprint.overlapWith(clashFootprint)
343
332
if ! overlap.isEmpty then i " ${CaptureSet (overlap)}"
344
333
else
345
- val sharedPeaks = hiddenSet.peaks.sharedWith(clashSet.peaks)
334
+ val sharedPeaks = hiddenSet.footprint(includeMax = true ).sharedWith:
335
+ clashSet.footprint(includeMax = true )
346
336
assert(! sharedPeaks.isEmpty, i " no overlap for $hiddenSet vs $clashSet" )
347
337
sharedPeaksStr(sharedPeaks)
348
338
@@ -391,9 +381,9 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
391
381
|Some of these overlap with the captures of the ${clashArgStr.trim}$clashTypeStr.
392
382
|
393
383
| Hidden set of current argument : ${CaptureSet (hiddenSet)}
394
- | Hidden footprint of current argument : ${CaptureSet (hiddenSet.footprint)}
384
+ | Hidden footprint of current argument : ${CaptureSet (hiddenSet.footprint() )}
395
385
| Capture set of $clashArgStr : ${CaptureSet (clashSet)}
396
- | Footprint set of $clashArgStr : ${CaptureSet (clashSet.footprint)}
386
+ | Footprint set of $clashArgStr : ${CaptureSet (clashSet.footprint() )}
397
387
| The two sets overlap at : ${overlapStr(hiddenSet, clashSet)}""" ,
398
388
polyArg.srcPos)
399
389
@@ -657,7 +647,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
657
647
val captured = genPart.deepCaptureSet.elems
658
648
val hiddenSet = captured.hiddenSet.pruned
659
649
val clashSet = otherPart.deepCaptureSet.elems
660
- val deepClashSet = (clashSet.footprint ++ clashSet.hiddenSet).pruned
650
+ val deepClashSet = (clashSet.footprint() ++ clashSet.hiddenSet).pruned
661
651
report.error(
662
652
em """ Separation failure in ${role.description} $tpe.
663
653
|One part, $genPart, hides capabilities ${CaptureSet (hiddenSet)}.
@@ -735,7 +725,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
735
725
c.add(c1)
736
726
case t @ CapturingType (parent, cs) =>
737
727
val c1 = this (c, parent)
738
- if cs.elems.containsHidden then c1.add(Captures .Hidden )
728
+ if cs.elems.exists(_.stripReadOnly.isFresh) then c1.add(Captures .Hidden )
739
729
else if ! cs.elems.isEmpty then c1.add(Captures .Explicit )
740
730
else c1
741
731
case t : TypeRef if t.symbol.isAbstractOrParamType =>
@@ -760,11 +750,11 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
760
750
// "see through them" when we look at hidden sets.
761
751
then
762
752
val refs = tpe.deepCaptureSet.elems
763
- val toCheck = refs.hiddenSet.footprint.deduct(refs.footprint)
753
+ val toCheck = refs.hiddenSet.footprint() .deduct(refs.footprint() )
764
754
checkConsumedRefs(toCheck, tpe, role, i " ${role.description} $tpe hides " , pos)
765
755
case TypeRole .Argument (arg) =>
766
756
if tpe.hasAnnotation(defn.ConsumeAnnot ) then
767
- val capts = captures(arg).footprint
757
+ val capts = captures(arg).footprint()
768
758
checkConsumedRefs(capts, tpe, role, i " argument to @consume parameter with type ${arg.nuType} refers to " , pos)
769
759
case _ =>
770
760
@@ -848,7 +838,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
848
838
def checkValOrDefDef (tree : ValOrDefDef )(using Context ): Unit =
849
839
if ! tree.symbol.isOneOf(TermParamOrAccessor ) && ! isUnsafeAssumeSeparate(tree.rhs) then
850
840
checkType(tree.tpt, tree.symbol)
851
- capt.println(i " sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hiddenSet.footprint}" )
841
+ capt.println(i " sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hiddenSet.footprint() }" )
852
842
pushDef(tree, captures(tree.tpt).hiddenSet.deductSymRefs(tree.symbol))
853
843
854
844
def inSection [T ](op : => T )(using Context ): T =
@@ -869,7 +859,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
869
859
case tree @ Select (qual, _) if tree.symbol.is(Method ) && tree.symbol.hasAnnotation(defn.ConsumeAnnot ) =>
870
860
traverseChildren(tree)
871
861
checkConsumedRefs(
872
- captures(qual).footprint, qual.nuType,
862
+ captures(qual).footprint() , qual.nuType,
873
863
TypeRole .Qualifier (qual, tree.symbol),
874
864
i " call prefix of @consume ${tree.symbol} refers to " , qual.srcPos)
875
865
case tree : GenericApply =>
0 commit comments