dotty.tools.dotc.cc.CaptureRef.scala Maven / Gradle / Ivy
package dotty.tools
package dotc
package cc
import core.*
import Types.*, Symbols.*, Contexts.*, Decorators.*
import util.{SimpleIdentitySet, Property}
import typer.ErrorReporting.Addenda
import TypeComparer.subsumesExistentially
import util.common.alwaysTrue
import scala.collection.mutable
import CCState.*
import Periods.NoRunId
import compiletime.uninitialized
import StdNames.nme
/** A trait for references in CaptureSets. These can be NamedTypes, ThisTypes or ParamRefs,
* as well as two kinds of AnnotatedTypes representing reach and maybe capabilities.
*/
trait CaptureRef extends TypeProxy, ValueType:
private var myCaptureSet: CaptureSet | Null = uninitialized
private var myCaptureSetRunId: Int = NoRunId
private var mySingletonCaptureSet: CaptureSet.Const | Null = null
/** Is the reference tracked? This is true if it can be tracked and the capture
* set of the underlying type is not always empty.
*/
final def isTracked(using Context): Boolean =
this.isTrackableRef && (isMaxCapability || !captureSetOfInfo.isAlwaysEmpty)
/** Is this a reach reference of the form `x*`? */
final def isReach(using Context): Boolean = this match
case AnnotatedType(_, annot) => annot.symbol == defn.ReachCapabilityAnnot
case _ => false
/** Is this a maybe reference of the form `x?`? */
final def isMaybe(using Context): Boolean = this match
case AnnotatedType(_, annot) => annot.symbol == defn.MaybeCapabilityAnnot
case _ => false
final def stripReach(using Context): CaptureRef =
if isReach then
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
parent
else this
final def stripMaybe(using Context): CaptureRef =
if isMaybe then
val AnnotatedType(parent: CaptureRef, _) = this: @unchecked
parent
else this
/** Is this reference the generic root capability `cap` ? */
final def isRootCapability(using Context): Boolean = this match
case tp: TermRef => tp.name == nme.CAPTURE_ROOT && tp.symbol == defn.captureRoot
case _ => false
/** Is this reference capability that does not derive from another capability ? */
final def isMaxCapability(using Context): Boolean = this match
case tp: TermRef => tp.isRootCapability || tp.info.derivesFrom(defn.Caps_Exists)
case tp: TermParamRef => tp.underlying.derivesFrom(defn.Caps_Exists)
case _ => false
// With the support of pathes, we don't need to normalize the `TermRef`s anymore.
// /** Normalize reference so that it can be compared with `eq` for equality */
// final def normalizedRef(using Context): CaptureRef = this match
// case tp @ AnnotatedType(parent: CaptureRef, annot) if tp.isTrackableRef =>
// tp.derivedAnnotatedType(parent.normalizedRef, annot)
// case tp: TermRef if tp.isTrackableRef =>
// tp.symbol.termRef
// case _ => this
/** The capture set consisting of exactly this reference */
final def singletonCaptureSet(using Context): CaptureSet.Const =
if mySingletonCaptureSet == null then
mySingletonCaptureSet = CaptureSet(this)
mySingletonCaptureSet.uncheckedNN
/** The capture set of the type underlying this reference */
final def captureSetOfInfo(using Context): CaptureSet =
if ctx.runId == myCaptureSetRunId then myCaptureSet.nn
else if myCaptureSet.asInstanceOf[AnyRef] eq CaptureSet.Pending then CaptureSet.empty
else
myCaptureSet = CaptureSet.Pending
val computed = CaptureSet.ofInfo(this)
if !isCaptureChecking || underlying.isProvisional then
myCaptureSet = null
else
myCaptureSet = computed
myCaptureSetRunId = ctx.runId
computed
final def invalidateCaches() =
myCaptureSetRunId = NoRunId
/** x subsumes x
* this subsumes this.f
* x subsumes y ==> x* subsumes y, x subsumes y?
* x subsumes y ==> x* subsumes y*, x? subsumes y?
* x: x1.type /\ x1 subsumes y ==> x subsumes y
* TODO: Document path cases
*/
final def subsumes(y: CaptureRef)(using Context): Boolean =
def subsumingRefs(x: Type, y: Type): Boolean = x match
case x: CaptureRef => y match
case y: CaptureRef => x.subsumes(y)
case _ => false
case _ => false
def viaInfo(info: Type)(test: Type => Boolean): Boolean = info.match
case info: SingletonCaptureRef => test(info)
case info: AndType => viaInfo(info.tp1)(test) || viaInfo(info.tp2)(test)
case info: OrType => viaInfo(info.tp1)(test) && viaInfo(info.tp2)(test)
case _ => false
(this eq y)
|| this.isRootCapability
|| y.match
case y: TermRef =>
y.prefix.match
case ypre: CaptureRef =>
this.subsumes(ypre)
|| this.match
case x @ TermRef(xpre: CaptureRef, _) if x.symbol == y.symbol =>
// To show `{x.f} <:< {y.f}`, it is important to prove `x` and `y`
// are equvalent, which means `x =:= y` in terms of subtyping,
// not just `{x} =:= {y}` in terms of subcapturing.
// It is possible to construct two singleton types `x` and `y`,
// which subsume each other, but are not equal references.
// See `tests/neg-custom-args/captures/path-prefix.scala` for example.
withMode(Mode.IgnoreCaptures) {TypeComparer.isSameRef(xpre, ypre)}
case _ =>
false
case _ => false
|| viaInfo(y.info)(subsumingRefs(this, _))
case MaybeCapability(y1) => this.stripMaybe.subsumes(y1)
case _ => false
|| this.match
case ReachCapability(x1) => x1.subsumes(y.stripReach)
case x: TermRef => viaInfo(x.info)(subsumingRefs(_, y))
case x: TermParamRef => subsumesExistentially(x, y)
case x: TypeRef => assumedContainsOf(x).contains(y)
case _ => false
end subsumes
def assumedContainsOf(x: TypeRef)(using Context): SimpleIdentitySet[CaptureRef] =
CaptureSet.assumedContains.getOrElse(x, SimpleIdentitySet.empty)
end CaptureRef
trait SingletonCaptureRef extends SingletonType, CaptureRef
© 2015 - 2025 Weber Informatics LLC | Privacy Policy