@@ -47,57 +47,59 @@ def ccState(using Context): CCState =
4747
4848extension (tree : Tree )
4949
50- /** Map tree with a Capability type to the corresponding capability,
51- * map CapSet^{refs} to the `refs` references,
52- * throw IllegalCaptureRef otherwise
53- */
54- def toCapabilities (using Context ): List [Capability ] = tree match
55- case ReachCapabilityApply (arg) =>
56- arg.toCapabilities.map(_.reach)
57- case ReadOnlyCapabilityApply (arg) =>
58- arg.toCapabilities.map(_.readOnly)
59- case CapsOfApply (arg) =>
60- arg.toCapabilities
61- case _ => tree.tpe.dealiasKeepAnnots match
62- case ref : TermRef if ref.isCapRef =>
63- GlobalCap :: Nil
64- case ref : Capability if ref.isTrackableRef =>
65- ref :: Nil
66- case AnnotatedType (parent, ann)
67- if ann.symbol.isRetains && parent.derivesFrom(defn.Caps_CapSet ) =>
68- ann.tree.toCaptureSet.elems.toList
69- case tpe =>
70- throw IllegalCaptureRef (tpe) // if this was compiled from cc syntax, problem should have been reported at Typer
71-
7250 /** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
7351 * For efficience, the result is cached as an Attachment on the tree.
7452 */
7553 def toCaptureSet (using Context ): CaptureSet =
7654 tree.getAttachment(Captures ) match
7755 case Some (refs) => refs
7856 case None =>
79- val refs = CaptureSet (tree.retainedElems.flatMap(_.toCapabilities)* )
80- // .showing(i"toCaptureSet $tree --> $result", capt)
57+ val refs = CaptureSet (tree.retainedSet.retainedElements* )
8158 tree.putAttachment(Captures , refs)
8259 refs
8360
84- /** The arguments of a @retains, @retainsCap or @retainsByName annotation */
85- def retainedElems (using Context ): List [Tree ] = tree match
86- case Apply (_, Typed (SeqLiteral (elems, _), _) :: Nil ) =>
87- elems
88- case _ =>
89- if tree.symbol.maybeOwner == defn.RetainsCapAnnot
90- then ref(defn.captureRoot) :: Nil
91- else Nil
61+ /** The type representing the capture set of @retains, @retainsCap or @retainsByName annotation. */
62+ def retainedSet (using Context ): Type =
63+ tree match
64+ case Apply (TypeApply (_, refs :: Nil ), _) => refs.tpe
65+ case _ =>
66+ if tree.symbol.maybeOwner == defn.RetainsCapAnnot
67+ then defn.captureRoot.termRef else NoType
9268
9369extension (tp : Type )
9470
71+ def toCapability (using Context ): Capability = tp match
72+ case ReachCapability (tp1) =>
73+ tp1.toCapability.reach
74+ case ReadOnlyCapability (tp1) =>
75+ tp1.toCapability.readOnly
76+ case ref : TermRef if ref.isCapRef =>
77+ GlobalCap
78+ case ref : Capability if ref.isTrackableRef =>
79+ ref
80+ case _ =>
81+ // if this was compiled from cc syntax, problem should have been reported at Typer
82+ throw IllegalCaptureRef (tp)
83+
84+ /** A list of raw elements of a retained set.
85+ * This will not crash even if it contains a non-wellformed Capability.
86+ */
87+ def retainedElementsRaw (using Context ): List [Type ] = tp match
88+ case OrType (tp1, tp2) =>
89+ tp1.retainedElementsRaw ++ tp2.retainedElementsRaw
90+ case tp =>
91+ // Nothing is a special type to represent the empty set
92+ if tp.isNothingType then Nil
93+ else tp :: Nil // should be checked by wellformedness
94+
95+ /** A list of capabilities of a retained set. */
96+ def retainedElements (using Context ): List [Capability ] =
97+ retainedElementsRaw.map(_.toCapability)
98+
9599 /** Is this type a Capability that can be tracked?
96100 * This is true for
97101 * - all ThisTypes and all TermParamRef,
98102 * - stable TermRefs with NoPrefix or ThisTypes as prefixes,
99- * - the root capability `caps.cap`
100- * - abstract or parameter TypeRefs that derive from caps.CapSet
101103 * - annotated types that represent reach or maybe capabilities
102104 */
103105 final def isTrackableRef (using Context ): Boolean = tp match
@@ -408,7 +410,7 @@ extension (cls: ClassSymbol)
408410 || bc.is(CaptureChecked )
409411 && bc.givenSelfType.dealiasKeepAnnots.match
410412 case CapturingType (_, refs) => refs.isAlwaysEmpty
411- case RetainingType (_, refs) => refs.isEmpty
413+ case RetainingType (_, refs) => refs.retainedElements. isEmpty
412414 case selfType =>
413415 isCaptureChecking // At Setup we have not processed self types yet, so
414416 // unless a self type is explicitly given, we can't tell
@@ -523,32 +525,36 @@ class CleanupRetains(using Context) extends TypeMap:
523525 def apply (tp : Type ): Type =
524526 tp match
525527 case AnnotatedType (tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
526- RetainingType (tp, Nil , byName = annot.symbol == defn.RetainsByNameAnnot )
528+ RetainingType (tp, defn. NothingType , byName = annot.symbol == defn.RetainsByNameAnnot )
527529 case _ => mapOver(tp)
528530
529- /** An extractor for `caps.reachCapability(ref)`, which is used to express a reach
530- * capability as a tree in a @retains annotation.
531+ /** A base class for extractors that match annotated types with a specific
532+ * Capability annotation.
531533 */
532- object ReachCapabilityApply :
533- def unapply (tree : Apply )(using Context ): Option [Tree ] = tree match
534- case Apply (reach, arg :: Nil ) if reach.symbol == defn.Caps_reachCapability => Some (arg)
534+ abstract class AnnotatedCapability (annotCls : Context ?=> ClassSymbol ):
535+ def apply (tp : Type )(using Context ): AnnotatedType =
536+ AnnotatedType (tp, Annotation (annotCls, util.Spans .NoSpan ))
537+
538+ def unapply (tree : AnnotatedType )(using Context ): Option [Type ] = tree match
539+ case AnnotatedType (parent : Type , ann) if ann.hasSymbol(annotCls) => Some (parent)
535540 case _ => None
536541
537- /** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only
538- * capability as a tree in a @retains annotation.
542+ end AnnotatedCapability
543+
544+ /** An extractor for `ref @readOnlyCapability`, which is used to express
545+ * the read-only capability `ref.rd` as a type.
539546 */
540- object ReadOnlyCapabilityApply :
541- def unapply (tree : Apply )(using Context ): Option [Tree ] = tree match
542- case Apply (ro, arg :: Nil ) if ro.symbol == defn.Caps_readOnlyCapability => Some (arg)
543- case _ => None
547+ object ReadOnlyCapability extends AnnotatedCapability (defn.ReadOnlyCapabilityAnnot )
544548
545- /** An extractor for `caps.capsOf[X] `, which is used to express a generic capture set
546- * as a tree in a @retains annotation .
549+ /** An extractor for `ref @reachCapability `, which is used to express
550+ * the reach capability `ref*` as a type .
547551 */
548- object CapsOfApply :
549- def unapply (tree : TypeApply )(using Context ): Option [Tree ] = tree match
550- case TypeApply (capsOf, arg :: Nil ) if capsOf.symbol == defn.Caps_capsOf => Some (arg)
551- case _ => None
552+ object ReachCapability extends AnnotatedCapability (defn.ReachCapabilityAnnot )
553+
554+ /** An extractor for `ref @amaybeCapability`, which is used to express
555+ * the maybe capability `ref?` as a type.
556+ */
557+ object MaybeCapability extends AnnotatedCapability (defn.MaybeCapabilityAnnot )
552558
553559/** An extractor for all kinds of function types as well as method and poly types.
554560 * It includes aliases of function types such as `=>`. TODO: Can we do without?
0 commit comments