Skip to content

Commit cc95088

Browse files
committed
Break out CaptureRef into a separate file
Move extension methods on CaptureRef into CaptureRef itself or into CaptureOps
1 parent bb94805 commit cc95088

File tree

5 files changed

+181
-162
lines changed

5 files changed

+181
-162
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,60 @@ extension (tree: Tree)
183183

184184
extension (tp: Type)
185185

186+
/** Is this type a CaptureRef that can be tracked?
187+
* This is true for
188+
* - all ThisTypes and all TermParamRef,
189+
* - stable TermRefs with NoPrefix or ThisTypes as prefixes,
190+
* - the root capability `caps.cap`
191+
* - abstract or parameter TypeRefs that derive from caps.CapSet
192+
* - annotated types that represent reach or maybe capabilities
193+
*/
194+
final def isTrackableRef(using Context): Boolean = tp match
195+
case _: (ThisType | TermParamRef) =>
196+
true
197+
case tp: TermRef =>
198+
((tp.prefix eq NoPrefix)
199+
|| tp.symbol.is(ParamAccessor) && tp.prefix.isThisTypeOf(tp.symbol.owner)
200+
|| tp.isRootCapability
201+
) && !tp.symbol.isOneOf(UnstableValueFlags)
202+
case tp: TypeRef =>
203+
tp.symbol.isAbstractOrParamType && tp.derivesFrom(defn.Caps_CapSet)
204+
case tp: TypeParamRef =>
205+
tp.derivesFrom(defn.Caps_CapSet)
206+
case AnnotatedType(parent, annot) =>
207+
annot.symbol == defn.ReachCapabilityAnnot
208+
|| annot.symbol == defn.MaybeCapabilityAnnot
209+
case _ =>
210+
false
211+
212+
/** The capture set of a type. This is:
213+
* - For trackable capture references: The singleton capture set consisting of
214+
* just the reference, provided the underlying capture set of their info is not empty.
215+
* - For other capture references: The capture set of their info
216+
* - For all other types: The result of CaptureSet.ofType
217+
*/
218+
final def captureSet(using Context): CaptureSet = tp match
219+
case tp: CaptureRef if tp.isTrackableRef =>
220+
val cs = tp.captureSetOfInfo
221+
if cs.isAlwaysEmpty then cs else tp.singletonCaptureSet
222+
case tp: SingletonCaptureRef => tp.captureSetOfInfo
223+
case _ => CaptureSet.ofType(tp, followResult = false)
224+
225+
/** A type capturing `ref` */
226+
def capturing(ref: CaptureRef)(using Context): Type =
227+
if tp.captureSet.accountsFor(ref) then tp
228+
else CapturingType(tp, ref.singletonCaptureSet)
229+
230+
/** A type capturing the capture set `cs`. If this type is already a capturing type
231+
* the two capture sets are combined.
232+
*/
233+
def capturing(cs: CaptureSet)(using Context): Type =
234+
if cs.isAlwaysEmpty || cs.isConst && cs.subCaptures(tp.captureSet, frozen = true).isOK
235+
then tp
236+
else tp match
237+
case CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs)
238+
case _ => CapturingType(tp, cs)
239+
186240
/** @pre `tp` is a CapturingType */
187241
def derivedCapturingType(parent: Type, refs: CaptureSet)(using Context): Type = tp match
188242
case tp @ CapturingType(p, r) =>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package dotty.tools
2+
package dotc
3+
package cc
4+
5+
import core.*
6+
import Types.*, Symbols.*, Contexts.*, Decorators.*
7+
import util.{SimpleIdentitySet, Property}
8+
import typer.ErrorReporting.Addenda
9+
import TypeComparer.subsumesExistentially
10+
import util.common.alwaysTrue
11+
import scala.collection.mutable
12+
import CCState.*
13+
import Periods.NoRunId
14+
import compiletime.uninitialized
15+
import StdNames.nme
16+
17+
/** A trait for references in CaptureSets. These can be NamedTypes, ThisTypes or ParamRefs,
18+
* as well as two kinds of AnnotatedTypes representing reach and maybe capabilities.
19+
*/
20+
trait CaptureRef extends TypeProxy, ValueType:
21+
private var myCaptureSet: CaptureSet | Null = uninitialized
22+
private var myCaptureSetRunId: Int = NoRunId
23+
private var mySingletonCaptureSet: CaptureSet.Const | Null = null
24+
25+
/** Is the reference tracked? This is true if it can be tracked and the capture
26+
* set of the underlying type is not always empty.
27+
*/
28+
final def isTracked(using Context): Boolean =
29+
this.isTrackableRef && (isMaxCapability || !captureSetOfInfo.isAlwaysEmpty)
30+
31+
/** Is this a reach reference of the form `x*`? */
32+
final def isReach(using Context): Boolean = this match
33+
case AnnotatedType(_, annot) => annot.symbol == defn.ReachCapabilityAnnot
34+
case _ => false
35+
36+
/** Is this a maybe reference of the form `x?`? */
37+
final def isMaybe(using Context): Boolean = this match
38+
case AnnotatedType(_, annot) => annot.symbol == defn.MaybeCapabilityAnnot
39+
case _ => false
40+
41+
final def stripReach(using Context): CaptureRef =
42+
if isReach then
43+
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
44+
parent
45+
else this
46+
47+
final def stripMaybe(using Context): CaptureRef =
48+
if isMaybe then
49+
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
50+
parent
51+
else this
52+
53+
/** Is this reference the generic root capability `cap` ? */
54+
final def isRootCapability(using Context): Boolean = this match
55+
case tp: TermRef => tp.name == nme.CAPTURE_ROOT && tp.symbol == defn.captureRoot
56+
case _ => false
57+
58+
/** Is this reference capability that does not derive from another capability ? */
59+
final def isMaxCapability(using Context): Boolean = this match
60+
case tp: TermRef => tp.isRootCapability || tp.info.derivesFrom(defn.Caps_Exists)
61+
case tp: TermParamRef => tp.underlying.derivesFrom(defn.Caps_Exists)
62+
case _ => false
63+
64+
/** Normalize reference so that it can be compared with `eq` for equality */
65+
final def normalizedRef(using Context): CaptureRef = this match
66+
case tp @ AnnotatedType(parent: CaptureRef, annot) if tp.isTrackableRef =>
67+
tp.derivedAnnotatedType(parent.normalizedRef, annot)
68+
case tp: TermRef if tp.isTrackableRef =>
69+
tp.symbol.termRef
70+
case _ => this
71+
72+
/** The capture set consisting of exactly this reference */
73+
final def singletonCaptureSet(using Context): CaptureSet.Const =
74+
if mySingletonCaptureSet == null then
75+
mySingletonCaptureSet = CaptureSet(this.normalizedRef)
76+
mySingletonCaptureSet.uncheckedNN
77+
78+
/** The capture set of the type underlying this reference */
79+
final def captureSetOfInfo(using Context): CaptureSet =
80+
if ctx.runId == myCaptureSetRunId then myCaptureSet.nn
81+
else if myCaptureSet.asInstanceOf[AnyRef] eq CaptureSet.Pending then CaptureSet.empty
82+
else
83+
myCaptureSet = CaptureSet.Pending
84+
val computed = CaptureSet.ofInfo(this)
85+
if !isCaptureChecking || underlying.isProvisional then
86+
myCaptureSet = null
87+
else
88+
myCaptureSet = computed
89+
myCaptureSetRunId = ctx.runId
90+
computed
91+
92+
final def invalidateCaches() =
93+
myCaptureSetRunId = NoRunId
94+
95+
/** x subsumes x
96+
* this subsumes this.f
97+
* x subsumes y ==> x* subsumes y, x subsumes y?
98+
* x subsumes y ==> x* subsumes y*, x? subsumes y?
99+
* x: x1.type /\ x1 subsumes y ==> x subsumes y
100+
*/
101+
final def subsumes(y: CaptureRef)(using Context): Boolean =
102+
(this eq y)
103+
|| this.isRootCapability
104+
|| y.match
105+
case y: TermRef =>
106+
(y.prefix eq this)
107+
|| y.info.match
108+
case y1: SingletonCaptureRef => this.subsumes(y1)
109+
case _ => false
110+
case MaybeCapability(y1) => this.stripMaybe.subsumes(y1)
111+
case _ => false
112+
|| this.match
113+
case ReachCapability(x1) => x1.subsumes(y.stripReach)
114+
case x: TermRef =>
115+
x.info match
116+
case x1: SingletonCaptureRef => x1.subsumes(y)
117+
case _ => false
118+
case x: TermParamRef => subsumesExistentially(x, y)
119+
case _ => false
120+
121+
end CaptureRef
122+
123+
trait SingletonCaptureRef extends SingletonType, CaptureRef
124+

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -152,33 +152,6 @@ sealed abstract class CaptureSet extends Showable:
152152
cs.addDependent(this)(using ctx, UnrecordedState)
153153
this
154154

