@@ -777,7 +777,7 @@ object CaptureSet:
777777 assert(elem.subsumes(elem1),
778778 i " Skipped map ${tm.getClass} maps newly added $elem to $elem1 in $this" )
779779
780- protected def includeElem (elem : Capability )(using Context ): Unit =
780+ protected def includeElem (elem : Capability )(using Context , VarState ): Unit =
781781 if ! elems.contains(elem) then
782782 if debugVars && id == debugTarget then
783783 println(i " ###INCLUDE $elem in $this" )
@@ -803,7 +803,10 @@ object CaptureSet:
803803 // id == 108 then assert(false, i"trying to add $elem to $this")
804804 assert(elem.isWellformed, elem)
805805 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
807810 if isBadRoot(elem) then
808811 rootAddedHandler()
809812 val normElem = if isMaybeSet then elem else elem.stripMaybe
@@ -947,12 +950,64 @@ object CaptureSet:
947950 override def toString = s " Var $id$elems"
948951 end Var
949952
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
9561011
9571012 /** A variable that is derived from some other variable via a map or filter. */
9581013 abstract class DerivedVar (owner : Symbol , initialElems : Refs )(using @ constructorOnly ctx : Context )
@@ -1163,6 +1218,9 @@ object CaptureSet:
11631218 */
11641219 class HiddenSet (initialOwner : Symbol , val owningCap : FreshCap )(using @ constructorOnly ictx : Context )
11651220 extends Var (initialOwner):
1221+
1222+ // Updated by anchorCaps in CheckCaptures, but owner can be changed only
1223+ // if it was NoSymbol before.
11661224 var givenOwner : Symbol = initialOwner
11671225
11681226 override def owner = givenOwner
@@ -1171,62 +1229,9 @@ object CaptureSet:
11711229
11721230 description = i " of elements subsumed by a fresh cap in $initialOwner"
11731231
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. */
12051233 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)
12301235
12311236 /** Apply function `f` to `elems` while setting `elems` to empty for the
12321237 * duration. This is used to escape infinite recursions if two Freshs
@@ -1553,7 +1558,7 @@ object CaptureSet:
15531558 /** The capture set of the type underlying the capability `c` */
15541559 def ofInfo (c : Capability )(using Context ): CaptureSet = c match
15551560 case Reach (c1) =>
1556- c1.widen.deepCaptureSet (includeTypevars = true )
1561+ c1.widen.computeDeepCaptureSet (includeTypevars = true )
15571562 .showing(i " Deep capture set of $c: ${c1.widen} = ${result}" , capt)
15581563 case Restricted (c1, cls) =>
15591564 if cls == defn.NothingClass then CaptureSet .empty
@@ -1615,13 +1620,17 @@ object CaptureSet:
16151620 /** The deep capture set of a type is the union of all covariant occurrences of
16161621 * capture sets. Nested existential sets are approximated with `cap`.
16171622 */
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 =
16191624 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+
16221630 def abstractTypeCase (acc : CaptureSet , t : TypeRef , upperBound : Type ) =
16231631 if includeTypevars && upperBound.isExactlyAny then fresh(Origin .DeepCS (t))
16241632 else this (acc, upperBound)
1633+
16251634 collect(CaptureSet .empty, tp)
16261635
16271636 type AssumedContains = immutable.Map [TypeRef , SimpleIdentitySet [Capability ]]
0 commit comments