@@ -39,8 +39,9 @@ import annotation.internal.sharable
39
39
* | +-- SetCapability -----+-- TypeRef
40
40
* | +-- TypeParamRef
41
41
* |
42
- * +-- DerivedCapability -+-- ReadOnly
43
- * +-- Reach
42
+ * +-- DerivedCapability -+-- Reach
43
+ * +-- Only
44
+ * +-- ReadOnly
44
45
* +-- Maybe
45
46
*
46
47
* All CoreCapabilities are Types, or, more specifically instances of TypeProxy.
@@ -96,9 +97,18 @@ object Capabilities:
96
97
* but they can wrap reach capabilities. We have
97
98
* (x?).readOnly = (x.rd)?
98
99
*/
99
- case class ReadOnly (underlying : ObjectCapability | RootCapability | Reach )
100
- extends DerivedCapability :
101
- assert(! underlying.isInstanceOf [Maybe ])
100
+ case class ReadOnly (underlying : ObjectCapability | RootCapability | Reach | Restricted )
101
+ extends DerivedCapability
102
+
103
+ /** The restricted capability `x.only[C]`. We have {x.only[C]} <: {x}.
104
+ *
105
+ * Restricted capabilities cannot wrap maybe capabilities or read-only capabilities
106
+ * but they can wrap reach capabilities. We have
107
+ * (x?).restrict[T] = (x.restrict[T])?
108
+ * (x.rd).restrict[T] = (x.restrict[T]).rd
109
+ */
110
+ case class Restricted (underlying : ObjectCapability | RootCapability | Reach , cls : ClassSymbol )
111
+ extends DerivedCapability
102
112
103
113
/** If `x` is a capability, its reach capability `x*`. `x*` stands for all
104
114
* capabilities reachable through `x`.
@@ -109,11 +119,11 @@ object Capabilities:
109
119
*
110
120
* Reach capabilities cannot wrap read-only capabilities or maybe capabilities.
111
121
* We have
112
- * (x.rd).reach = x*.rd
113
- * (x.rd)? = (x*)?
122
+ * (x?).reach = (x.reach)?
123
+ * (x.rd).reach = (x.reach).rd
124
+ * (x.only[T]).reach = (x*).only[T]
114
125
*/
115
- case class Reach (underlying : ObjectCapability ) extends DerivedCapability :
116
- assert(! underlying.isInstanceOf [Maybe | ReadOnly ])
126
+ case class Reach (underlying : ObjectCapability ) extends DerivedCapability
117
127
118
128
/** The global root capability referenced as `caps.cap`
119
129
* `cap` does not subsume other capabilities, except in arguments of
@@ -124,6 +134,7 @@ object Capabilities:
124
134
def descr (using Context ) = " the universal root capability"
125
135
override val maybe = Maybe (this )
126
136
override val readOnly = ReadOnly (this )
137
+ override def restrict (cls : ClassSymbol )(using Context ) = Restricted (this , cls)
127
138
override def reach = unsupported(" cap.reach" )
128
139
override def singletonCaptureSet (using Context ) = CaptureSet .universal
129
140
override def captureSetOfInfo (using Context ) = singletonCaptureSet
@@ -242,7 +253,7 @@ object Capabilities:
242
253
/** A trait for references in CaptureSets. These can be NamedTypes, ThisTypes or ParamRefs,
243
254
* as well as three kinds of AnnotatedTypes representing readOnly, reach, and maybe capabilities.
244
255
* If there are several annotations they come with an order:
245
- * `*` first, `.rd` next, `?` last.
256
+ * `*` first, `.only` next, `. rd` next, `?` last.
246
257
*/
247
258
trait Capability extends Showable :
248
259
@@ -254,7 +265,15 @@ object Capabilities:
254
265
protected def cached [C <: DerivedCapability ](newRef : C ): C =
255
266
def recur (refs : List [DerivedCapability ]): C = refs match
256
267
case ref :: refs1 =>
257
- if ref.getClass == newRef.getClass then ref.asInstanceOf [C ] else recur(refs1)
268
+ val exists = ref match
269
+ case Restricted (_, cls) =>
270
+ newRef match
271
+ case Restricted (_, newCls) => cls == newCls
272
+ case _ => false
273
+ case _ =>
274
+ ref.getClass == newRef.getClass
275
+ if exists then ref.asInstanceOf [C ]
276
+ else recur(refs1)
258
277
case Nil =>
259
278
myDerived = newRef :: myDerived
260
279
newRef
@@ -267,11 +286,24 @@ object Capabilities:
267
286
def readOnly : ReadOnly | Maybe = this match
268
287
case Maybe (ref1) => Maybe (ref1.readOnly)
269
288
case self : ReadOnly => self
270
- case self : (ObjectCapability | RootCapability | Reach ) => cached(ReadOnly (self))
271
-
272
- def reach : Reach | ReadOnly | Maybe = this match
289
+ case self : (ObjectCapability | RootCapability | Reach | Restricted ) => cached(ReadOnly (self))
290
+
291
+ def restrict (cls : ClassSymbol )(using Context ): Restricted | ReadOnly | Maybe = this match
292
+ case Maybe (ref1) => Maybe (ref1.restrict(cls))
293
+ case ReadOnly (ref1) => ReadOnly (ref1.restrict(cls).asInstanceOf [Restricted ])
294
+ 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
299
+ if combinedCls == prevCls then self
300
+ else cached(Restricted (ref1, combinedCls))
301
+ case self : (ObjectCapability | RootCapability | Reach ) => cached(Restricted (self, cls))
302
+
303
+ def reach : Reach | Restricted | ReadOnly | Maybe = this match
273
304
case Maybe (ref1) => Maybe (ref1.reach)
274
- case ReadOnly (ref1) => ReadOnly (ref1.reach.asInstanceOf [Reach ])
305
+ case ReadOnly (ref1) => ReadOnly (ref1.reach.asInstanceOf [Reach | Restricted ])
306
+ case Restricted (ref1, cls) => Restricted (ref1.reach.asInstanceOf [Reach ], cls)
275
307
case self : Reach => self
276
308
case self : ObjectCapability => cached(Reach (self))
277
309
@@ -285,6 +317,12 @@ object Capabilities:
285
317
case tp : SetCapability => tp.captureSetOfInfo.isReadOnly
286
318
case _ => this ne stripReadOnly
287
319
320
+ final def restriction (using Context ): Symbol = this match
321
+ case Restricted (_, cls) => cls
322
+ case ReadOnly (ref1) => ref1.restriction
323
+ case Maybe (ref1) => ref1.restriction
324
+ case _ => NoSymbol
325
+
288
326
/** Is this a reach reference of the form `x*` or a readOnly or maybe variant
289
327
* of a reach reference?
290
328
*/
@@ -299,6 +337,12 @@ object Capabilities:
299
337
case Maybe (ref1) => ref1.stripReadOnly.maybe
300
338
case _ => this
301
339
340
+ final def stripRestricted (using Context ): Capability = this match
341
+ case Restricted (ref1, _) => ref1
342
+ case ReadOnly (ref1) => ref1.stripRestricted.readOnly
343
+ case Maybe (ref1) => ref1.stripRestricted.maybe
344
+ case _ => this
345
+
302
346
final def stripReach (using Context ): Capability = this match
303
347
case Reach (ref1) => ref1
304
348
case ReadOnly (ref1) => ref1.stripReach.readOnly
0 commit comments