155-
/** x subsumes x
156-
* this subsumes this.f
157-
* x subsumes y ==> x* subsumes y, x subsumes y?
158-
* x subsumes y ==> x* subsumes y*, x? subsumes y?
159-
* x: x1.type /\ x1 subsumes y ==> x subsumes y
160-
*/
161-
extension (x: CaptureRef)
162-
private def subsumes(y: CaptureRef)(using Context): Boolean =
163-
(x eq y)
164-
|| x.isRootCapability
165-
|| y.match
166-
case y: TermRef =>
167-
(y.prefix eq x)
168-
|| y.info.match
169-
case y1: SingletonCaptureRef => x.subsumes(y1)
170-
case _ => false
171-
case MaybeCapability(y1) => x.stripMaybe.subsumes(y1)
172-
case _ => false
173-
|| x.match
174-
case ReachCapability(x1) => x1.subsumes(y.stripReach)
175-
case x: TermRef =>
176-
x.info match
177-
case x1: SingletonCaptureRef => x1.subsumes(y)
178-
case _ => false
179-
case x: TermParamRef => subsumesExistentially(x, y)
180-
case _ => false
181-
182155
/** {x} <:< this where <:< is subcapturing, but treating all variables
183156
* as frozen.
184157
*/

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import typer.ForceDegree
1818
import typer.Inferencing.*
1919
import typer.IfBottom
2020
import reporting.TestingReporter
21-
import cc.{CapturingType, derivedCapturingType, CaptureSet, isBoxed, isBoxedCapturing}
21+
import cc.{CapturingType, derivedCapturingType, CaptureSet, captureSet, isBoxed, isBoxedCapturing}
2222
import CaptureSet.{CompareResult, IdempotentCaptRefMap, IdentityCaptRefMap}
2323

