Skip to content

Commit cd0bc94

Browse files
committed
SepCheck: Record span capture sets instead of deep capture sets
1 parent 28eb166 commit cd0bc94

File tree

7 files changed

+24
-25
lines changed

7 files changed

+24
-25
lines changed

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ extension (tp: Type)
157157
* a singleton capability `x` or a reach capability `x*`, the deep capture
158158
* set can be narrowed to`{x*}`.
159159
*/
160-
def deepCaptureSet(includeTypevars: Boolean)(using Context): CaptureSet =
161-
val dcs = CaptureSet.ofTypeDeeply(tp.widen.stripCapturing, includeTypevars)
160+
def deepCaptureSet(includeTypevars: Boolean, includeBoxed: Boolean = true)(using Context): CaptureSet =
161+
val dcs = CaptureSet.ofTypeDeeply(tp.widen.stripCapturing, includeTypevars, includeBoxed)
162162
if dcs.isAlwaysEmpty then tp.captureSet
163163
else tp match
164164
case tp: ObjectCapability if tp.isTrackableRef => tp.reach.singletonCaptureSet
@@ -167,6 +167,9 @@ extension (tp: Type)
167167
def deepCaptureSet(using Context): CaptureSet =
168168
deepCaptureSet(includeTypevars = false)
169169

170+
def spanCaptureSet(using Context): CaptureSet =
171+
deepCaptureSet(includeTypevars = false, includeBoxed = false)
172+
170173
/** A type capturing `ref` */
171174
def capturing(ref: Capability)(using Context): Type =
172175
if tp.captureSet.accountsFor(ref) then tp
@@ -362,7 +365,7 @@ extension (tp: Type)
362365
*/
363366
def derivesFromCapTraitDeeply(cls: ClassSymbol)(using Context): Boolean =
364367
val accumulate = new DeepTypeAccumulator[Boolean]:
365-
def capturingCase(acc: Boolean, parent: Type, refs: CaptureSet) =
368+
def capturingCase(acc: Boolean, parent: Type, refs: CaptureSet, boxed: Boolean) =
366369
this(acc, parent)
367370
&& (parent.derivesFromCapTrait(cls)
368371
|| refs.isConst && refs.elems.forall(_.derivesFromCapTrait(cls)))
@@ -734,15 +737,15 @@ object ContainsParam:
734737
abstract class DeepTypeAccumulator[T](using Context) extends TypeAccumulator[T]:
735738
val seen = util.HashSet[Symbol]()
736739

737-
protected def capturingCase(acc: T, parent: Type, refs: CaptureSet): T
740+
protected def capturingCase(acc: T, parent: Type, refs: CaptureSet, boxed: Boolean): T
738741

739742
protected def abstractTypeCase(acc: T, t: TypeRef, upperBound: Type): T
740743

741744
def apply(acc: T, t: Type) =
742745
if variance < 0 then acc
743746
else t.dealias match
744747
case t @ CapturingType(parent, cs) =>
745-
capturingCase(acc, parent, cs)
748+
capturingCase(acc, parent, cs, t.isBoxed)
746749
case t: TypeRef if t.symbol.isAbstractOrParamType && !seen.contains(t.symbol) =>
747750
seen += t.symbol
748751
abstractTypeCase(acc, t, t.info.bounds.hi)

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ object CaptureSet:
957957
/** Variables created in types of inferred type trees */
958958
class ProperVar(override val owner: Symbol, initialElems: Refs, nestedOK: Boolean)(using /*@constructorOnly*/ ictx: Context)
959959
extends Var(owner, initialElems, nestedOK)
960-
960+
961961
/** A variable that is derived from some other variable via a map or filter. */
962962
abstract class DerivedVar(owner: Symbol, initialElems: Refs)(using @constructorOnly ctx: Context)
963963
extends Var(owner, initialElems):
@@ -1619,13 +1619,17 @@ object CaptureSet:
16191619
/** The deep capture set of a type is the union of all covariant occurrences of
16201620
* capture sets. Nested existential sets are approximated with `cap`.
16211621
*/
1622-
def ofTypeDeeply(tp: Type, includeTypevars: Boolean = false)(using Context): CaptureSet =
1622+
def ofTypeDeeply(tp: Type, includeTypevars: Boolean = false, includeBoxed: Boolean = true)(using Context): CaptureSet =
16231623
val collect = new DeepTypeAccumulator[CaptureSet]:
1624-
def capturingCase(acc: CaptureSet, parent: Type, refs: CaptureSet) =
1625-
this(acc, parent) ++ refs
1624+
1625+
def capturingCase(acc: CaptureSet, parent: Type, refs: CaptureSet, boxed: Boolean) =
1626+
if includeBoxed || !boxed then this(acc, parent) ++ refs
1627+
else this(acc, parent)
1628+
16261629
def abstractTypeCase(acc: CaptureSet, t: TypeRef, upperBound: Type) =
16271630
if includeTypevars && upperBound.isExactlyAny then fresh(Origin.DeepCS(t))
16281631
else this(acc, upperBound)
1632+
16291633
collect(CaptureSet.empty, tp)
16301634

