Skip to content

Commit c971af4

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

File tree

5 files changed

+181
-162
lines changed

5 files changed

+181
-162
lines changed

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

+54
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,60 @@ extension (tree: Tree)
168168

169169
extension (tp: Type)
170170

171+
/** Is this type a CaptureRef that can be tracked?
172+
* This is true for
173+
* - all ThisTypes and all TermParamRef,
174+
* - stable TermRefs with NoPrefix or ThisTypes as prefixes,
175+
* - the root capability `caps.cap`
176+
* - abstract or parameter TypeRefs that derive from caps.CapSet
177+
* - annotated types that represent reach or maybe capabilities
178+
*/
179+
final def isTrackableRef(using Context): Boolean = tp match
180+
case _: (ThisType | TermParamRef) =>
181+
true
182+
case tp: TermRef =>
183+
((tp.prefix eq NoPrefix)
184+
|| tp.symbol.is(ParamAccessor) && tp.prefix.isThisTypeOf(tp.symbol.owner)
185+
|| tp.isRootCapability
186+
) && !tp.symbol.isOneOf(UnstableValueFlags)
187+
case tp: TypeRef =>
188+
tp.symbol.isAbstractOrParamType && tp.derivesFrom(defn.Caps_CapSet)
189+
case tp: TypeParamRef =>
190+
tp.derivesFrom(defn.Caps_CapSet)
191+
case AnnotatedType(parent, annot) =>
192+
annot.symbol == defn.ReachCapabilityAnnot
193+
|| annot.symbol == defn.MaybeCapabilityAnnot
194+
case _ =>
195+
false
196+
197+
/** The capture set of a type. This is:
198+
* - For trackable capture references: The singleton capture set consisting of
199+
* just the reference, provided the underlying capture set of their info is not empty.
200+
* - For other capture references: The capture set of their info
201+
* - For all other types: The result of CaptureSet.ofType
202+
*/
203+
final def captureSet(using Context): CaptureSet = tp match
204+
case tp: CaptureRef if tp.isTrackableRef =>
205+
val cs = tp.captureSetOfInfo
206+
if cs.isAlwaysEmpty then cs else tp.singletonCaptureSet
207+
case tp: SingletonCaptureRef => tp.captureSetOfInfo
208+
case _ => CaptureSet.ofType(tp, followResult = false)
209+
210+
/** A type capturing `ref` */
211+
def capturing(ref: CaptureRef)(using Context): Type =
212+
if tp.captureSet.accountsFor(ref) then tp
213+
else CapturingType(tp, ref.singletonCaptureSet)
214+
215+
/** A type capturing the capture set `cs`. If this type is already a capturing type
216+
* the two capture sets are combined.
217+
*/
218+
def capturing(cs: CaptureSet)(using Context): Type =
219+
if cs.isAlwaysEmpty || cs.isConst && cs.subCaptures(tp.captureSet, frozen = true).isOK
220+
then tp
221+
else tp match
222+
case CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs)
223+
case _ => CapturingType(tp, cs)
224+
171225
/** @pre `tp` is a CapturingType */
172226
def derivedCapturingType(parent: Type, refs: CaptureSet)(using Context): Type = tp match
173227
case tp @ CapturingType(p, r) =>
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

-27
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

+1-1
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

+2-134
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
@@ -522,45 +523,6 @@ object Types extends TypeUtils {
522523
*/
523524
def isDeclaredVarianceLambda: Boolean = false
524525

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

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

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

0 commit comments

Comments
 (0)