Skip to content

Commit a4b91bd

Browse files
committed
Drop transitive hidden set construction
1 parent 64b4e78 commit a4b91bd

File tree

4 files changed

+23
-39
lines changed

4 files changed

+23
-39
lines changed

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,11 @@ class CheckCaptures extends Recheck, SymTransformer:
525525
def includeCallCaptures(sym: Symbol, resType: Type, tree: Tree)(using Context): Unit = resType match
526526
case _: MethodOrPoly => // wait until method is fully applied
527527
case _ =>
528-
if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), tree)
528+
def isRetained(ref: CaptureRef): Boolean = ref.pathRoot match
529+
case root: ThisType => ctx.owner.isContainedIn(root.cls)
530+
case _ => true
531+
if sym.exists && curEnv.isOpen then
532+
markFree(capturedVars(sym).filter(isRetained), tree)
529533

530534
/** Under the sealed policy, disallow the root capability in type arguments.
531535
* Type arguments come either from a TypeApply node or from an AppliedType

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

+14-34
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,6 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
197197
val elems: Refs = refs.filter(!_.isMaxCapability)
198198
recur(elems, elems.toList)
199199

200-
/** The members of type Fresh.Cap(...) or Fresh.Cap(...).rd in the transitive closure
201-
* of this set
202-
*/
203-
private def freshElems(using Context): Refs =
204-
def recur(seen: Refs, acc: Refs, newElems: List[CaptureRef]): Refs = newElems match
205-
case newElem :: newElems1 =>
206-
if seen.contains(newElem) then
207-
recur(seen, acc, newElems1)
208-
else newElem.stripReadOnly match
209-
case Fresh.Cap(_) =>
210-
recur(seen, acc + newElem, newElems1)
211-
//case _: TypeRef | _: TypeParamRef =>
212-
// recur(seen + newElem, acc, newElems1)
213-
case _ =>
214-
recur(seen + newElem, acc, newElem.captureSetOfInfo.elems.toList ++ newElems1)
215-
case Nil => acc
216-
recur(emptyRefs, emptyRefs, refs.toList)
217-
218200
private def peaks(using Context): Refs =
219201
def recur(seen: Refs, acc: Refs, newElems: List[CaptureRef]): Refs = newElems match
220202
case newElem :: newElems1 =>
@@ -286,7 +268,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
286268
* capability in `refs`. E g. if `R = {x, <cap hiding <y, <cap hiding z>>}` then
287269
* its hidden set is `{y, z}`.
288270
*/
289-
private def hidden(using Context): Refs =
271+
private def hiddenSet(using Context): Refs =
290272
val seen: util.EqHashSet[CaptureRef] = new util.EqHashSet
291273

292274
def hiddenByElem(elem: CaptureRef): Refs = elem match
@@ -299,7 +281,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
299281
if seen.add(elem) then elems ++ hiddenByElem(elem) else elems
300282

301283
recur(refs)
302-
end hidden
284+
end hiddenSet
303285

304286
/** Same as !refs.hidden.isEmpty but more efficient */
305287
private def containsHidden(using Context): Boolean =
@@ -315,11 +297,6 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
315297
recur(refs)
316298
end containsHidden
317299

318-
def hiddenSet(using Context): Refs =
319-
freshElems.flatMap:
320-
case Fresh.Cap(hidden) => hidden.elems
321-
case ReadOnlyCapability(Fresh.Cap(hidden)) => hidden.elems.map(_.readOnly)
322-
323300
/** Subtract all elements that are covered by some element in `others` from this set. */
324301
private def deduct(others: Refs)(using Context): Refs =
325302
refs.filter: ref =>
@@ -353,7 +330,12 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
353330
private def captures(tree: Tree)(using Context): Refs =
354331
tree.nuType.deepCaptureSet.elems
355332

356-
// ---- Error reporting TODO Once these are stabilized, move to messages -----
333+
// ---- Error reporting TODO Once these are stabilized, move to messages -----" +
334+
335+
def sharedPeaksStr(shared: Refs)(using Context): String =
336+
shared.nth(0) match
337+
case fresh @ Fresh.Cap(hidden) =>
338+
if hidden.owner.exists then i"$fresh of ${hidden.owner}" else i"$fresh"
357339

