@@ -47,57 +47,59 @@ def ccState(using Context): CCState =
47
47
48
48
extension (tree : Tree )
49
49
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
-
72
50
/** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
73
51
* For efficience, the result is cached as an Attachment on the tree.
74
52
*/
75
53
def toCaptureSet (using Context ): CaptureSet =
76
54
tree.getAttachment(Captures ) match
77
55
case Some (refs) => refs
78
56
case None =>
79
- val refs = CaptureSet (tree.retainedElems.flatMap(_.toCapabilities)* )
80
- // .showing(i"toCaptureSet $tree --> $result", capt)
57
+ val refs = CaptureSet (tree.retainedSet.retainedElements* )
81
58
tree.putAttachment(Captures , refs)
82
59
refs
83
60
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
92
68
93
69
extension (tp : Type )
94
70
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
+
95
99
/** Is this type a Capability that can be tracked?
96
100
* This is true for
97
101
* - all ThisTypes and all TermParamRef,
98
102
* - stable TermRefs with NoPrefix or ThisTypes as prefixes,
99
- * - the root capability `caps.cap`
100
- * - abstract or parameter TypeRefs that derive from caps.CapSet
101
103
* - annotated types that represent reach or maybe capabilities
102
104
*/
103
105
final def isTrackableRef (using Context ): Boolean = tp match
@@ -408,7 +410,7 @@ extension (cls: ClassSymbol)
408
410
|| bc.is(CaptureChecked )
409
411
&& bc.givenSelfType.dealiasKeepAnnots.match
410
412
case CapturingType (_, refs) => refs.isAlwaysEmpty
411
- case RetainingType (_, refs) => refs.isEmpty
413
+ case RetainingType (_, refs) => refs.retainedElements. isEmpty
412
414
case selfType =>
413
415
isCaptureChecking // At Setup we have not processed self types yet, so
414
416
// unless a self type is explicitly given, we can't tell
@@ -523,32 +525,36 @@ class CleanupRetains(using Context) extends TypeMap:
523
525
def apply (tp : Type ): Type =
524
526
tp match
525
527
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 )
527
529
case _ => mapOver(tp)
528
530
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.
531
533
*/
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)
535
540
case _ => None
536
541
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.
539
546
*/
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 )
544
548
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 .
547
551
*/
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 )
552
558
553
559
/** An extractor for all kinds of function types as well as method and poly types.
554
560
* It includes aliases of function types such as `=>`. TODO: Can we do without?
0 commit comments