@@ -263,13 +263,19 @@ sealed abstract class CaptureSet extends Showable:
263263 */
264264 def mightAccountFor (x : Capability )(using Context ): Boolean =
265265 reporting.trace(i " $this mightAccountFor $x, ${x.captureSetOfInfo}? " , show = true ):
266- CCState .withCollapsedFresh: // OK here since we opportunistically choose an alternative which gets checked later
266+ CCState .withCollapsedFresh:
267+ // withCollapsedFresh should be dropped. The problem is that since our level checking
268+ // does not deal with classes well, we get false negatives here. Observed in the line
269+ //
270+ // stateFromIteratorConcatSuffix(it)(flatMapImpl(rest, f).state))))
271+ //
272+ // in cc-lib's LazyListIterable.scala.
267273 TypeComparer .noNotes:
268274 elems.exists(_.subsumes(x)(using ctx)(using VarState .ClosedUnrecorded ))
269275 || ! x.isTerminalCapability
270276 && {
271- val elems = x.captureSetOfInfo.elems
272- ! elems .isEmpty && elems .forall(mightAccountFor)
277+ val xelems = x.captureSetOfInfo.elems
278+ ! xelems .isEmpty && xelems .forall(mightAccountFor)
273279 }
274280
275281 /** A more optimistic version of subCaptures used to choose one of two typing rules
@@ -436,9 +442,18 @@ sealed abstract class CaptureSet extends Showable:
436442 def adoptClassifier (cls : ClassSymbol )(using Context ): Unit =
437443 for elem <- elems do
438444 elem.stripReadOnly match
439- case fresh : FreshCap => fresh.hiddenSet. adoptClassifier(cls)
445+ case fresh : FreshCap => fresh.adoptClassifier(cls, freeze = isConst )
440446 case _ =>
441447
448+ /** All capabilities of this set except those Termrefs and FreshCaps that
449+ * are bound by `mt`.
450+ */
451+ def freeInResult (mt : MethodicType )(using Context ): CaptureSet =
452+ filter :
453+ case TermParamRef (binder, _) => binder ne mt
454+ case ResultCap (binder) => binder ne mt
455+ case _ => true
456+
442457 /** A bad root `elem` is inadmissible as a member of this set. What is a bad roots depends
443458 * on the value of `rootLimit`.
444459 * If the limit is null, all capture roots are good.
@@ -611,9 +626,13 @@ object CaptureSet:
611626 then i " under-approximating the result of mapping $ref to $mapped"
612627 else " "
613628
629+ private def capImpliedByCapability (parent : Type )(using Context ): Capability =
630+ if parent.derivesFromExclusive then GlobalCap .readOnly else GlobalCap
631+
614632 /* The same as {cap.rd} but generated implicitly for references of Capability subtypes.
615633 */
616- case class CSImpliedByCapability () extends Const (SimpleIdentitySet (GlobalCap .readOnly))
634+ class CSImpliedByCapability (parent : Type )(using @ constructorOnly ctx : Context )
635+ extends Const (SimpleIdentitySet (capImpliedByCapability(parent)))
617636
618637 /** A special capture set that gets added to the types of symbols that were not
619638 * themselves capture checked, in order to admit arbitrary corresponding capture
@@ -692,6 +711,9 @@ object CaptureSet:
692711 */
693712 private [CaptureSet ] var rootLimit : Symbol | Null = null
694713
714+ def isBadRoot (elem : Capability )(using Context ): Boolean =
715+ isBadRoot(rootLimit, elem)
716+
695717 private var myClassifier : ClassSymbol = defn.AnyClass
696718 def classifier : ClassSymbol = myClassifier
697719
@@ -743,13 +765,14 @@ object CaptureSet:
743765 else if ! levelOK(elem) then
744766 failWith(IncludeFailure (this , elem, levelError = true )) // or `elem` is not visible at the level of the set.
745767 else if ! elem.tryClassifyAs(classifier) then
768+ // println(i"cannot classify $elem as $classifier, ${elem.asInstanceOf[CoreCapability].classifier}")
746769 failWith(IncludeFailure (this , elem))
747770 else
748771 // id == 108 then assert(false, i"trying to add $elem to $this")
749772 assert(elem.isWellformed, elem)
750773 assert(! this .isInstanceOf [HiddenSet ] || summon[VarState ].isSeparating, summon[VarState ])
751774 includeElem(elem)
752- if isBadRoot(rootLimit, elem) then
775+ if isBadRoot(elem) then
753776 rootAddedHandler()
754777 val normElem = if isMaybeSet then elem else elem.stripMaybe
755778 // assert(id != 5 || elems.size != 3, this)
@@ -778,7 +801,7 @@ object CaptureSet:
778801 case _ => foldOver(b, t)
779802 find(false , binder)
780803
781- private def levelOK (elem : Capability )(using Context ): Boolean = elem match
804+ def levelOK (elem : Capability )(using Context ): Boolean = elem match
782805 case _ : FreshCap =>
783806 ! level.isDefined
784807 || ccState.symLevel(elem.ccOwner) <= level
@@ -1246,7 +1269,13 @@ object CaptureSet:
12461269 * when a subsumes check decides that an existential variable `ex` cannot be
12471270 * instantiated to the other capability `other`.
12481271 */
1249- case class ExistentialSubsumesFailure (val ex : ResultCap , val other : Capability ) extends ErrorNote
1272+ case class ExistentialSubsumesFailure (val ex : ResultCap , val other : Capability ) extends ErrorNote :
1273+ def description (using Context ): String =
1274+ def reason =
1275+ if other.isTerminalCapability then " "
1276+ else " since that capability is not a `Sharable` capability"
1277+ i """ the existential capture root in ${ex.originalBinder.resType}
1278+ |cannot subsume the capability $other$reason. """
12501279
12511280 /** Failure indicating that `elem` cannot be included in `cs` */
12521281 case class IncludeFailure (cs : CaptureSet , elem : Capability , levelError : Boolean = false ) extends ErrorNote , Showable :
@@ -1258,6 +1287,38 @@ object CaptureSet:
12581287 res.myTrace = cs1 :: this .myTrace
12591288 res
12601289
1290+ def description (using Context ): String =
1291+ def why =
1292+ val reasons = cs.elems.toList.collect:
1293+ case c : FreshCap if ! c.acceptsLevelOf(elem) =>
1294+ i " $elem${elem.levelOwner.qualString(" in" )} is not visible from $c${c.ccOwner.qualString(" in" )}"
1295+ case c : FreshCap if ! elem.tryClassifyAs(c.hiddenSet.classifier) =>
1296+ i " $c is classified as ${c.hiddenSet.classifier} but $elem is not "
1297+ if reasons.isEmpty then " "
1298+ else reasons.mkString(" \n because " , " \n and " , " " )
1299+ cs match
1300+ case cs : Var =>
1301+ if ! cs.levelOK(elem) then
1302+ val levelStr = elem match
1303+ case ref : TermRef => i " , defined in ${ref.symbol.maybeOwner}"
1304+ case _ => " "
1305+ i """ capability ${elem}$levelStr
1306+ |cannot be included in outer capture set $cs"""
1307+ else if ! elem.tryClassifyAs(cs.classifier) then
1308+ i """ capability ${elem} is not classified as ${cs.classifier}, therefore it
1309+ |cannot be included in capture set $cs of ${cs.classifier} elements """
1310+ else if cs.isBadRoot(elem) then
1311+ elem match
1312+ case elem : FreshCap =>
1313+ i """ local capability $elem created in ${elem.ccOwner}
1314+ |cannot be included in outer capture set $cs"""
1315+ case _ =>
1316+ i " universal capability $elem cannot be included in capture set $cs"
1317+ else
1318+ i " capability $elem cannot be included in capture set $cs"
1319+ case _ =>
1320+ i " capability $elem is not included in capture set $cs$why"
1321+
12611322 override def toText (printer : Printer ): Text =
12621323 inContext(printer.printerContext):
12631324 if levelError then
@@ -1274,7 +1335,11 @@ object CaptureSet:
12741335 * @param lo the lower type of the orginal type comparison, or NoType if not known
12751336 * @param hi the upper type of the orginal type comparison, or NoType if not known
12761337 */
1277- case class MutAdaptFailure (cs : CaptureSet , lo : Type = NoType , hi : Type = NoType ) extends ErrorNote
1338+ case class MutAdaptFailure (cs : CaptureSet , lo : Type = NoType , hi : Type = NoType ) extends ErrorNote :
1339+ def description (using Context ): String =
1340+ def ofType (tp : Type ) = if tp.exists then i " of the mutable type $tp" else " of a mutable type"
1341+ i """ $cs is an exclusive capture set ${ofType(hi)},
1342+ |it cannot subsume a read-only capture set ${ofType(lo)}. """
12781343
12791344 /** A VarState serves as a snapshot mechanism that can undo
12801345 * additions of elements or super sets if an operation fails
@@ -1487,14 +1552,10 @@ object CaptureSet:
14871552 // `ref` will not seem subsumed by other capabilities in a `++`.
14881553 universal
14891554 case c : CoreCapability =>
1490- ofType(c.underlying, followResult = false )
1555+ ofType(c.underlying, followResult = true )
14911556
14921557 /** Capture set of a type
14931558 * @param followResult If true, also include capture sets of function results.
1494- * This mode is currently not used. It could be interesting
1495- * when we change the system so that the capture set of a function
1496- * is the union of the capture sets if its span.
1497- * In this case we should use `followResult = true` in the call in ofInfo above.
14981559 */
14991560 def ofType (tp : Type , followResult : Boolean )(using Context ): CaptureSet =
15001561 def recur (tp : Type ): CaptureSet = trace(i " ofType $tp, ${tp.getClass} $followResult" , show = true ):
@@ -1510,13 +1571,9 @@ object CaptureSet:
15101571 recur(parent) ++ refs
15111572 case tp @ AnnotatedType (parent, ann) if ann.symbol.isRetains =>
15121573 recur(parent) ++ ann.tree.toCaptureSet
1513- case tpd @ defn.RefinedFunctionOf (rinfo : MethodType ) if followResult =>
1574+ case tpd @ defn.RefinedFunctionOf (rinfo : MethodOrPoly ) if followResult =>
15141575 ofType(tpd.parent, followResult = false ) // pick up capture set from parent type
1515- ++ recur(rinfo.resType) // add capture set of result
1516- .filter:
1517- case TermParamRef (binder, _) => binder ne rinfo
1518- case ResultCap (binder) => binder ne rinfo
1519- case _ => true
1576+ ++ recur(rinfo.resType).freeInResult(rinfo) // add capture set of result
15201577 case tpd @ AppliedType (tycon, args) =>
15211578 if followResult && defn.isNonRefinedFunction(tpd) then
15221579 recur(args.last)
0 commit comments