@@ -52,18 +52,10 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
52
52
53
53
private def hidden (using Context ): Refs =
54
54
val seen : util.EqHashSet [CaptureRef ] = new util.EqHashSet
55
-
56
- def hiddenByElem (elem : CaptureRef ): Refs =
57
- if seen.add(elem) then elem match
58
- case Fresh .Cap (hcs) => hcs.elems.filter(! _.isRootCapability) ++ recur(hcs.elems)
59
- case ReadOnlyCapability (ref) => hiddenByElem(ref).map(_.readOnly)
60
- case _ => emptySet
61
- else emptySet
62
-
63
55
def recur (cs : Refs ): Refs =
64
56
(emptySet /: cs): (elems, elem) =>
65
- elems ++ hiddenByElem(elem)
66
-
57
+ if seen.add(elem) then elems ++ hiddenByElem(elem, recur )
58
+ else elems
67
59
recur(refs)
68
60
end hidden
69
61
@@ -79,6 +71,11 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
79
71
refs -- captures(dep).footprint
80
72
end extension
81
73
74
+ private def hiddenByElem (ref : CaptureRef , recur : Refs => Refs )(using Context ): Refs = ref match
75
+ case Fresh .Cap (hcs) => hcs.elems.filter(! _.isRootCapability) ++ recur(hcs.elems)
76
+ case ReadOnlyCapability (ref1) => hiddenByElem(ref1, recur).map(_.readOnly)
77
+ case _ => emptySet
78
+
82
79
/** The captures of an argument or prefix widened to the formal parameter, if
83
80
* the latter contains a cap.
84
81
*/
@@ -212,6 +209,34 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
212
209
if ! overlap.isEmpty then
213
210
sepUseError(tree, usedFootprint, overlap)
214
211
212
+ def checkType (tpt : Tree , sym : Symbol )(using Context ) =
213
+ def checkSep (hidden : Refs , footprint : Refs , descr : String ) =
214
+ val overlap = hidden.overlapWith(footprint)
215
+ if ! overlap.isEmpty then
216
+ report.error(
217
+ em """ Separation failure: ${tpt.nuType} captures a root element hiding ${CaptureSet (hidden)}
218
+ |and also $descr ${CaptureSet (footprint)}.
219
+ |The two sets overlap at ${CaptureSet (overlap)}""" ,
220
+ tpt.srcPos)
221
+
222
+ val capts = CaptureSet .ofTypeDeeply(tpt.nuType,
223
+ union = (xs, ys) => ctx ?=> CaptureSet (xs.elems ++ ys.elems))
224
+ .elems
225
+ // Note: Can't use captures(...) or deepCaptureSet here because these would map
226
+ // e.g (Object^{<cap hiding x}, Object^{x}) to {<cap hiding x>} and we need
227
+ // {<cap hiding x>, x} instead.
228
+ val explicitFootprint = capts.footprint
229
+ var hiddenFootprint : Refs = emptySet
230
+ // println(i"checking tp ${tpt.tpe} with $capts fp $explicitFootprint")
231
+ for ref <- capts do
232
+ val hidden0 = hiddenByElem(ref, _.hidden).footprint
233
+ val hiddenByRef = hiddenByElem(ref, _.hidden).footprint.deductSym(sym)
234
+ if ! hiddenByRef.isEmpty then
235
+ checkSep(hiddenByRef, explicitFootprint, " refers to" )
236
+ checkSep(hiddenByRef, hiddenFootprint, " captures another root element hiding" )
237
+ hiddenFootprint ++= hiddenByRef
238
+ end checkType
239
+
215
240
private def collectMethodTypes (tp : Type ): List [TermLambda ] = tp match
216
241
case tp : MethodType => tp :: collectMethodTypes(tp.resType)
217
242
case tp : PolyType => collectMethodTypes(tp.resType)
@@ -269,11 +294,13 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
269
294
defsShadow = saved
270
295
case tree : ValOrDefDef =>
271
296
traverseChildren(tree)
272
- if previousDefs.nonEmpty && ! tree.symbol.isOneOf(TermParamOrAccessor ) then
273
- capt.println(i " sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hidden.footprint}" )
274
- defsShadow ++= captures(tree.tpt).hidden.footprint.deductSym(tree.symbol)
275
- resultType(tree.symbol) = tree.tpt.nuType
276
- previousDefs.head += tree
297
+ if ! tree.symbol.isOneOf(TermParamOrAccessor ) then
298
+ checkType(tree.tpt, tree.symbol)
299
+ if previousDefs.nonEmpty then
300
+ capt.println(i " sep check def ${tree.symbol}: ${tree.tpt} with ${captures(tree.tpt).hidden.footprint}" )
301
+ defsShadow ++= captures(tree.tpt).hidden.footprint.deductSym(tree.symbol)
302
+ resultType(tree.symbol) = tree.tpt.nuType
303
+ previousDefs.head += tree
277
304
case _ =>
278
305
traverseChildren(tree)
279
306
end SepChecker
0 commit comments