@@ -54,23 +54,23 @@ extension (tree: Tree)
5454 * map CapSet^{refs} to the `refs` references,
5555 * throw IllegalCaptureRef otherwise
5656 */
57- def toCapabilities (using Context ): List [Capability ] = tree match
58- case ReachCapabilityApply (arg) =>
59- arg.toCapabilities.map(_.reach)
60- case ReadOnlyCapabilityApply (arg) =>
61- arg.toCapabilities.map(_.readOnly)
62- case CapsOfApply (arg) =>
63- arg.toCapabilities
64- case _ => tree.tpe.dealiasKeepAnnots match
65- case ref : TermRef if ref.isCapRef =>
66- GlobalCap :: Nil
67- case ref : Capability if ref.isTrackableRef =>
68- ref :: Nil
69- case AnnotatedType (parent, ann)
70- if ann.symbol.isRetains && parent.derivesFrom(defn.Caps_CapSet ) =>
71- ann.tree.toCaptureSet.elems.toList
72- case tpe =>
73- throw IllegalCaptureRef (tpe) // if this was compiled from cc syntax, problem should have been reported at Typer
57+ // def toCapabilities(using Context): List[Capability] = tree match
58+ // case ReachCapabilityApply(arg) =>
59+ // arg.toCapabilities.map(_.reach)
60+ // case ReadOnlyCapabilityApply(arg) =>
61+ // arg.toCapabilities.map(_.readOnly)
62+ // case CapsOfApply(arg) =>
63+ // arg.toCapabilities
64+ // case _ => tree.tpe.dealiasKeepAnnots match
65+ // case ref: TermRef if ref.isCapRef =>
66+ // GlobalCap :: Nil
67+ // case ref: Capability if ref.isTrackableRef =>
68+ // ref :: Nil
69+ // case AnnotatedType(parent, ann)
70+ // if ann.symbol.isRetains && parent.derivesFrom(defn.Caps_CapSet) =>
71+ // ann.tree.toCaptureSet.elems.toList
72+ // case tpe =>
73+ // throw IllegalCaptureRef(tpe) // if this was compiled from cc syntax, problem should have been reported at Typer
7474
7575 /** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
7676 * For efficience, the result is cached as an Attachment on the tree.
@@ -79,28 +79,41 @@ extension (tree: Tree)
7979 tree.getAttachment(Captures ) match
8080 case Some (refs) => refs
8181 case None =>
82- val refs = CaptureSet (tree.retainedElems.flatMap(_.toCapabilities)* )
83- // .showing(i"toCaptureSet $tree --> $result", capt)
82+ val refs = CaptureSet (tree.retainedSet.retainedElements* )
8483 tree.putAttachment(Captures , refs)
8584 refs
86-
87- /** The arguments of a @retains, @retainsCap or @retainsByName annotation */
88- def retainedElems (using Context ): List [Tree ] = tree match
89- case Apply (_, Typed (SeqLiteral (elems, _), _) :: Nil ) =>
90- elems
91- case _ =>
92- if tree.symbol.maybeOwner == defn.RetainsCapAnnot
93- then ref(defn.captureRoot) :: Nil
94- else Nil
85+ /** The type representing the capture set of retains annotation.
86+ */
87+ def retainedSet (using Context ): Type =
88+ tree match
89+ case Apply (TypeApply (_, refs :: Nil ), _) => refs.tpe
90+ case _ =>
91+ if tree.symbol.maybeOwner == defn.RetainsCapAnnot
92+ then ref(defn.captureRoot) else NoType
9593
9694extension (tp : Type )
9795
96+ def retainedElementsRaw (using Context ): List [Type ] = tp match
97+ case ReachCapability (tp1) =>
98+ tp1.reach :: Nil
99+ case ReadOnlyCapability (tp1) =>
100+ tp1.readOnly :: Nil
101+ case OrType (tp1, tp2) =>
102+ tp1.retainedElementsRaw ++ tp2.retainedElementsRaw
103+ case tp =>
104+ // Nothing is a special type to represent the empty set
105+ if tp.isNothingType then Nil
106+ else tp :: Nil // should be checked by wellformedness
107+
108+ def retainedElements (using Context ): List [Capability ] =
109+ retainedElementsRaw.map:
110+ case tp : CaptureRef => tp
111+ case tp => throw IllegalCaptureRef (tp)
112+
98113 /** Is this type a Capability that can be tracked?
99114 * This is true for
100115 * - all ThisTypes and all TermParamRef,
101116 * - stable TermRefs with NoPrefix or ThisTypes as prefixes,
102- * - the root capability `caps.cap`
103- * - abstract or parameter TypeRefs that derive from caps.CapSet
104117 * - annotated types that represent reach or maybe capabilities
105118 */
106119 final def isTrackableRef (using Context ): Boolean = tp match
@@ -418,7 +431,7 @@ extension (cls: ClassSymbol)
418431 || bc.is(CaptureChecked )
419432 && bc.givenSelfType.dealiasKeepAnnots.match
420433 case CapturingType (_, refs) => refs.isAlwaysEmpty
421- case RetainingType (_, refs) => refs.isEmpty
434+ case RetainingType (_, refs) => refs.retainedElements. isEmpty
422435 case selfType =>
423436 isCaptureChecking // At Setup we have not processed self types yet, so
424437 // unless a self type is explicitly given, we can't tell
@@ -533,7 +546,7 @@ class CleanupRetains(using Context) extends TypeMap:
533546 def apply (tp : Type ): Type =
534547 tp match
535548 case AnnotatedType (tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
536- RetainingType (tp, Nil , byName = annot.symbol == defn.RetainsByNameAnnot )
549+ RetainingType (tp, defn. NothingType , byName = annot.symbol == defn.RetainsByNameAnnot )
537550 case _ => mapOver(tp)
538551
539552/** A typemap that follows aliases and keeps their transformed results if
@@ -549,29 +562,57 @@ trait FollowAliasesMap(using Context) extends TypeMap:
549562 else t
550563 else mapOver(t)
551564
552- /** An extractor for `caps.reachCapability(ref)`, which is used to express a reach
553- * capability as a tree in a @retains annotation.
554- */
555- object ReachCapabilityApply :
556- def unapply (tree : Apply )(using Context ): Option [Tree ] = tree match
557- case Apply (reach, arg :: Nil ) if reach.symbol == defn.Caps_reachCapability => Some (arg)
565+ // /** An extractor for `caps.reachCapability(ref)`, which is used to express a reach
566+ // * capability as a tree in a @retains annotation.
567+ // */
568+ // object ReachCapabilityApply:
569+ // def unapply(tree: Apply)(using Context): Option[Tree] = tree match
570+ // case Apply(reach, arg :: Nil) if reach.symbol == defn.Caps_reachCapability => Some(arg)
571+ // case _ => None
572+
573+ // /** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only
574+ // * capability as a tree in a @retains annotation.
575+ // */
576+ // object ReadOnlyCapabilityApply:
577+ // def unapply(tree: Apply)(using Context): Option[Tree] = tree match
578+ // case Apply(ro, arg :: Nil) if ro.symbol == defn.Caps_readOnlyCapability => Some(arg)
579+ // case _ => None
580+
581+ abstract class AnnotatedCapability (annotCls : Context ?=> ClassSymbol ):
582+ def apply (tp : Type )(using Context ): AnnotatedType =
583+ assert(tp.isTrackableRef, i " not a trackable ref: $tp" )
584+ tp match
585+ case AnnotatedType (_, annot) =>
586+ assert(! unwrappable.contains(annot.symbol), i " illegal combination of derived capabilities: $annotCls over ${annot.symbol}" )
587+ case _ =>
588+ tp match
589+ case tp : Capability => tp.derivedRef(annotCls)
590+ case _ => AnnotatedType (tp, Annotation (annotCls, util.Spans .NoSpan ))
591+
592+ def unapply (tree : AnnotatedType )(using Context ): Option [Capability ] = tree match
593+ case AnnotatedType (parent : Capability , ann) if ann.hasSymbol(annotCls) => Some (parent)
558594 case _ => None
559595
560- /** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only
561- * capability as a tree in a @retains annotation.
562- */
563- object ReadOnlyCapabilityApply :
564- def unapply (tree : Apply )(using Context ): Option [Tree ] = tree match
565- case Apply (ro, arg :: Nil ) if ro.symbol == defn.Caps_readOnlyCapability => Some (arg)
596+ protected def unwrappable (using Context ): Set [Symbol ]
597+ end AnnotatedCapability
598+
599+ object QualifiedCapability :
600+ def unapply (tree : AnnotatedType )(using Context ): Option [Capability ] = tree match
601+ case AnnotatedType (parent : Capability , ann)
602+ if defn.capabilityQualifierAnnots.contains(ann.symbol) => Some (parent)
566603 case _ => None
567604
568- /** An extractor for `caps.capsOf[X] `, which is used to express a generic capture set
569- * as a tree in a @retains annotation .
605+ /** An extractor for `ref @readOnlyCapability `, which is used to express
606+ * the read-only capability `ref.rd` as a type .
570607 */
571- object CapsOfApply :
572- def unapply (tree : TypeApply )(using Context ): Option [Tree ] = tree match
573- case TypeApply (capsOf, arg :: Nil ) if capsOf.symbol == defn.Caps_capsOf => Some (arg)
574- case _ => None
608+ object ReadOnlyCapability extends AnnotatedCapability (defn.ReadOnlyCapabilityAnnot ):
609+ protected def unwrappable (using Context ) = Set ()
610+
611+ /** An extractor for `ref @annotation.internal.reachCapability`, which is used to express
612+ * the reach capability `ref*` as a type.
613+ */
614+ object ReachCapability extends AnnotatedCapability (defn.ReachCapabilityAnnot ):
615+ protected def unwrappable (using Context ) = Set (defn.ReadOnlyCapabilityAnnot )
575616
576617/** An extractor for all kinds of function types as well as method and poly types.
577618 * It includes aliases of function types such as `=>`. TODO: Can we do without?
0 commit comments