@@ -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
@@ -665,6 +691,8 @@ object Capabilities:
665691
666692 try (this eq y)
667693 || maxSubsumes(y, canAddHidden = ! vs.isOpen)
694+ // if vs is open, we should add new elements to the set containing `this`
695+ // instead of adding them to the hidden set of of `this`.
668696 || y.match
669697 case y : TermRef =>
670698 y.prefix.match
@@ -732,12 +760,26 @@ object Capabilities:
732760 (this eq y)
733761 || this .match
734762 case x : FreshCap =>
763+ def classifierOK =
764+ if y.tryClassifyAs(x.hiddenSet.classifier) then true
765+ else
766+ capt.println(i " $y cannot be classified as $x" )
767+ false
768+ 769+ def prefixAllowsAddHidden : Boolean =
770+ CCState .collapseFresh || x.prefix.match
771+ case NoPrefix => true
772+ case pre : ThisType => x.ccOwner.isContainedIn(pre.cls)
773+ case pre =>
774+ capt.println(i " fresh not open $x, ${x.rootId}, $pre, ${x.ccOwner.skipWeakOwner.thisType}" )
775+ false
776+ 735777 vs.ifNotSeen(this )(x.hiddenSet.elems.exists(_.subsumes(y)))
778+ || x.coversFresh(y)
736779 || x.acceptsLevelOf(y)
737- && ( y.tryClassifyAs(x.hiddenSet.classifier)
738- || { capt.println(i " $y cannot be classified as $x" ); false }
739- )
780+ && classifierOK
740781 && canAddHidden
782+ && prefixAllowsAddHidden
741783 && vs.addHidden(x.hiddenSet, y)
742784 case x : ResultCap =>
743785 val result = y match
@@ -800,15 +842,39 @@ object Capabilities:
800842 case _ =>
801843 false
802844 || x.match
803- case x : FreshCap if ! seen.contains(x) =>
804- seen.add(x)
805- x.hiddenSet.exists(recur(_, y))
845+ case x : FreshCap =>
846+ if x.coversFresh(y) then true
847+ else if ! seen.contains(x) then
848+ seen.add(x)
849+ x.hiddenSet.exists(recur(_, y))
850+ else false
806851 case Restricted (x1, _) => recur(x1, y)
807852 case _ => false
808853
809854 recur(this , y)
810855 end covers
811856
857+ /** `x eq y` or `x` is a fresh cap, `y` is a fresh cap with prefix
858+ * `p`, and there is a prefix of `p` that contains `x` in its
859+ * capture set.
860+ */
861+ final def coversFresh (y : Capability )(using Context ): Boolean =
862+ (this eq y) || this .match
863+ case x : FreshCap => y match
864+ case y : FreshCap =>
865+ x.origin match
866+ case Origin .InDecl (sym) =>
867+ def occursInPrefix (pre : Type ): Boolean = pre match
868+ case pre @ TermRef (pre1, _) =>
869+ pre.symbol == sym
870+ && pre.info.captureSet.elems.contains(x)
871+ || occursInPrefix(pre1)
872+ case _ => false
873+ occursInPrefix(y.prefix)
874+ case _ => false
875+ case _ => false
876+ case _ => false
877+ 812878 def assumedContainsOf (x : TypeRef )(using Context ): SimpleIdentitySet [Capability ] =
813879 CaptureSet .assumedContains.getOrElse(x, SimpleIdentitySet .empty)
814880
@@ -857,18 +923,26 @@ object Capabilities:
857923 else if cls2.isSubClass(cls1) then cls2
858924 else defn.NothingClass
859925
860- def joinClassifiers (cs1 : Classifiers , cs2 : Classifiers )(using Context ): Classifiers =
926+ /** The smallest list D of class symbols in cs1 and cs2 such that
927+ * every class symbol in cs1 and cs2 is a subclass of a class symbol in D
928+ */
929+ def dominators (cs1 : List [ClassSymbol ], cs2 : List [ClassSymbol ])(using Context ): List [ClassSymbol ] =
861930 // Drop classes that subclass classes of the other set
862931 // @param proper If true, only drop proper subclasses of a class of the other set
863932 def filterSub (cs1 : List [ClassSymbol ], cs2 : List [ClassSymbol ], proper : Boolean ) =
864933 cs1.filter: cls1 =>
865934 ! cs2.exists: cls2 =>
866935 cls1.isSubClass(cls2) && (! proper || cls1 != cls2)
936+ filterSub(cs1, cs2, proper = true ) ++ filterSub(cs2, cs1, proper = false )
937+ 938+ def joinClassifiers (cs1 : Classifiers , cs2 : Classifiers )(using Context ): Classifiers =
867939 (cs1, cs2) match
868- case (Unclassified , _) | (_, Unclassified ) => Unclassified
869- case (UnknownClassifier , _) | (_, UnknownClassifier ) => UnknownClassifier
940+ case (Unclassified , _) | (_, Unclassified ) =>
941+ Unclassified
942+ case (UnknownClassifier , _) | (_, UnknownClassifier ) =>
943+ UnknownClassifier
870944 case (ClassifiedAs (cs1), ClassifiedAs (cs2)) =>
871- ClassifiedAs (filterSub (cs1, cs2, proper = true ) ++ filterSub(cs2, cs1, proper = false ))
945+ ClassifiedAs (dominators (cs1, cs2))
872946
873947 /** The place of - and cause for - creating a fresh capability. Used for
874948 * error diagnostics
@@ -881,7 +955,7 @@ object Capabilities:
881955 case ResultInstance (methType : Type , meth : Symbol )
882956 case UnapplyInstance (info : MethodType )
883957 case LocalInstance (restpe : Type )
884- case NewMutable (tp : Type )
958+ case NewInstance (tp : Type )
885959 case NewCapability (tp : Type )
886960 case LambdaExpected (respt : Type )
887961 case LambdaActual (restp : Type )
@@ -911,10 +985,11 @@ object Capabilities:
911985 i " when instantiating argument of unapply with type $info"
912986 case LocalInstance (restpe) =>
913987 i " when instantiating expected result type $restpe of function literal "
914- case NewMutable (tp) =>
915- i " when constructing mutable $tp"
988+ case NewInstance (tp) =>
989+ i " when constructing instance $tp"
916990 case NewCapability (tp) =>
917- i " when constructing Capability instance $tp"
991+ val kind = if tp.derivesFromMutable then " mutable" else " Capability instance"
992+ i " when constructing $kind$tp"
918993 case LambdaExpected (respt) =>
919994 i " when instantiating expected result type $respt of lambda "
920995 case LambdaActual (restp : Type ) =>
0 commit comments