@@ -336,15 +336,20 @@ object Capabilities:
336336 case Maybe (ref1) => ref1.stripReadOnly.maybe
337337 case _ => this
338338
339- final def stripRestricted (using Context ): Capability = this match
340- case Restricted (ref1, _) => ref1
341- case ReadOnly (ref1) => ref1.stripRestricted.readOnly
342- case Maybe (ref1) => ref1.stripRestricted.maybe
339+ /** Drop restrictions with clss `cls` or a superclass of `cls` */
340+ final def stripRestricted (cls : ClassSymbol )(using Context ): Capability = this match
341+ case Restricted (ref1, cls1) if cls.isSubClass(cls1) => ref1
342+ case ReadOnly (ref1) => ref1.stripRestricted(cls).readOnly
343+ case Maybe (ref1) => ref1.stripRestricted(cls).maybe
343344 case _ => this
344345
346+ final def stripRestricted (using Context ): Capability =
347+ stripRestricted(defn.NothingClass )
348+
345349 final def stripReach (using Context ): Capability = this match
346350 case Reach (ref1) => ref1
347351 case ReadOnly (ref1) => ref1.stripReach.readOnly
352+ case Restricted (ref1, cls) => ref1.stripReach.restrict(cls)
348353 case Maybe (ref1) => ref1.stripReach.maybe
349354 case _ => this
350355
@@ -541,6 +546,22 @@ object Capabilities:
541546 self.classifier.isSubClass(cls)
542547 && captureSetOfInfo.tryClassifyAs(cls)
543548
549+ def isKnownClassifiedAs (cls : ClassSymbol )(using Context ): Boolean =
550+ transClassifiers match
551+ case ClassifiedAs (cs) => cs.forall(_.isSubClass(cls))
552+ case _ => false
553+
554+ def isKnownEmpty (using Context ): Boolean = this match
555+ case Restricted (ref1, cls) =>
556+ val isEmpty = ref1.transClassifiers match
557+ case ClassifiedAs (cs) =>
558+ cs.forall(c => leastClassifier(c, cls) == defn.NothingClass )
559+ case _ => false
560+ isEmpty || ref1.isKnownEmpty
561+ case ReadOnly (ref1) => ref1.isKnownEmpty
562+ case Maybe (ref1) => ref1.isKnownEmpty
563+ case _ => false
564+
544565 def invalidateCaches () =
545566 captureSetValid = invalid
546567 classifiersValid = invalid
@@ -597,6 +618,7 @@ object Capabilities:
597618 || viaInfo(y.info)(subsumingRefs(this , _))
598619 case Maybe (y1) => this .stripMaybe.subsumes(y1)
599620 case ReadOnly (y1) => this .stripReadOnly.subsumes(y1)
621+ case Restricted (y1, cls) => this .stripRestricted(cls).subsumes(y1)
600622 case y : TypeRef if y.derivesFrom(defn.Caps_CapSet ) =>
601623 // The upper and lower bounds don't have to be in the form of `CapSet^{...}`.
602624 // They can be other capture set variables, which are bounded by `CapSet`,
@@ -611,6 +633,7 @@ object Capabilities:
611633 case _ => false
612634 || this .match
613635 case Reach (x1) => x1.subsumes(y.stripReach)
636+ case Restricted (x1, cls) => y.isKnownClassifiedAs(cls) && x1.subsumes(y)
614637 case x : TermRef => viaInfo(x.info)(subsumingRefs(_, y))
615638 case x : TypeRef if assumedContainsOf(x).contains(y) => true
616639 case x : TypeRef if x.derivesFrom(defn.Caps_CapSet ) =>
@@ -652,7 +675,7 @@ object Capabilities:
652675 vs.ifNotSeen(this )(x.hiddenSet.elems.exists(_.subsumes(y)))
653676 || levelOK
654677 && ( y.tryClassifyAs(x.hiddenSet.classifier)
655- || { capt.println(i " $y is not classified as $x" ); false }
678+ || { capt.println(i " $y cannot be classified as $x" ); false }
656679 )
657680 && canAddHidden
658681 && vs.addHidden(x.hiddenSet, y)
@@ -674,6 +697,7 @@ object Capabilities:
674697 case _ =>
675698 y match
676699 case ReadOnly (y1) => this .stripReadOnly.maxSubsumes(y1, canAddHidden)
700+ case Restricted (y1, cls) => this .stripRestricted(cls).maxSubsumes(y1, canAddHidden)
677701 case _ => false
678702
679703 /** `x covers y` if we should retain `y` when computing the overlap of
@@ -718,6 +742,7 @@ object Capabilities:
718742 val c1 = c.underlying.toType
719743 c match
720744 case _ : ReadOnly => ReadOnlyCapability (c1)
745+ case Restricted (_, cls) => OnlyCapability (c1, cls)
721746 case _ : Reach => ReachCapability (c1)
722747 case _ : Maybe => MaybeCapability (c1)
723748 case _ => c1
0 commit comments