@@ -777,7 +777,7 @@ object CaptureSet:
777
777
assert(elem.subsumes(elem1),
778
778
i " Skipped map ${tm.getClass} maps newly added $elem to $elem1 in $this" )
779
779
780
- protected def includeElem (elem : Capability )(using Context ): Unit =
780
+ protected def includeElem (elem : Capability )(using Context , VarState ): Unit =
781
781
if ! elems.contains(elem) then
782
782
if debugVars && id == debugTarget then
783
783
println(i " ###INCLUDE $elem in $this" )
@@ -803,7 +803,10 @@ object CaptureSet:
803
803
// id == 108 then assert(false, i"trying to add $elem to $this")
804
804
assert(elem.isWellformed, elem)
805
805
assert(! this .isInstanceOf [HiddenSet ] || summon[VarState ].isSeparating, summon[VarState ])
806
- includeElem(elem)
806
+ try includeElem(elem)
807
+ catch case ex : AssertionError =>
808
+ println(i " error for incl $elem in $this, ${summon[VarState ].toString}" )
809
+ throw ex
807
810
if isBadRoot(elem) then
808
811
rootAddedHandler()
809
812
val normElem = if isMaybeSet then elem else elem.stripMaybe
@@ -947,12 +950,64 @@ object CaptureSet:
947
950
override def toString = s " Var $id$elems"
948
951
end Var
949
952
950
- /** Variables that represent refinements of class parameters can have the universal
951
- * capture set, since they represent only what is the result of the constructor.
952
- * Test case: Without that tweak, logger.scala would not compile.
953
- */
954
- class RefiningVar (owner : Symbol )(using Context ) extends Var (owner):
955
- override def disallowBadRoots (upto : Symbol )(handler : () => Context ?=> Unit )(using Context ) = this
953
+ /** Variables created in types of inferred type trees */
954
+ class ProperVar (override val owner : Symbol , initialElems : Refs = emptyRefs, nestedOK : Boolean = true , isRefining : Boolean )(using /* @constructorOnly*/ ictx : Context )
955
+ extends Var (owner, initialElems, nestedOK):
956
+
957
+ /** Make sure that capset variables in types of vals and result types of
958
+ * non-anonymous functions contain only a single FreshCap, and furthermore
959
+ * that that FreshCap has as origin InDecl(owner), where owner is the val
960
+ * or def for which the type is defined.
961
+ * Note: This currently does not apply to classified or read-only fresh caps.
962
+ */
963
+ override def includeElem (elem : Capability )(using ctx : Context , vs : VarState ): Unit = elem match
964
+ case elem : FreshCap
965
+ if ! nestedOK
966
+ && ! elems.contains(elem)
967
+ && ! owner.isAnonymousFunction
968
+ && ccConfig.newScheme =>
969
+ def fail = i " attempting to add $elem to $this"
970
+ def hideIn (fc : FreshCap ): Unit =
971
+ assert(elem.tryClassifyAs(fc.hiddenSet.classifier), fail)
972
+ if ! isRefining then
973
+ // If a variable is added by addCaptureRefinements in a synthetic
974
+ // refinement of a class type, don't do level checking. The problem is
975
+ // that the variable might be matched against a type that does not have
976
+ // a refinement, in which case FreshCaps of the class definition would
977
+ // leak out in the corresponding places. This will fail level checking.
978
+ // The disallowBadRoots override below has a similar reason.
979
+ // TODO: We should instead mark the variable as impossible to instantiate
980
+ // and drop the refinement later in the inferred type.
981
+ // Test case is drop-refinement.scala.
982
+ assert(fc.acceptsLevelOf(elem),
983
+ i " level failure, cannot add $elem with ${elem.levelOwner} to $owner / $getClass / $fail" )
984
+ fc.hiddenSet.add(elem)
985
+ val isSubsumed = (false /: elems): (isSubsumed, prev) =>
986
+ prev match
987
+ case prev : FreshCap =>
988
+ hideIn(prev)
989
+ true
990
+ case _ => isSubsumed
991
+ if ! isSubsumed then
992
+ if elem.origin != Origin .InDecl (owner) || elem.hiddenSet.isConst then
993
+ val fc = new FreshCap (owner, Origin .InDecl (owner))
994
+ assert(fc.tryClassifyAs(elem.hiddenSet.classifier), fail)
995
+ hideIn(fc)
996
+ super .includeElem(fc)
997
+ else
998
+ super .includeElem(elem)
999
+ case _ =>
1000
+ super .includeElem(elem)
1001
+
1002
+ /** Variables that represent refinements of class parameters can have the universal
1003
+ * capture set, since they represent only what is the result of the constructor.
1004
+ * Test case: Without that tweak, logger.scala would not compile.
1005
+ */
1006
+ override def disallowBadRoots (upto : Symbol )(handler : () => Context ?=> Unit )(using Context ) =
1007
+ if isRefining then this
1008
+ else super .disallowBadRoots(upto)(handler)
1009
+
1010
+ end ProperVar
956
1011
957
1012
/** A variable that is derived from some other variable via a map or filter. */
958
1013
abstract class DerivedVar (owner : Symbol , initialElems : Refs )(using @ constructorOnly ctx : Context )
@@ -1163,6 +1218,9 @@ object CaptureSet:
1163
1218
*/
1164
1219
class HiddenSet (initialOwner : Symbol , val owningCap : FreshCap )(using @ constructorOnly ictx : Context )
1165
1220
extends Var (initialOwner):
1221
+
1222
+ // Updated by anchorCaps in CheckCaptures, but owner can be changed only
1223
+ // if it was NoSymbol before.
1166
1224
var givenOwner : Symbol = initialOwner
1167
1225
1168
1226
override def owner = givenOwner
@@ -1171,62 +1229,9 @@ object CaptureSet:
1171
1229
1172
1230
description = i " of elements subsumed by a fresh cap in $initialOwner"
1173
1231
1174
- private def aliasRef : FreshCap | Null =
1175
- if myElems.size == 1 then
1176
- myElems.nth(0 ) match
1177
- case alias : FreshCap if deps.contains(alias.hiddenSet) => alias
1178
- case _ => null
1179
- else null
1180
-
1181
- private def aliasSet : HiddenSet =
1182
- if myElems.size == 1 then
1183
- myElems.nth(0 ) match
1184
- case alias : FreshCap if deps.contains(alias.hiddenSet) => alias.hiddenSet
1185
- case _ => this
1186
- else this
1187
-
1188
- def superCaps : List [FreshCap ] =
1189
- deps.toList.map(_.asInstanceOf [HiddenSet ].owningCap)
1190
-
1191
- override def elems : Refs =
1192
- val al = aliasSet
1193
- if al eq this then super .elems else al.elems
1194
-
1195
- override def elems_= (refs : Refs ) =
1196
- val al = aliasSet
1197
- if al eq this then super .elems_=(refs) else al.elems_=(refs)
1198
-
1199
- /** Add element to hidden set. Also add it to all supersets (as indicated by
1200
- * deps of this set). Follow aliases on both hidden set and added element
1201
- * before adding. If the added element is also a Fresh instance with
1202
- * hidden set H which is a superset of this set, then make this set an
1203
- * alias of H.
1204
- */
1232
+ /** Add element to hidden set. */
1205
1233
def add (elem : Capability )(using ctx : Context , vs : VarState ): Unit =
1206
- val alias = aliasSet
1207
- if alias ne this then alias.add(elem)
1208
- else
1209
- def addToElems () =
1210
- assert(! isConst)
1211
- includeElem(elem)
1212
- deps.foreach: dep =>
1213
- assert(dep != this )
1214
- vs.addHidden(dep.asInstanceOf [HiddenSet ], elem)
1215
- elem match
1216
- case elem : FreshCap =>
1217
- if this ne elem.hiddenSet then
1218
- val alias = elem.hiddenSet.aliasRef
1219
- if alias != null then
1220
- add(alias)
1221
- else if deps.contains(elem.hiddenSet) then // make this an alias of elem
1222
- capt.println(i " Alias $this to ${elem.hiddenSet}" )
1223
- elems = SimpleIdentitySet (elem)
1224
- deps = SimpleIdentitySet (elem.hiddenSet)
1225
- else
1226
- addToElems()
1227
- elem.hiddenSet.includeDep(this )
1228
- case _ =>
1229
- addToElems()
1234
+ includeElem(elem)
1230
1235
1231
1236
/** Apply function `f` to `elems` while setting `elems` to empty for the
1232
1237
* duration. This is used to escape infinite recursions if two Freshs
@@ -1553,7 +1558,7 @@ object CaptureSet:
1553
1558
/** The capture set of the type underlying the capability `c` */
1554
1559
def ofInfo (c : Capability )(using Context ): CaptureSet = c match
1555
1560
case Reach (c1) =>
1556
- c1.widen.deepCaptureSet (includeTypevars = true )
1561
+ c1.widen.computeDeepCaptureSet (includeTypevars = true )
1557
1562
.showing(i " Deep capture set of $c: ${c1.widen} = ${result}" , capt)
1558
1563
case Restricted (c1, cls) =>
1559
1564
if cls == defn.NothingClass then CaptureSet .empty
@@ -1615,13 +1620,17 @@ object CaptureSet:
1615
1620
/** The deep capture set of a type is the union of all covariant occurrences of
1616
1621
* capture sets. Nested existential sets are approximated with `cap`.
1617
1622
*/
1618
- def ofTypeDeeply (tp : Type , includeTypevars : Boolean = false )(using Context ): CaptureSet =
1623
+ def ofTypeDeeply (tp : Type , includeTypevars : Boolean = false , includeBoxed : Boolean = true )(using Context ): CaptureSet =
1619
1624
val collect = new DeepTypeAccumulator [CaptureSet ]:
1620
- def capturingCase (acc : CaptureSet , parent : Type , refs : CaptureSet ) =
1621
- this (acc, parent) ++ refs
1625
+
1626
+ def capturingCase (acc : CaptureSet , parent : Type , refs : CaptureSet , boxed : Boolean ) =
1627
+ if includeBoxed || ! boxed then this (acc, parent) ++ refs
1628
+ else this (acc, parent)
1629
+
1622
1630
def abstractTypeCase (acc : CaptureSet , t : TypeRef , upperBound : Type ) =
1623
1631
if includeTypevars && upperBound.isExactlyAny then fresh(Origin .DeepCS (t))
1624
1632
else this (acc, upperBound)
1633
+
1625
1634
collect(CaptureSet .empty, tp)
1626
1635
1627
1636
type AssumedContains = immutable.Map [TypeRef , SimpleIdentitySet [Capability ]]
0 commit comments