@@ -23,6 +23,7 @@ import printing.Texts.Text
2323import reporting .{Message , trace }
2424import NameOps .isImpureFunction
2525import annotation .internal .sharable
26+ import collection .immutable
2627
2728/** Capabilities are members of capture sets. They partially overlap with types
2829 * as shown in the trait hierarchy below.
@@ -147,10 +148,30 @@ object Capabilities:
147148 * @param origin an indication where and why the FreshCap was created, used
148149 * for diagnostics
149150 */
150- case class FreshCap (owner : Symbol , origin : Origin )(using @ constructorOnly ctx : Context ) extends RootCapability :
151- val hiddenSet = CaptureSet .HiddenSet (owner, this : @ unchecked)
151+ case class FreshCap (val prefix : Type )
152+ (val owner : Symbol , val origin : Origin , origHidden : CaptureSet .HiddenSet | Null )
153+ (using @ constructorOnly ctx : Context )
154+ extends RootCapability :
155+ val hiddenSet =
156+ if origHidden == null then CaptureSet .HiddenSet (owner, this : @ unchecked)
157+ else origHidden
152158 // fails initialization check without the @unchecked
153159
160+ def derivedFreshCap (newPrefix : Type )(using Context ): FreshCap =
161+ if newPrefix eq prefix then this
162+ else if newPrefix eq hiddenSet.owningCap.prefix then
163+ hiddenSet.owningCap
164+ else
165+ hiddenSet.derivedCaps
166+ .getOrElseUpdate(newPrefix, FreshCap (newPrefix)(owner, origin, hiddenSet))
167+
168+ /** A map from context owners to skolem TermRefs that were created by ensurePath
169+ * TypeMap's mapCapability.
170+ */
171+ var skolems : immutable.Map [Symbol , TermRef ] = immutable.HashMap .empty
172+
173+ // assert(rootId != 10, i"fresh $prefix, ${ctx.owner}")
174+
154175 /** Is this fresh cap (definitely) classified? If that's the case, the
155176 * classifier cannot be changed anymore.
156177 * We need to distinguish `FreshCap`s that can still be classified from
@@ -167,12 +188,6 @@ object Capabilities:
167188 case _ => false
168189
169190 /** Is this fresh cap at the right level to be able to subsume `ref`?
170- * Only outer freshes can be subsumed.
171- * TODO Can we merge this with levelOK? Right now we use two different schemes:
172- * - For level checking capsets with levelOK: Check that the visibility of the element
173- * os not properly contained in the captset owner.
174- * - For level checking elements subsumed by FreshCaps: Check that the widened scope
175- * (using levelOwner) of the elements contains the owner of the FreshCap.
176191 */
177192 def acceptsLevelOf (ref : Capability )(using Context ): Boolean =
178193 if ccConfig.useFreshLevels && ! CCState .collapseFresh then
@@ -203,8 +218,12 @@ object Capabilities:
203218 i " a fresh root capability $classifierStr$originStr"
204219
205220 object FreshCap :
221+ def apply (owner : Symbol , prefix : Type , origin : Origin )(using Context ): FreshCap =
222+ new FreshCap (prefix)(owner, origin, null )
223+ def apply (owner : Symbol , origin : Origin )(using Context ): FreshCap =
224+ apply(owner, owner.skipWeakOwner.thisType, origin)
206225 def apply (origin : Origin )(using Context ): FreshCap =
207- FreshCap (ctx.owner, origin)
226+ apply (ctx.owner, origin)
208227
209228 /** A root capability associated with a function type. These are conceptually
210229 * existentially quantified over the function's result type.
@@ -441,6 +460,7 @@ object Capabilities:
441460 * the form this.C but their pathroot is still this.C, not this.
442461 */
443462 final def pathRoot (using Context ): Capability = this match
463+ case FreshCap (pre : Capability ) => pre.pathRoot
444464 case _ : RootCapability => this
445465 case self : DerivedCapability => self.underlying.pathRoot
446466 case self : CoreCapability => self.dealias match
@@ -485,7 +505,13 @@ object Capabilities:
485505 case TermRef (prefix : Capability , _) => prefix.ccOwner
486506 case self : NamedType => self.symbol
487507 case self : DerivedCapability => self.underlying.ccOwner
488- case self : FreshCap => self.hiddenSet.owner
508+ case self : FreshCap =>
509+ val setOwner = self.hiddenSet.owner
510+ self.prefix match
511+ case prefix : ThisType if setOwner.isTerm && setOwner.owner == prefix.cls =>
512+ setOwner
513+ case prefix : Capability => prefix.ccOwner
514+ case _ => setOwner
489515 case _ /* : GlobalCap | ResultCap | ParamRef */ => NoSymbol
490516
491517 final def visibility (using Context ): Symbol = this match
@@ -732,12 +758,25 @@ object Capabilities:
732758 (this eq y)
733759 || this .match
734760 case x : FreshCap =>
761+ def classifierOK =
762+ if y.tryClassifyAs(x.hiddenSet.classifier) then true
763+ else
764+ capt.println(i " $y cannot be classified as $x" )
765+ false
766+
767+ def prefixAllowsAddHidden : Boolean =
768+ CCState .collapseFresh || x.prefix.match
769+ case NoPrefix => true
770+ case pre : ThisType => x.ccOwner.isContainedIn(pre.cls)
771+ case pre =>
772+ capt.println(i " fresh not open $x, ${x.rootId}, $pre, ${x.ccOwner.skipWeakOwner.thisType}" )
773+ false
774+
735775 vs.ifNotSeen(this )(x.hiddenSet.elems.exists(_.subsumes(y)))
736776 || x.acceptsLevelOf(y)
737- && ( y.tryClassifyAs(x.hiddenSet.classifier)
738- || { capt.println(i " $y cannot be classified as $x" ); false }
739- )
777+ && classifierOK
740778 && canAddHidden
779+ && prefixAllowsAddHidden
741780 && vs.addHidden(x.hiddenSet, y)
742781 case x : ResultCap =>
743782 val result = y match
0 commit comments