@@ -54,23 +54,23 @@ extension (tree: Tree)
54
54
* map CapSet^{refs} to the `refs` references,
55
55
* throw IllegalCaptureRef otherwise
56
56
*/
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
74
74
75
75
/** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
76
76
* For efficience, the result is cached as an Attachment on the tree.
@@ -79,28 +79,41 @@ extension (tree: Tree)
79
79
tree.getAttachment(Captures ) match
80
80
case Some (refs) => refs
81
81
case None =>
82
- val refs = CaptureSet (tree.retainedElems.flatMap(_.toCapabilities)* )
83
- // .showing(i"toCaptureSet $tree --> $result", capt)
82
+ val refs = CaptureSet (tree.retainedSet.retainedElements* )
84
83
tree.putAttachment(Captures , refs)
85
84
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
95
93
96
94
extension (tp : Type )
97
95
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
+
98
113
/** Is this type a Capability that can be tracked?
99
114
* This is true for
100
115
* - all ThisTypes and all TermParamRef,
101
116
* - stable TermRefs with NoPrefix or ThisTypes as prefixes,
102
- * - the root capability `caps.cap`
103
- * - abstract or parameter TypeRefs that derive from caps.CapSet
104
117
* - annotated types that represent reach or maybe capabilities
105
118
*/
106
119
final def isTrackableRef (using Context ): Boolean = tp match
@@ -418,7 +431,7 @@ extension (cls: ClassSymbol)
418
431
|| bc.is(CaptureChecked )
419
432
&& bc.givenSelfType.dealiasKeepAnnots.match
420
433
case CapturingType (_, refs) => refs.isAlwaysEmpty
421
- case RetainingType (_, refs) => refs.isEmpty
434
+ case RetainingType (_, refs) => refs.retainedElements. isEmpty
422
435
case selfType =>
423
436
isCaptureChecking // At Setup we have not processed self types yet, so
424
437
// unless a self type is explicitly given, we can't tell
@@ -533,7 +546,7 @@ class CleanupRetains(using Context) extends TypeMap:
533
546
def apply (tp : Type ): Type =
534
547
tp match
535
548
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 )
537
550
case _ => mapOver(tp)
538
551
539
552
/** A typemap that follows aliases and keeps their transformed results if
@@ -549,29 +562,57 @@ trait FollowAliasesMap(using Context) extends TypeMap:
549
562
else t
550
563
else mapOver(t)
551
564
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)
558
594
case _ => None
559
595
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)
566
603
case _ => None
567
604
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 .
570
607
*/
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 )
575
616
576
617
/** An extractor for all kinds of function types as well as method and poly types.
577
618
* It includes aliases of function types such as `=>`. TODO: Can we do without?
0 commit comments