@@ -457,14 +457,16 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
457
457
* Also check separation via checkType within individual arguments widened to their
458
458
* formal paramater types.
459
459
*
460
- * @param fn the applied function
461
- * @param args the flattened argument lists
462
- * @param app the entire application tree
463
- * @param deps cross argument dependencies: maps argument trees to
464
- * those other arguments that where mentioned by coorresponding
465
- * formal parameters.
460
+ * @param fn the applied function
461
+ * @param args the flattened argument lists
462
+ * @param app the entire application tree
463
+ * @param deps cross argument dependencies: maps argument trees to
464
+ * those other arguments that where mentioned by coorresponding
465
+ * formal parameters.
466
+ * @param resultPeaks peaks in the result type that could interfere with the
467
+ * hidden sets of formal parameters
466
468
*/
467
- private def checkApply (fn : Tree , args : List [Tree ], app : Tree , deps : collection.Map [Tree , List [Tree ]])(using Context ): Unit =
469
+ private def checkApply (fn : Tree , args : List [Tree ], app : Tree , deps : collection.Map [Tree , List [Tree ]], resultPeaks : Refs )(using Context ): Unit =
468
470
val (qual, fnCaptures) = methPart(fn) match
469
471
case Select (qual, _) => (qual, qual.nuType.captureSet)
470
472
case _ => (fn, CaptureSet .empty)
@@ -475,6 +477,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
475
477
i """ check separate $fn( $args), fnCaptures = $fnCaptures,
476
478
| formalCaptures = ${args.map(arg => CaptureSet (formalCaptures(arg)))},
477
479
| actualCaptures = ${args.map(arg => CaptureSet (captures(arg)))},
480
+ | resultPeaks = ${resultPeaks},
478
481
| deps = ${deps.toList}""" )
479
482
val parts = qual :: args
480
483
var reported : SimpleIdentitySet [Tree ] = SimpleIdentitySet .empty
@@ -519,26 +522,10 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
519
522
currentPeaks.hidden ++ argPeaks.hidden)
520
523
end for
521
524
522
- def collectRefs (args : List [Type ], res : Type ) =
523
- args.foldLeft(argCaptures(res)): (refs, arg) =>
524
- refs ++ arg.deepCaptureSet.elems
525
-
526
- /** The deep capture sets of all parameters of this type (if it is a function type) */
527
- def argCaptures (tpe : Type ): Refs = tpe match
528
- case defn.FunctionOf (args, resultType, isContextual) =>
529
- collectRefs(args, resultType)
530
- case defn.RefinedFunctionOf (mt) =>
531
- collectRefs(mt.paramInfos, mt.resType)
532
- case CapturingType (parent, _) =>
533
- argCaptures(parent)
534
- case _ =>
535
- emptyRefs
536
-
537
- if ! deps(app).isEmpty then
538
- lazy val appPeaks = argCaptures(app.nuType).peaks
525
+ if ! resultPeaks.isEmpty then
539
526
lazy val partPeaks = partsWithPeaks.toMap
540
- for arg <- deps(app) do
541
- if arg.needsSepCheck && ! partPeaks(arg).hidden.sharedWith(appPeaks ).isEmpty then
527
+ for arg <- args do
528
+ if arg.needsSepCheck && ! partPeaks(arg).hidden.sharedWith(resultPeaks ).isEmpty then
542
529
sepApplyError(fn, parts, arg, app)
543
530
end checkApply
544
531
@@ -816,10 +803,15 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
816
803
* then the dependencies of an application `f(a, b, c)` of type C^{y} is the map
817
804
*
818
805
* [ b -> [a]
819
- * , c -> [a, b]
820
- * , f(a, b, c) -> [b]]
806
+ * , c -> [a, b] ]
807
+ *
808
+ * It also returns the interfering peaks of the result of the application. They are the
809
+ * peaks of argument captures and deep captures of the result function type, minus the
810
+ * those dependent on parameters. For instance,
811
+ * if `f` has the type (x: A, y: B, c: C) -> (op: () ->{b} Unit) -> List[() ->{x, y, a} Unit], its interfering
812
+ * peaks will be the peaks of `a` and `b`.
821
813
*/
822
- private def dependencies (fn : Tree , argss : List [List [Tree ]], app : Tree )(using Context ): collection.Map [Tree , List [Tree ]] =
814
+ private def dependencies (fn : Tree , argss : List [List [Tree ]], app : Tree )(using Context ): ( collection.Map [Tree , List [Tree ]], Refs ) =
823
815
def isFunApply (sym : Symbol ) =
824
816
sym.name == nme.apply && defn.isFunctionClass(sym.owner)
825
817
val mtpe =
@@ -831,23 +823,47 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
831
823
val argMap = mtpsWithArgs.toMap
832
824
val deps = mutable.HashMap [Tree , List [Tree ]]().withDefaultValue(Nil )
833
825
826
+ def argOfDep (dep : Capability ): Option [Tree ] =
827
+ dep.stripReach match
828
+ case dep : TermParamRef =>
829
+ Some (argMap(dep.binder)(dep.paramNum))
830
+ case dep : ThisType if dep.cls == fn.symbol.owner =>
831
+ val Select (qual, _) = fn : @ unchecked // TODO can we use fn instead?
832
+ Some (qual)
833
+ case _ =>
834
+ None
835
+
834
836
def recordDeps (formal : Type , actual : Tree ) =
835
- for dep <- formal.captureSet.elems.toList do
836
- val referred = dep.stripReach match
837
- case dep : TermParamRef =>
838
- argMap(dep.binder)(dep.paramNum) :: Nil
839
- case dep : ThisType if dep.cls == fn.symbol.owner =>
840
- val Select (qual, _) = fn : @ unchecked // TODO can we use fn instead?
841
- qual :: Nil
842
- case _ =>
843
- Nil
837
+ def captures = formal.captureSet
838
+ for dep <- captures.elems.toList do
839
+ val referred = argOfDep(dep)
844
840
deps(actual) ++= referred
845
841
842
+ inline def isLocalRef (x : Capability ): Boolean = x.isInstanceOf [TermParamRef ]
843
+
844
+ def resultArgCaptures (tpe : Type ): Refs =
845
+ def collectRefs (args : List [Type ], res : Type ) =
846
+ args.foldLeft(resultArgCaptures(res)): (refs, arg) =>
847
+ refs ++ arg.captureSet.elems
848
+ tpe match
849
+ case defn.FunctionOf (args, resultType, isContextual) =>
850
+ collectRefs(args, resultType)
851
+ case defn.RefinedFunctionOf (mt) =>
852
+ collectRefs(mt.paramInfos, mt.resType)
853
+ case CapturingType (parent, refs) =>
854
+ resultArgCaptures(parent) ++ tpe.boxedCaptureSet.elems
855
+ case _ =>
856
+ emptyRefs
857
+
846
858
for (mt, args) <- mtpsWithArgs; (formal, arg) <- mt.paramInfos.zip(args) do
847
859
recordDeps(formal, arg)
848
- recordDeps(mtpe.finalResultType, app)
860
+
861
+ val resultType = mtpe.finalResultType
862
+ val resultCaptures =
863
+ (resultArgCaptures(resultType) ++ resultType.deepCaptureSet.elems).filter(! isLocalRef(_))
864
+ val resultPeaks = resultCaptures.peaks
849
865
capt.println(i " deps for $app = ${deps.toList}" )
850
- deps
866
+ ( deps, resultPeaks)
851
867
852
868
853
869
/** Decompose an application into a function prefix and a list of argument lists.
@@ -860,7 +876,8 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
860
876
case TypeApply (fn, args) => recur(fn, argss) // skip type arguments
861
877
case _ =>
862
878
if argss.nestedExists(_.needsSepCheck) then
863
- checkApply(tree, argss.flatten, app, dependencies(tree, argss, app))
879
+ val (deps, resultPeaks) = dependencies(tree, argss, app)
880
+ checkApply(tree, argss.flatten, app, deps, resultPeaks)
864
881
recur(app, Nil )
865
882
866
883
/** Is `tree` an application of `caps.unsafe.unsafeAssumeSeparate`? */
0 commit comments