@@ -761,7 +761,6 @@ object CaptureSet:
761761
762762 if debugVars && id == debugTarget then
763763 println(i " ###INIT ELEMS of $id of class $getClass in $initialOwner, $nestedOK to $initialElems" )
764- assert(false )
765764
766765 def elems : Refs = myElems
767766 def elems_= (refs : Refs ): Unit =
@@ -1029,63 +1028,72 @@ object CaptureSet:
10291028 end Var
10301029
10311030 /** Variables created in types of inferred type trees */
1032- class ProperVar (override val owner : Symbol , initialElems : Refs = emptyRefs, nestedOK : Boolean = true , isRefining : Boolean )(using /* @constructorOnly*/ ictx : Context )
1033- extends Var (owner, initialElems, nestedOK):
1031+ class VarInTypeTree (override val owner : Symbol , initialElems : Refs = emptyRefs, val nestedOK : Boolean = true , isRefining : Boolean )(using /* @constructorOnly*/ ictx : Context )
1032+ extends Var (owner, initialElems, nestedOK) {
10341033
10351034 /** Make sure that capset variables in types of vals and result types of
10361035 * non-anonymous functions contain only a single LocalCap, and furthermore
10371036 * that that LocalCap has as origin InDecl(owner), where owner is the val
1038- * or def for which the type is defined.
1037+ * or def for which the type is defined. If the capture set does not satisfy
1038+ * this condition, create a LocalCap with the right origin and move other
1039+ * LocalCaps to its hidden set.
10391040 * Note: This currently does not apply to classified or read-only LocalCaps.
10401041 */
1041- override def includeElem (elem : Capability )(using ctx : Context , vs : VarState ): Unit = elem match
1042- case elem : LocalCap
1043- if ! nestedOK
1044- && ! elems.contains(elem)
1045- && ! owner.isAnonymousFunction =>
1046- def fail = i " attempting to add $elem to $this"
1047- def hideIn (ac : LocalCap ): Boolean =
1048- assert(elem.tryClassifyAs(ac.hiddenSet.classifier), fail)
1049- if isRefining then
1050- // If a variable is added by addCaptureRefinements in a synthetic
1051- // refinement of a class type, don't do level checking. The problem is
1052- // that the variable might be matched against a type that does not have
1053- // a refinement, in which case LocalCaps of the class definition would
1054- // leak out in the corresponding places. This will fail level checking.
1055- // The disallowBadRoots override below has a similar reason.
1056- // TODO: We should instead mark the variable as impossible to instantiate
1057- // and drop the refinement later in the inferred type.
1058- // Test case is drop-refinement.scala.
1059- true
1060- else if ac.acceptsLevelOf(elem) then
1061- ac.hiddenSet.add(elem)
1062- true
1063- else
1064- capt.println(i " level failure when subsuming in a LocalCap, cannot add $elem with ${elem.levelOwner} to $owner / $fail" )
1065- false
1066- val isSubsumed = (false /: elems): (isSubsumed, prev) =>
1067- prev match
1068- case prev : LocalCap => hideIn(prev)
1069- case _ => isSubsumed
1070- if ! isSubsumed then
1071- if elem.origin != Origin .InDecl (owner) || elem.hiddenSet.isConst then
1072- val fc = LocalCap (owner, Origin .InDecl (owner, elem.origin.contributingFields))
1073- assert(fc.tryClassifyAs(elem.hiddenSet.classifier), fail)
1074- hideIn(fc)
1075- super .includeElem(fc)
1076- else
1077- super .includeElem(elem)
1078- case _ =>
1079- super .includeElem(elem)
1042+ def normalizeLocalCaps ()(using ctx : Context ): Unit =
1043+ if ! nestedOK && ! owner.isAnonymousFunction then
1044+ var inDeclRoots = elems.filter:
1045+ case elem : LocalCap => elem.origin == Origin .InDecl (owner)
1046+ case _ => false
1047+ val oldElems = elems
1048+ elems = inDeclRoots
1049+ given VarState = VarState .Closed ()
1050+ for elem <- oldElems do {
1051+ def fail = i " attempting to add $elem to $this"
1052+
1053+ def hideIn (ac : LocalCap ): Boolean =
1054+ assert(elem.tryClassifyAs(ac.hiddenSet.classifier), fail)
1055+ if isRefining then
1056+ // If a variable is added by addCaptureRefinements in a synthetic
1057+ // refinement of a class type, don't do level checking. The problem is
1058+ // that the variable might be matched against a type that does not have
1059+ // a refinement, in which case LocalCaps of the class definition would
1060+ // leak out in the corresponding places. This will fail level checking.
1061+ // The disallowBadRoots override below has a similar reason.
1062+ // TODO: We should instead mark the variable as impossible to instantiate
1063+ // and drop the refinement later in the inferred type.
1064+ // Test case is drop-refinement.scala.
1065+ true
1066+ else if ac.acceptsLevelOf(elem) then
1067+ ac.hiddenSet.add(elem)
1068+ true
1069+ else
1070+ capt.println(i " level failure when subsuming in a LocalCap, cannot add $elem with ${elem.levelOwner} to $owner / $fail" )
1071+ false
1072+
1073+ elem match
1074+ case elem : LocalCap =>
1075+ if elem.origin != Origin .InDecl (owner) then
1076+ val isSubsumed = (false /: inDeclRoots): (isSubsumed, root) =>
1077+ hideIn(root.asInstanceOf [LocalCap ])
1078+ if ! isSubsumed then
1079+ val fc = LocalCap (owner, Origin .InDecl (owner, elem.origin.contributingFields))
1080+ assert(fc.tryClassifyAs(elem.hiddenSet.classifier), fail)
1081+ if hideIn(fc) then
1082+ inDeclRoots += fc
1083+ elems += fc
1084+ else
1085+ elems += elem
1086+ case _ =>
1087+ elems += elem
1088+ }
10801089
10811090 /** Variables that represent refinements of class parameters can have the universal
10821091 * capture set, since they represent only what is the result of the constructor.
10831092 * Test case: Without that tweak, logger.scala would not compile.
10841093 */
10851094 override def disallowBadRoots (upto : Symbol )(handler : () => Context ?=> Unit )(using Context ) =
10861095 if ! isRefining then super .disallowBadRoots(upto)(handler)
1087-
1088- end ProperVar
1096+ }
10891097
10901098 /** A variable that is derived from some other variable via a map or filter. */
10911099 abstract class DerivedVar (owner : Symbol , initialElems : Refs )(using @ constructorOnly ctx : Context )
0 commit comments