358340
def overlapStr(hiddenSet: Refs, clashSet: Refs)(using Context): String =
359341
val hiddenFootprint = hiddenSet.footprint
@@ -365,9 +347,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
365347
else
366348
val sharedPeaks = hiddenSet.peaks.sharedWith(clashSet.peaks)
367349
assert(!sharedPeaks.isEmpty, i"no overlap for $hiddenSet vs $clashSet")
368-
sharedPeaks.nth(0) match
369-
case fresh @ Fresh.Cap(hidden) =>
370-
if hidden.owner.exists then i"cap of ${hidden.owner}" else i"$fresh"
350+
sharedPeaksStr(sharedPeaks)
371351

372352
/** Report a separation failure in an application `fn(args)`
373353
* @param fn the function
@@ -429,7 +409,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
429409
*/
430410
def sepUseError(tree: Tree, used: Refs, globalOverlap: Refs)(using Context): Unit =
431411
val individualChecks = for mdefs <- previousDefs.iterator; mdef <- mdefs.iterator yield
432-
val hiddenByDef = captures(mdef.tpt).hidden.footprint
412+
val hiddenByDef = captures(mdef.tpt).hiddenSet.footprint
433413
val overlap = defUseOverlap(hiddenByDef, used, tree.symbol)
434414
if !overlap.isEmpty then
435415
def resultStr = if mdef.isInstanceOf[DefDef] then " result" else ""
@@ -560,7 +540,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
560540
resultType.get(sym) match
561541
case Some(tp) if !overlap.isEmpty =>
562542
val declared = tp.captureSet.elems
563-
overlap.deduct(declared.footprint).deduct(declared.hidden.footprint)
543+
overlap.deduct(declared.footprint).deduct(declared.hiddenSet.footprint)
564544
case _ =>
565545
overlap
566546

@@ -784,7 +764,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
784764
// "see through them" when we look at hidden sets.
785765
then
786766
val refs = tpe.deepCaptureSet.elems
787-
val toCheck = refs.hidden.footprint.deduct(refs.footprint)
767+
val toCheck = refs.hiddenSet.footprint.deduct(refs.footprint)
788768
checkConsumedRefs(toCheck, tpe, role, i"${role.description} $tpe hides", pos)
789769
case TypeRole.Argument(arg) =>
790770
if tpe.hasAnnotation(defn.ConsumeAnnot) then
@@ -869,8 +849,8 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
869849
if !tree.symbol.isOneOf(TermParamOrAccessor) && !isUnsafeAssumeSeparate(tree.rhs) then
870850
checkType(tree.tpt, tree.symbol)
871851
if previousDefs.nonEmpty then
872-
capt.println(i"sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hidden.footprint}")
873-
defsShadow ++= captures(tree.tpt).hidden.deductSymRefs(tree.symbol).footprint
852+
capt.println(i"sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hiddenSet.footprint}")
853+
defsShadow ++= captures(tree.tpt).hiddenSet.deductSymRefs(tree.symbol).footprint
874854
resultType(tree.symbol) = tree.tpt.nuType
875855
previousDefs.head += tree
876856

tests/neg-custom-args/captures/sep-pairs.check

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
13 |def bad: Pair[Ref^, Ref^] = // error: overlap at r1*, r0
3030
| ^^^^^^^^^^^^^^^^
3131
| Separation failure in method bad's result type Pair[box Ref^, box Ref^].
32-
| One part, box Ref^, hides capabilities {cap, cap}.
33-
| Another part, box Ref^, captures capabilities {cap, cap}.
34-
| The two sets overlap at cap of method bad.
32+
| One part, box Ref^, hides capabilities {r1*, r0}.
33+
| Another part, box Ref^, captures capabilities {r1*, r0}.
34+
| The two sets overlap at {r1*, r0}.
3535
-- Error: tests/neg-custom-args/captures/sep-pairs.scala:44:18 ---------------------------------------------------------
3636
44 | val sameToPair: Pair[Ref^, Ref^] = Pair(fstSame, sndSame) // error
3737
| ^^^^^^^^^^^^^^^^

tests/neg-custom-args/captures/sep-use2.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test1(@consume c: Object^, f: Object^ => Object^) =
1515
def test2(@consume c: Object^, f: Object^ ->{c} Object^) =
1616
def cc: Object^ = c // error
1717
val x1 =
18-
{ f(cc) } // error
18+
{ f(cc) } // error // error
1919
val x4: Object^ =
2020
{ f(c) } // error // error
2121

0 commit comments

Comments
 (0)