@@ -90,33 +90,33 @@ object Capabilities:
9090 */
9191 case class Maybe (underlying : Capability ) extends DerivedCapability
9292
93+ /** The readonly capability `x.rd`. We have {x.rd} <: {x}.
94+ *
95+ * Read-only capabilities cannot wrap maybe capabilities
96+ * but they can wrap reach capabilities. We have
97+ * (x?).readOnly = (x.rd)?
98+ */
99+ case class ReadOnly (underlying : CoreCapability | RootCapability | Reach | Restricted )
100+ extends DerivedCapability
101+
93102 /** The restricted capability `x.only[C]`. We have {x.only[C]} <: {x}.
94103 *
95- * Restricted capabilities cannot wrap maybe capabilities
104+ * Restricted capabilities cannot wrap maybe capabilities or read-only capabilities
96105 * but they can wrap reach capabilities. We have
97106 * (x?).restrict[T] = (x.restrict[T])?
98107 * (x.rd).restrict[T] = (x.restrict[T]).rd
99108 */
100109 case class Restricted (underlying : CoreCapability | RootCapability | Reach , cls : ClassSymbol )
101110 extends DerivedCapability
102111
103- /** An extractor for the read-only capability `x.rd`. `x.rd` is represented as
104- * `c.only[caps.Read]`.
105- */
106- object ReadOnly :
107- def apply (underlying : CoreCapability | RootCapability | Reach | Restricted )(using Context ): Restricted =
108- Restricted (underlying.stripRestricted.asInstanceOf , defn.Caps_Read )
109- def unapply (ref : Restricted )(using Context ): Option [CoreCapability | RootCapability | Reach ] =
110- if ref.cls == defn.Caps_Read then Some (ref.underlying) else None
111-
112112 /** If `x` is a capability, its reach capability `x*`. `x*` stands for all
113113 * capabilities reachable through `x`.
114114 * We have `{x} <: {x*} <: dcs(x)}` where the deep capture set `dcs(x)` of `x`
115115 * is the union of all capture sets that appear in covariant position in the
116116 * type of `x`. If `x` and `y` are different variables then `{x*}` and `{y*}`
117117 * are unrelated.
118118 *
119- * Reach capabilities cannot wrap restricted capabilities or maybe capabilities.
119+ * Reach capabilities cannot wrap read-only capabilities or maybe capabilities.
120120 * We have
121121 * (x?).reach = (x.reach)?
122122 * (x.rd).reach = (x.reach).rd
@@ -132,7 +132,7 @@ object Capabilities:
132132 object GlobalCap extends RootCapability :
133133 def descr (using Context ) = " the universal root capability"
134134 override val maybe = Maybe (this )
135- override def readOnly ( using Context ) = ReadOnly (this )
135+ override val readOnly = ReadOnly (this )
136136 override def restrict (cls : ClassSymbol )(using Context ) = Restricted (this , cls)
137137 override def reach = unsupported(" cap.reach" )
138138 override def singletonCaptureSet (using Context ) = CaptureSet .universal
@@ -347,21 +347,23 @@ object Capabilities:
347347 case self : Maybe => self
348348 case _ => cached(Maybe (this ))
349349
350- def readOnly ( using Context ) : Restricted | Maybe = this match
350+ def readOnly : ReadOnly | Maybe = this match
351351 case Maybe (ref1) => Maybe (ref1.readOnly)
352- case self @ ReadOnly (_) => self
352+ case self : ReadOnly => self
353353 case self : (CoreCapability | RootCapability | Reach | Restricted ) => cached(ReadOnly (self))
354354
355- def restrict (cls : ClassSymbol )(using Context ): Restricted | Maybe = this match
355+ def restrict (cls : ClassSymbol )(using Context ): Restricted | ReadOnly | Maybe = this match
356356 case Maybe (ref1) => Maybe (ref1.restrict(cls))
357+ case ReadOnly (ref1) => ReadOnly (ref1.restrict(cls).asInstanceOf [Restricted ])
357358 case self @ Restricted (ref1, prevCls) =>
358359 val combinedCls = leastClassifier(prevCls, cls)
359360 if combinedCls == prevCls then self
360361 else cached(Restricted (ref1, combinedCls))
361362 case self : (CoreCapability | RootCapability | Reach ) => cached(Restricted (self, cls))
362363
363- def reach : Reach | Restricted | Maybe = this match
364+ def reach : Reach | Restricted | ReadOnly | Maybe = this match
364365 case Maybe (ref1) => Maybe (ref1.reach)
366+ case ReadOnly (ref1) => ReadOnly (ref1.reach.asInstanceOf [Reach | Restricted ])
365367 case Restricted (ref1, cls) => Restricted (ref1.reach.asInstanceOf [Reach ], cls)
366368 case self : Reach => self
367369 case self : ObjectCapability => cached(Reach (self))
@@ -382,6 +384,7 @@ object Capabilities:
382384 */
383385 final def classifier (using Context ): Symbol = this match
384386 case Restricted (_, cls) => cls
387+ case ReadOnly (ref1) => ref1.classifier
385388 case Maybe (ref1) => ref1.classifier
386389 case self : FreshCap => self.hiddenSet.classifier
387390 case _ => NoSymbol
@@ -400,9 +403,10 @@ object Capabilities:
400403 case Maybe (ref1) => ref1.stripReadOnly.maybe
401404 case _ => this
402405
403- /** Drop restrictions with class `cls` or a superclass of `cls` */
406+ /** Drop restrictions with clss `cls` or a superclass of `cls` */
404407 final def stripRestricted (cls : ClassSymbol )(using Context ): Capability = this match
405408 case Restricted (ref1, cls1) if cls.isSubClass(cls1) => ref1
409+ case ReadOnly (ref1) => ref1.stripRestricted(cls).readOnly
406410 case Maybe (ref1) => ref1.stripRestricted(cls).maybe
407411 case _ => this
408412
@@ -411,6 +415,7 @@ object Capabilities:
411415
412416 final def stripReach (using Context ): Capability = this match
413417 case Reach (ref1) => ref1
418+ case ReadOnly (ref1) => ref1.stripReach.readOnly
414419 case Restricted (ref1, cls) => ref1.stripReach.restrict(cls)
415420 case Maybe (ref1) => ref1.stripReach.maybe
416421 case _ => this
@@ -596,6 +601,7 @@ object Capabilities:
596601 def computeHiddenSet (f : Refs => Refs )(using Context ): Refs = this match
597602 case self : FreshCap => f(self.hiddenSet.elems)
598603 case Restricted (elem1, cls) => elem1.computeHiddenSet(f).map(_.restrict(cls))
604+ case ReadOnly (elem1) => elem1.computeHiddenSet(f).map(_.readOnly)
599605 case _ => emptyRefs
600606
601607 /** The transitive classifiers of this capability. */
@@ -613,6 +619,8 @@ object Capabilities:
613619 assert(cls != defn.AnyClass )
614620 if cls == defn.NothingClass then ClassifiedAs (Nil )
615621 else ClassifiedAs (cls :: Nil )
622+ case ReadOnly (ref1) =>
623+ ref1.transClassifiers
616624 case Maybe (ref1) =>
617625 ref1.transClassifiers
618626 case Reach (_) =>
@@ -636,6 +644,8 @@ object Capabilities:
636644 case Restricted (_, cls1) =>
637645 assert(cls != defn.AnyClass )
638646 cls1.isSubClass(cls)
647+ case ReadOnly (ref1) =>
648+ ref1.tryClassifyAs(cls)
639649 case Maybe (ref1) =>
640650 ref1.tryClassifyAs(cls)
641651 case Reach (_) =>
@@ -656,6 +666,7 @@ object Capabilities:
656666 cs.forall(c => leastClassifier(c, cls) == defn.NothingClass )
657667 case _ => false
658668 isEmpty || ref1.isKnownEmpty
669+ case ReadOnly (ref1) => ref1.isKnownEmpty
659670 case Maybe (ref1) => ref1.isKnownEmpty
660671 case _ => false
661672
@@ -716,6 +727,7 @@ object Capabilities:
716727 case _ => false
717728 || viaInfo(y.info)(subsumingRefs(this , _))
718729 case Maybe (y1) => this .stripMaybe.subsumes(y1)
730+ case ReadOnly (y1) => this .stripReadOnly.subsumes(y1)
719731 case Restricted (y1, cls) => this .stripRestricted(cls).subsumes(y1)
720732 case y : TypeRef if y.derivesFrom(defn.Caps_CapSet ) =>
721733 // The upper and lower bounds don't have to be in the form of `CapSet^{...}`.
@@ -799,6 +811,7 @@ object Capabilities:
799811 y.isKnownClassifiedAs(cls) && x1.maxSubsumes(y, canAddHidden)
800812 case _ =>
801813 y match
814+ case ReadOnly (y1) => this .stripReadOnly.maxSubsumes(y1, canAddHidden)
802815 case Restricted (y1, cls) => this .stripRestricted(cls).maxSubsumes(y1, canAddHidden)
803816 case _ => false
804817
@@ -886,6 +899,7 @@ object Capabilities:
886899 case c : DerivedCapability =>
887900 val c1 = c.underlying.toType
888901 c match
902+ case _ : ReadOnly => ReadOnlyCapability (c1)
889903 case Restricted (_, cls) => OnlyCapability (c1, cls)
890904 case _ : Reach => ReachCapability (c1)
891905 case _ : Maybe => MaybeCapability (c1)
0 commit comments