2424
import scala.annotation.internal.sharable

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 2 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ import config.Printers.{core, typr, matchTypes}
3838
import reporting.{trace, Message}
3939
import java.lang.ref.WeakReference
4040
import compiletime.uninitialized
41-
import cc.{CapturingType, CaptureSet, derivedCapturingType, isBoxedCapturing, isCaptureChecking, isRetains, isRetainsLike}
41+
import cc.{CapturingType, CaptureRef, CaptureSet, SingletonCaptureRef, isTrackableRef,
42+
derivedCapturingType, isBoxedCapturing, isCaptureChecking, isRetains, isRetainsLike}
4243
import CaptureSet.{CompareResult, IdempotentCaptRefMap, IdentityCaptRefMap}
4344

4445
import scala.annotation.internal.sharable
@@ -517,45 +518,6 @@ object Types extends TypeUtils {
517518
*/
518519
def isDeclaredVarianceLambda: Boolean = false
519520

520-
/** Is this type a CaptureRef that can be tracked?
521-
* This is true for
522-
* - all ThisTypes and all TermParamRef,
523-
* - stable TermRefs with NoPrefix or ThisTypes as prefixes,
524-
* - the root capability `caps.cap`
525-
* - abstract or parameter TypeRefs that derive from caps.CapSet
526-
* - annotated types that represent reach or maybe capabilities
527-
*/
528-
final def isTrackableRef(using Context): Boolean = this match
529-
case _: (ThisType | TermParamRef) =>
530-
true
531-
case tp: TermRef =>
532-
((tp.prefix eq NoPrefix)
533-
|| tp.symbol.is(ParamAccessor) && tp.prefix.isThisTypeOf(tp.symbol.owner)
534-
|| tp.isRootCapability
535-
) && !tp.symbol.isOneOf(UnstableValueFlags)
536-
case tp: TypeRef =>
537-
tp.symbol.isAbstractOrParamType && tp.derivesFrom(defn.Caps_CapSet)
538-
case tp: TypeParamRef =>
539-
tp.derivesFrom(defn.Caps_CapSet)
540-
case AnnotatedType(parent, annot) =>
541-
annot.symbol == defn.ReachCapabilityAnnot
542-
|| annot.symbol == defn.MaybeCapabilityAnnot
543-
case _ =>
544-
false
545-
546-
/** The capture set of a type. This is:
547-
* - For trackable capture references: The singleton capture set consisting of
548-
* just the reference, provided the underlying capture set of their info is not empty.
549-
* - For other capture references: The capture set of their info
550-
* - For all other types: The result of CaptureSet.ofType
551-
*/
552-
final def captureSet(using Context): CaptureSet = this match
553-
case tp: CaptureRef if tp.isTrackableRef =>
554-
val cs = tp.captureSetOfInfo
555-
if cs.isAlwaysEmpty then cs else tp.singletonCaptureSet
556-
case tp: SingletonCaptureRef => tp.captureSetOfInfo
557-
case _ => CaptureSet.ofType(this, followResult = false)
558-
559521
/** Does this type contain wildcard types? */
560522
final def containsWildcardTypes(using Context) =
561523
existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false)
@@ -2081,20 +2043,6 @@ object Types extends TypeUtils {
20812043
case _ =>
20822044
this
20832045

2084-
/** A type capturing `ref` */
2085-
def capturing(ref: CaptureRef)(using Context): Type =
2086-
if captureSet.accountsFor(ref) then this
2087-
else CapturingType(this, ref.singletonCaptureSet)
2088-
2089-
/** A type capturing the capture set `cs`. If this type is already a capturing type
2090-
* the two capture sets are combined.
2091-
*/
2092-
def capturing(cs: CaptureSet)(using Context): Type =
2093-
if cs.isAlwaysEmpty || cs.isConst && cs.subCaptures(captureSet, frozen = true).isOK then this
2094-
else this match
2095-
case CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs)
2096-
case _ => CapturingType(this, cs)
2097-
20982046
/** The set of distinct symbols referred to by this type, after all aliases are expanded */
20992047
def coveringSet(using Context): Set[Symbol] =
21002048
(new CoveringSetAccumulator).apply(Set.empty[Symbol], this)
@@ -2293,86 +2241,6 @@ object Types extends TypeUtils {
22932241
def isOverloaded(using Context): Boolean = false
22942242
}
22952243

