@@ -336,15 +336,20 @@ object Capabilities:
336
336
case Maybe (ref1) => ref1.stripReadOnly.maybe
337
337
case _ => this
338
338
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
343
344
case _ => this
344
345
346
+ final def stripRestricted (using Context ): Capability =
347
+ stripRestricted(defn.NothingClass )
348
+
345
349
final def stripReach (using Context ): Capability = this match
346
350
case Reach (ref1) => ref1
347
351
case ReadOnly (ref1) => ref1.stripReach.readOnly
352
+ case Restricted (ref1, cls) => ref1.stripReach.restrict(cls)
348
353
case Maybe (ref1) => ref1.stripReach.maybe
349
354
case _ => this
350
355
@@ -541,6 +546,22 @@ object Capabilities:
541
546
self.classifier.isSubClass(cls)
542
547
&& captureSetOfInfo.tryClassifyAs(cls)
543
548
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
+
544
565
def invalidateCaches () =
545
566
captureSetValid = invalid
546
567
classifiersValid = invalid
@@ -597,6 +618,7 @@ object Capabilities:
597
618
|| viaInfo(y.info)(subsumingRefs(this , _))
598
619
case Maybe (y1) => this .stripMaybe.subsumes(y1)
599
620
case ReadOnly (y1) => this .stripReadOnly.subsumes(y1)
621
+ case Restricted (y1, cls) => this .stripRestricted(cls).subsumes(y1)
600
622
case y : TypeRef if y.derivesFrom(defn.Caps_CapSet ) =>
601
623
// The upper and lower bounds don't have to be in the form of `CapSet^{...}`.
602
624
// They can be other capture set variables, which are bounded by `CapSet`,
@@ -611,6 +633,7 @@ object Capabilities:
611
633
case _ => false
612
634
|| this .match
613
635
case Reach (x1) => x1.subsumes(y.stripReach)
636
+ case Restricted (x1, cls) => y.isKnownClassifiedAs(cls) && x1.subsumes(y)
614
637
case x : TermRef => viaInfo(x.info)(subsumingRefs(_, y))
615
638
case x : TypeRef if assumedContainsOf(x).contains(y) => true
616
639
case x : TypeRef if x.derivesFrom(defn.Caps_CapSet ) =>
@@ -652,7 +675,7 @@ object Capabilities:
652
675
vs.ifNotSeen(this )(x.hiddenSet.elems.exists(_.subsumes(y)))
653
676
|| levelOK
654
677
&& ( 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 }
656
679
)
657
680
&& canAddHidden
658
681
&& vs.addHidden(x.hiddenSet, y)
@@ -674,6 +697,7 @@ object Capabilities:
674
697
case _ =>
675
698
y match
676
699
case ReadOnly (y1) => this .stripReadOnly.maxSubsumes(y1, canAddHidden)
700
+ case Restricted (y1, cls) => this .stripRestricted(cls).maxSubsumes(y1, canAddHidden)
677
701
case _ => false
678
702
679
703
/** `x covers y` if we should retain `y` when computing the overlap of
@@ -718,6 +742,7 @@ object Capabilities:
718
742
val c1 = c.underlying.toType
719
743
c match
720
744
case _ : ReadOnly => ReadOnlyCapability (c1)
745
+ case Restricted (_, cls) => OnlyCapability (c1, cls)
721
746
case _ : Reach => ReachCapability (c1)
722
747
case _ : Maybe => MaybeCapability (c1)
723
748
case _ => c1
0 commit comments