16311635
type AssumedContains = immutable.Map[TypeRef, SimpleIdentitySet[Capability]]

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,12 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
312312
private def formalCaptures(arg: Tree)(using Context): Refs =
313313
arg.formalType.orElse(arg.nuType).deepCaptureSet.elems
314314

315-
/** The deep capture set if the type of `tree` */
315+
/** The span capture set if the type of `tree` */
316316
private def captures(tree: Tree)(using Context): Refs =
317+
tree.nuType.spanCaptureSet.elems
318+
319+
/** The deep capture set if the type of `tree` */
320+
private def deepCaptures(tree: Tree)(using Context): Refs =
317321
tree.nuType.deepCaptureSet.elems
318322

319323
// ---- Error reporting TODO Once these are stabilized, move to messages -----" +
@@ -376,7 +380,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
376380
if clashIdx == 0 && !isShowableMethod then "" // we already mentioned the type in `funStr`
377381
else i" with type ${clashing.nuType}"
378382
val hiddenSet = formalCaptures(polyArg).hiddenSet
379-
val clashSet = captures(clashing)
383+
val clashSet = deepCaptures(clashing)
380384
report.error(
381385
em"""Separation failure: argument of type ${polyArg.nuType}
382386
|to $funStr

tests/neg-custom-args/captures/sepchecks2.check

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
-- Error: tests/neg-custom-args/captures/sepchecks2.scala:10:10 --------------------------------------------------------
2-
10 | println(c) // error
3-
| ^
4-
| Separation failure: Illegal access to {c} which is hidden by the previous definition
5-
| of value xs with type List[() => Unit].
6-
| This type hides capabilities {c}
7-
|
8-
| where: => refers to a fresh root capability in the type of value xs
91
-- Error: tests/neg-custom-args/captures/sepchecks2.scala:13:7 ---------------------------------------------------------
102
13 | foo((() => println(c)) :: Nil, c) // error
113
| ^^^^^^^^^^^^^^^^^^^^^^^^

tests/neg-custom-args/captures/sepchecks2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def bar(x: (Object^, Object^)): Unit = ???
77

88
def Test(consume c: Object^) =
99
val xs: List[() => Unit] = (() => println(c)) :: Nil
10-
println(c) // error
10+
println(c)
1111

1212
def Test2(c: Object^, d: Object^): Unit =
1313
foo((() => println(c)) :: Nil, c) // error

tests/neg-custom-args/captures/unsound-reach-6.check

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,3 @@
2626
| ^^
2727
| Local reach capability ys* leaks into capture scope of method test.
2828
| You could try to abstract the capabilities referred to by ys* in a capset variable.
29-
-- Error: tests/neg-custom-args/captures/unsound-reach-6.scala:19:14 ---------------------------------------------------
30-
19 | val z = f(ys) // error consume failure
31-
| ^^
32-
|Separation failure: argument to consume parameter with type List[() ->{io} Unit] refers to non-local parameter io

tests/neg-custom-args/captures/unsound-reach-6.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test(io: IO^)(ys: List[() ->{io} Unit]) =
1616
def test(io: IO^) =
1717
def ys: List[() ->{io} Unit] = ???
1818
val x = () =>
19-
val z = f(ys) // error consume failure
19+
val z = f(ys) // ok, was error consume failure
2020
z()
2121
val _: () -> Unit = x // error
2222
()

0 commit comments

Comments
 (0)