2296-
/** A trait for references in CaptureSets. These can be NamedTypes, ThisTypes or ParamRefs */
2297-
trait CaptureRef extends TypeProxy, ValueType:
2298-
private var myCaptureSet: CaptureSet | Null = uninitialized
2299-
private var myCaptureSetRunId: Int = NoRunId
2300-
private var mySingletonCaptureSet: CaptureSet.Const | Null = null
2301-
2302-
/** Is the reference tracked? This is true if it can be tracked and the capture
2303-
* set of the underlying type is not always empty.
2304-
*/
2305-
final def isTracked(using Context): Boolean =
2306-
isTrackableRef && (isMaxCapability || !captureSetOfInfo.isAlwaysEmpty)
2307-
2308-
/** Is this a reach reference of the form `x*`? */
2309-
final def isReach(using Context): Boolean = this match
2310-
case AnnotatedType(_, annot) => annot.symbol == defn.ReachCapabilityAnnot
2311-
case _ => false
2312-
2313-
/** Is this a maybe reference of the form `x?`? */
2314-
final def isMaybe(using Context): Boolean = this match
2315-
case AnnotatedType(_, annot) => annot.symbol == defn.MaybeCapabilityAnnot
2316-
case _ => false
2317-
2318-
final def stripReach(using Context): CaptureRef =
2319-
if isReach then
2320-
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
2321-
parent
2322-
else this
2323-
2324-
final def stripMaybe(using Context): CaptureRef =
2325-
if isMaybe then
2326-
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
2327-
parent
2328-
else this
2329-
2330-
/** Is this reference the generic root capability `cap` ? */
2331-
final def isRootCapability(using Context): Boolean = this match
2332-
case tp: TermRef => tp.name == nme.CAPTURE_ROOT && tp.symbol == defn.captureRoot
2333-
case _ => false
2334-
2335-
/** Is this reference capability that does not derive from another capability ? */
2336-
final def isMaxCapability(using Context): Boolean = this match
2337-
case tp: TermRef => tp.isRootCapability || tp.info.derivesFrom(defn.Caps_Exists)
2338-
case tp: TermParamRef => tp.underlying.derivesFrom(defn.Caps_Exists)
2339-
case _ => false
2340-
2341-
/** Normalize reference so that it can be compared with `eq` for equality */
2342-
final def normalizedRef(using Context): CaptureRef = this match
2343-
case tp @ AnnotatedType(parent: CaptureRef, annot) if isTrackableRef =>
2344-
tp.derivedAnnotatedType(parent.normalizedRef, annot)
2345-
case tp: TermRef if isTrackableRef =>
2346-
tp.symbol.termRef
2347-
case _ => this
2348-
2349-
/** The capture set consisting of exactly this reference */
2350-
final def singletonCaptureSet(using Context): CaptureSet.Const =
2351-
if mySingletonCaptureSet == null then
2352-
mySingletonCaptureSet = CaptureSet(this.normalizedRef)
2353-
mySingletonCaptureSet.uncheckedNN
2354-
2355-
/** The capture set of the type underlying this reference */
2356-
final def captureSetOfInfo(using Context): CaptureSet =
2357-
if ctx.runId == myCaptureSetRunId then myCaptureSet.nn
2358-
else if myCaptureSet.asInstanceOf[AnyRef] eq CaptureSet.Pending then CaptureSet.empty
2359-
else
2360-
myCaptureSet = CaptureSet.Pending
2361-
val computed = CaptureSet.ofInfo(this)
2362-
if !isCaptureChecking || underlying.isProvisional then
2363-
myCaptureSet = null
2364-
else
2365-
myCaptureSet = computed
2366-
myCaptureSetRunId = ctx.runId
2367-
computed
2368-
2369-
final def invalidateCaches() =
2370-
myCaptureSetRunId = NoRunId
2371-
2372-
end CaptureRef
2373-
2374-
trait SingletonCaptureRef extends SingletonType, CaptureRef
2375-
23762244
/** A trait for types that bind other types that refer to them.
23772245
* Instances are: LambdaType, RecType.
23782246
*/

0 commit comments

Comments
 (0)