@@ -258,9 +258,11 @@ object Capabilities:
258
258
trait Capability extends Showable :
259
259
260
260
private var myCaptureSet : CaptureSet | Null = uninitialized
261
- private var myCaptureSetValid : Validity = invalid
261
+ private var captureSetValid : Validity = invalid
262
262
private var mySingletonCaptureSet : CaptureSet .Const | Null = null
263
263
private var myDerived : List [DerivedCapability ] = Nil
264
+ private var myClassifiers : Classifiers = UnknownClassifier
265
+ private var classifiersValid : Validity = invalid
264
266
265
267
protected def cached [C <: DerivedCapability ](newRef : C ): C =
266
268
def recur (refs : List [DerivedCapability ]): C = refs match
@@ -292,10 +294,7 @@ object Capabilities:
292
294
case Maybe (ref1) => Maybe (ref1.restrict(cls))
293
295
case ReadOnly (ref1) => ReadOnly (ref1.restrict(cls).asInstanceOf [Restricted ])
294
296
case self @ Restricted (ref1, prevCls) =>
295
- val combinedCls =
296
- if prevCls.isSubClass(cls) then prevCls
297
- else if cls.isSubClass(prevCls) then cls
298
- else defn.NothingClass
297
+ val combinedCls = leastClassifier(prevCls, cls)
299
298
if combinedCls == prevCls then self
300
299
else cached(Restricted (ref1, combinedCls))
301
300
case self : (ObjectCapability | RootCapability | Reach ) => cached(Restricted (self, cls))
@@ -469,7 +468,7 @@ object Capabilities:
469
468
470
469
def derivesFromCapability (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Capability )
471
470
def derivesFromMutable (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Mutable )
472
- def derivesFromSharedCapability (using Context ): Boolean = derivesFromCapTrait(defn.Caps_SharedCapability )
471
+ def derivesFromSharable (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Sharable )
473
472
474
473
/** The capture set consisting of exactly this reference */
475
474
def singletonCaptureSet (using Context ): CaptureSet .Const =
@@ -479,7 +478,7 @@ object Capabilities:
479
478
480
479
/** The capture set of the type underlying this reference */
481
480
def captureSetOfInfo (using Context ): CaptureSet =
482
- if myCaptureSetValid == currentId then myCaptureSet.nn
481
+ if captureSetValid == currentId then myCaptureSet.nn
483
482
else if myCaptureSet.asInstanceOf [AnyRef ] eq CaptureSet .Pending then CaptureSet .empty
484
483
else
485
484
myCaptureSet = CaptureSet .Pending
@@ -491,11 +490,60 @@ object Capabilities:
491
490
myCaptureSet = null
492
491
else
493
492
myCaptureSet = computed
494
- myCaptureSetValid = currentId
493
+ captureSetValid = currentId
495
494
computed
496
495
496
+ /** The transitive classifiers of this capability. */
497
+ def transClassifiers (using Context ): Classifiers =
498
+ def toClassifiers (cls : ClassSymbol ): Classifiers =
499
+ if cls == defn.AnyClass then Unclassified
500
+ else ClassifiedAs (cls :: Nil )
501
+ if classifiersValid != currentId then
502
+ myClassifiers = this match
503
+ case self : FreshCap =>
504
+ toClassifiers(self.hiddenSet.classifier)
505
+ case self : RootCapability =>
506
+ Unclassified
507
+ case Restricted (_, cls) =>
508
+ assert(cls != defn.AnyClass )
509
+ if cls == defn.NothingClass then ClassifiedAs (Nil )
510
+ else ClassifiedAs (cls :: Nil )
511
+ case ReadOnly (ref1) =>
512
+ ref1.transClassifiers
513
+ case Maybe (ref1) =>
514
+ ref1.transClassifiers
515
+ case Reach (_) =>
516
+ captureSetOfInfo.transClassifiers
517
+ case self : CoreCapability =>
518
+ joinClassifiers(toClassifiers(self.classifier), captureSetOfInfo.transClassifiers)
519
+ if myClassifiers != UnknownClassifier then
520
+ classifiersValid == currentId
521
+ myClassifiers
522
+ end transClassifiers
523
+
524
+ def tryClassifyAs (cls : ClassSymbol )(using Context ): Boolean =
525
+ cls == defn.AnyClass
526
+ || this .match
527
+ case self : FreshCap =>
528
+ self.hiddenSet.tryClassifyAs(cls)
529
+ case self : RootCapability =>
530
+ true
531
+ case Restricted (_, cls1) =>
532
+ assert(cls != defn.AnyClass )
533
+ cls1.isSubClass(cls)
534
+ case ReadOnly (ref1) =>
535
+ ref1.tryClassifyAs(cls)
536
+ case Maybe (ref1) =>
537
+ ref1.tryClassifyAs(cls)
538
+ case Reach (_) =>
539
+ captureSetOfInfo.tryClassifyAs(cls)
540
+ case self : CoreCapability =>
541
+ self.classifier.isSubClass(cls)
542
+ && captureSetOfInfo.tryClassifyAs(cls)
543
+
497
544
def invalidateCaches () =
498
- myCaptureSetValid = invalid
545
+ captureSetValid = invalid
546
+ classifiersValid = invalid
499
547
500
548
/** x subsumes x
501
549
* x =:= y ==> x subsumes y
@@ -603,12 +651,15 @@ object Capabilities:
603
651
604
652
vs.ifNotSeen(this )(x.hiddenSet.elems.exists(_.subsumes(y)))
605
653
|| levelOK
654
+ && ( y.tryClassifyAs(x.hiddenSet.classifier)
655
+ || { capt.println(i " $y is not classified as $x" ); false }
656
+ )
606
657
&& canAddHidden
607
658
&& vs.addHidden(x.hiddenSet, y)
608
659
case x : ResultCap =>
609
660
val result = y match
610
661
case y : ResultCap => vs.unify(x, y)
611
- case _ => y.derivesFromSharedCapability
662
+ case _ => y.derivesFromSharable
612
663
if ! result then
613
664
TypeComparer .addErrorNote(CaptureSet .ExistentialSubsumesFailure (x, y))
614
665
result
@@ -618,7 +669,7 @@ object Capabilities:
618
669
case _ : ResultCap => false
619
670
case _ : FreshCap if CCState .collapseFresh => true
620
671
case _ =>
621
- y.derivesFromSharedCapability
672
+ y.derivesFromSharable
622
673
|| canAddHidden && vs != VarState .HardSeparate && CCState .capIsRoot
623
674
case _ =>
624
675
y match
@@ -674,6 +725,39 @@ object Capabilities:
674
725
def toText (printer : Printer ): Text = printer.toTextCapability(this )
675
726
end Capability
676
727
728
+ /** Result type of `transClassifiers`. Interprete as follows:
729
+ * UnknownClassifier: No list could be computed since some capture sets
730
+ * are still unsolved variables
731
+ * Unclassified : No set exists since some parts of tcs are not classified
732
+ * ClassifiedAs(clss: All parts of tcss are classified with classes in clss
733
+ */
734
+ enum Classifiers :
735
+ case UnknownClassifier
736
+ case Unclassified
737
+ case ClassifiedAs (clss : List [ClassSymbol ])
738
+
739
+ export Classifiers .{UnknownClassifier , Unclassified , ClassifiedAs }
740
+
741
+ /** The least classifier between `cls1` and `cls2`, which are either
742
+ * AnyClass, NothingClass, or a class directly extending caps.Classifier.
743
+ * @return if oen of cls1, cls2 is a subclass of the other, the subclass
744
+ * otherwise NothingClass (which is a subclass of all classes)
745
+ */
746
+ def leastClassifier (cls1 : ClassSymbol , cls2 : ClassSymbol )(using Context ): ClassSymbol =
747
+ if cls1.isSubClass(cls2) then cls1
748
+ else if cls2.isSubClass(cls1) then cls2
749
+ else defn.NothingClass
750
+
751
+ def joinClassifiers (cs1 : Classifiers , cs2 : Classifiers )(using Context ): Classifiers =
752
+ // Drop classes that subclass classes of the other set
753
+ def filterSub (cs1 : List [ClassSymbol ], cs2 : List [ClassSymbol ]) =
754
+ cs1.filter(cls1 => ! cs2.exists(cls2 => cls1.isSubClass(cls2)))
755
+ (cs1, cs2) match
756
+ case (Unclassified , _) | (_, Unclassified ) => Unclassified
757
+ case (UnknownClassifier , _) | (_, UnknownClassifier ) => UnknownClassifier
758
+ case (ClassifiedAs (cs1), ClassifiedAs (cs2)) =>
759
+ ClassifiedAs (filterSub(cs1, cs2) ++ filterSub(cs2, cs1))
760
+
677
761
/** The place of - and cause for - creating a fresh capability. Used for
678
762
* error diagnostics
679
763
*/
0 commit comments