@@ -168,7 +168,7 @@ sealed abstract class CaptureSet extends Showable:
168
168
*/
169
169
protected def addThisElem (elem : CaptureRef )(using Context , VarState ): CompareResult
170
170
171
- protected def addHiddenElem (elem : CaptureRef )(using ctx : Context , vs : VarState ): CompareResult =
171
+ protected def addIfHiddenOrFail (elem : CaptureRef )(using ctx : Context , vs : VarState ): CompareResult =
172
172
if elems.exists(_.maxSubsumes(elem, canAddHidden = true ))
173
173
then CompareResult .OK
174
174
else CompareResult .Fail (this :: Nil )
@@ -438,7 +438,7 @@ object CaptureSet:
438
438
def isAlwaysEmpty = elems.isEmpty
439
439
440
440
def addThisElem (elem : CaptureRef )(using Context , VarState ): CompareResult =
441
- addHiddenElem (elem)
441
+ addIfHiddenOrFail (elem)
442
442
443
443
def addDependent (cs : CaptureSet )(using Context , VarState ) = CompareResult .OK
444
444
@@ -487,7 +487,10 @@ object CaptureSet:
487
487
private var isSolved : Boolean = false
488
488
489
489
/** The elements currently known to be in the set */
490
- var elems : Refs = initialElems
490
+ protected var myElems : Refs = initialElems
491
+
492
+ def elems : Refs = myElems
493
+ def elems_= (refs : Refs ): Unit = myElems = refs
491
494
492
495
/** The sets currently known to be dependent sets (i.e. new additions to this set
493
496
* are propagated to these dependent sets.)
@@ -535,7 +538,7 @@ object CaptureSet:
535
538
536
539
final def addThisElem (elem : CaptureRef )(using Context , VarState ): CompareResult =
537
540
if isConst || ! recordElemsState() then // Fail if variable is solved or given VarState is frozen
538
- addHiddenElem (elem)
541
+ addIfHiddenOrFail (elem)
539
542
else if Existential .isBadExistential(elem) then // Fail if `elem` is an out-of-scope existential
540
543
CompareResult .Fail (this :: Nil )
541
544
else if ! levelOK(elem) then
@@ -925,10 +928,76 @@ object CaptureSet:
925
928
def elemIntersection (cs1 : CaptureSet , cs2 : CaptureSet )(using Context ): Refs =
926
929
cs1.elems.filter(cs2.mightAccountFor) ++ cs2.elems.filter(cs1.mightAccountFor)
927
930
928
- /** A capture set variable used to record the references hidden by a Fresh.Cap instance */
931
+ /** A capture set variable used to record the references hidden by a Fresh.Cap instance,
932
+ * The elems and deps members are repurposed as follows:
933
+ * elems: Set of hidden references
934
+ * deps : Set of hidden sets for which the Fresh.Cap instance owning this set
935
+ * is a hidden element.
936
+ * Hidden sets may become aliases of other hidden sets, which means that
937
+ * reads and writes of elems go to the alias.
938
+ * If H is an alias of R.hidden for some Fresh.Cap R then:
939
+ * H.elems == {R}
940
+ * H.deps = {R.hidden}
941
+ * This encoding was chosen because it relies only on the elems and deps fields
942
+ * which are already subject through snapshotting and rollbacks in VarState.
943
+ * It's advantageous if we don't need to deal with other pieces of state there.
944
+ */
929
945
class HiddenSet (initialHidden : Refs = emptyRefs)(using @ constructorOnly ictx : Context )
930
946
extends Var (initialElems = initialHidden):
931
947
948
+ private def aliasRef : AnnotatedType | Null =
949
+ if myElems.size == 1 then
950
+ myElems.nth(0 ) match
951
+ case al @ Fresh .Cap (hidden) if deps.contains(hidden) => al
952
+ case _ => null
953
+ else null
954
+
955
+ private def aliasSet : HiddenSet =
956
+ if myElems.size == 1 then
957
+ myElems.nth(0 ) match
958
+ case Fresh .Cap (hidden) if deps.contains(hidden) => hidden
959
+ case _ => this
960
+ else this
961
+
962
+ override def elems : Refs =
963
+ val al = aliasSet
964
+ if al eq this then super .elems else al.elems
965
+
966
+ override def elems_= (refs : Refs ) =
967
+ val al = aliasSet
968
+ if al eq this then super .elems_=(refs) else al.elems_=(refs)
969
+
970
+ /** Add element to hidden set. Also add it to all supersets (as indicated by
971
+ * deps of this set). Follow aliases on both hidden set and added element
972
+ * before adding. If the added element is also a Fresh.Cap instance with
973
+ * hidden set H which is a superset of this set, then make this set an
974
+ * alias of H.
975
+ */
976
+ def add (elem : CaptureRef )(using ctx : Context , vs : VarState ): Unit =
977
+ val alias = aliasSet
978
+ if alias ne this then alias.add(elem)
979
+ else
980
+ def addToElems () =
981
+ elems += elem
982
+ deps.foreach: dep =>
983
+ assert(dep != this )
984
+ vs.addHidden(dep.asInstanceOf [HiddenSet ], elem)
985
+ elem match
986
+ case Fresh .Cap (hidden) =>
987
+ if this ne hidden then
988
+ val alias = hidden.aliasRef
989
+ if alias != null then
990
+ add(alias)
991
+ else if deps.contains(hidden) then // make this an alias of elem
992
+ capt.println(i " Alias $this to $hidden" )
993
+ elems = SimpleIdentitySet (elem)
994
+ deps = SimpleIdentitySet (hidden)
995
+ else
996
+ addToElems()
997
+ hidden.deps += this
998
+ case _ =>
999
+ addToElems()
1000
+
932
1001
/** Apply function `f` to `elems` while setting `elems` to empty for the
933
1002
* duration. This is used to escape infinite recursions if two Fresh.Caps
934
1003
* refer to each other in their hidden sets.
@@ -1075,9 +1144,11 @@ object CaptureSet:
1075
1144
*/
1076
1145
def addHidden (hidden : HiddenSet , elem : CaptureRef )(using Context ): Boolean =
1077
1146
elemsMap.get(hidden) match
1078
- case None => elemsMap(hidden) = hidden.elems
1147
+ case None =>
1148
+ elemsMap(hidden) = hidden.elems
1149
+ depsMap(hidden) = hidden.deps
1079
1150
case _ =>
1080
- hidden.elems += elem
1151
+ hidden.add(elem)( using ctx, this )
1081
1152
true
1082
1153
1083
1154
/** Roll back global state to what was recorded in this VarState */
0 commit comments