Skip to content

Commit 41e7556

Browse files
committed
Switch to new scheme for bound caps
Drop old-style existentials and use instead Fresh instances that refer to that MethodType which defines the scope of the Fresh as its result type.
1 parent c5c0768 commit 41e7556

25 files changed

+427
-182
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ extension (tp: Type)
195195
*/
196196
final def isTrackableRef(using Context): Boolean = tp match
197197
case _: ThisType => true
198-
case tp: TermParamRef => !Existential.isBinder(tp)
198+
case tp: TermParamRef => !Existential.isBinderOLD(tp)
199199
case tp: TermRef =>
200200
((tp.prefix eq NoPrefix)
201201
|| tp.symbol.isField && !tp.symbol.isStatic && tp.prefix.isTrackableRef
@@ -205,7 +205,8 @@ extension (tp: Type)
205205
tp.symbol.isType && tp.derivesFrom(defn.Caps_CapSet)
206206
case tp: TypeParamRef =>
207207
tp.derivesFrom(defn.Caps_CapSet)
208-
case Existential.Var(_) => true
208+
case Existential.VarOLD(_) => true
209+
case Existential.Vble(_) => true
209210
case AnnotatedType(parent, annot) =>
210211
defn.capabilityWrapperAnnots.contains(annot.symbol) && parent.isTrackableRef
211212
case _ =>
@@ -526,11 +527,11 @@ extension (tp: Type)
526527
case t @ AnnotatedType(parent, ann) =>
527528
// Don't map annotations, which includes capture sets
528529
t.derivedAnnotatedType(this(parent), ann)
529-
case t @ FunctionOrMethod(args, res @ Existential(_, _))
530+
case t @ FunctionOrMethod(args, res)
530531
if args.forall(_.isAlwaysPure) =>
531532
// Also map existentials in results to reach capabilities if all
532533
// preceding arguments are known to be always pure
533-
apply(t.derivedFunctionOrMethod(args, Existential.toCap(res)))
534+
t.derivedFunctionOrMethod(args, apply(Existential.toCap(res)))
534535
case Existential(_, _) =>
535536
t
536537
case _ =>
@@ -572,6 +573,11 @@ extension (tp: Type)
572573
case tp: ThisType => tp.cls.ccLevel.nextInner
573574
case _ => undefinedLevel
574575

576+
def hasSuffix(other: MethodType)(using Context): Boolean =
577+
(tp eq other) || tp.match
578+
case tp: MethodOrPoly => tp.resType.hasSuffix(other)
579+
case _ => false
580+
575581
extension (cls: ClassSymbol)
576582

577583
def pureBaseClass(using Context): Option[Symbol] =

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core.*
66
import Types.*, Symbols.*, Contexts.*, Decorators.*
77
import util.{SimpleIdentitySet, Property}
88
import typer.ErrorReporting.Addenda
9-
import TypeComparer.subsumesExistentially
9+
import TypeComparer.subsumesExistentiallyOLD
1010
import util.common.alwaysTrue
1111
import scala.collection.mutable
1212
import CCState.*
@@ -110,7 +110,8 @@ trait CaptureRef extends TypeProxy, ValueType:
110110
*/
111111
final def isMaxCapability(using Context): Boolean = this match
112112
case tp: TermRef => tp.isCap || tp.info.derivesFrom(defn.Caps_Exists)
113-
case Existential.Var(_) => true
113+
case Existential.VarOLD(_) => true
114+
case Existential.Vble(_) => true
114115
case Fresh(_) => true
115116
case ReadOnlyCapability(tp1) => tp1.isMaxCapability
116117
case _ => false
@@ -228,7 +229,7 @@ trait CaptureRef extends TypeProxy, ValueType:
228229
case _ => false
229230
|| this.match
230231
case ReachCapability(x1) => x1.subsumes(y.stripReach)
231-
case Existential.Var(bv) => subsumesExistentially(bv, y)
232+
case Existential.VarOLD(bv) => subsumesExistentiallyOLD(bv, y)
232233
case x: TermRef => viaInfo(x.info)(subsumingRefs(_, y))
233234
case x: TypeRef if assumedContainsOf(x).contains(y) => true
234235
case x: TypeRef if x.derivesFrom(defn.Caps_CapSet) =>
@@ -258,6 +259,10 @@ trait CaptureRef extends TypeProxy, ValueType:
258259
case Fresh(hidden) =>
259260
vs.ifNotSeen(this)(hidden.elems.exists(_.subsumes(y)))
260261
|| !y.stripReadOnly.isCap && canAddHidden && vs.addHidden(hidden, y)
262+
case Existential.Vble(binder) =>
263+
y.stripReadOnly match
264+
case Existential.Vble(binder1) => binder1.hasSuffix(binder)
265+
case _ => true
261266
case _ =>
262267
this.isCap && canAddHidden && vs != VarState.HardSeparate
263268
|| y.match

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

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ sealed abstract class CaptureSet extends Showable:
104104

105105
final def isUnboxable(using Context) =
106106
elems.exists:
107-
case Existential.Var(_) => true
107+
case Existential.VarOLD(_) => true
108+
case Existential.Vble(_) => true
108109
case elem => elem.isRootCapability
109110

110111
final def isReadOnly(using Context): Boolean =
@@ -547,7 +548,7 @@ object CaptureSet:
547548
final def addThisElem(elem: CaptureRef)(using Context, VarState): CompareResult =
548549
if isConst || !recordElemsState() then // Fail if variable is solved or given VarState is frozen
549550
addIfHiddenOrFail(elem)
550-
else if Existential.isBadExistential(elem) then // Fail if `elem` is an out-of-scope existential
551+
else if Existential.isBadExistentialOLD(elem) then // Fail if `elem` is an out-of-scope existential
551552
CompareResult.Fail(this :: Nil)
552553
else if !levelOK(elem) then
553554
CompareResult.LevelError(this, elem) // or `elem` is not visible at the level of the set.
@@ -567,15 +568,21 @@ object CaptureSet:
567568
elems -= elem
568569
res.addToTrace(this)
569570

571+
// TODO: Also track allowable TermParamRefs and Existential.Vbles in capture sets
570572
private def levelOK(elem: CaptureRef)(using Context): Boolean =
571573
if elem.isRootCapability then
572574
!noUniversal
573575
else elem match
574-
case Existential.Var(bv) =>
576+
case Existential.VarOLD(bv) =>
575577
!noUniversal
576578
&& !TypeComparer.isOpenedExistential(bv)
577579
// Opened existentials on the left cannot be added to nested capture sets on the right
578580
// of a comparison. Test case is open-existential.scala.
581+
case elem @ Existential.Vble(mt) =>
582+
!noUniversal
583+
&& !TypeComparer.isOpenedExistential(elem)
584+
// Opened existentials on the left cannot be added to nested capture sets on the right
585+
// of a comparison. Test case is open-existential.scala.
579586
case elem: TermRef if level.isDefined =>
580587
elem.prefix match
581588
case prefix: CaptureRef =>
@@ -629,7 +636,8 @@ object CaptureSet:
629636
try
630637
val approx = computeApprox(origin).ensuring(_.isConst)
631638
if approx.elems.exists:
632-
case Existential.Var(_) => true
639+
case Existential.VarOLD(_) => true
640+
case Existential.Vble(_) => true
633641
case _ => false
634642
then
635643
ccState.approxWarnings +=
@@ -1304,7 +1312,7 @@ object CaptureSet:
13041312
ref1.captureSetOfInfo.map(ReadOnlyMap())
13051313
case _ =>
13061314
if ref.isMaxCapability then ref.singletonCaptureSet
1307-
else ofType(ref.underlying, followResult = true)
1315+
else ofType(ref.underlying, followResult = true) // TODO: why followResult = true?
13081316

13091317
/** Capture set of a type */
13101318
def ofType(tp: Type, followResult: Boolean)(using Context): CaptureSet =
@@ -1317,7 +1325,9 @@ object CaptureSet:
13171325
case tp: (TypeRef | TypeParamRef) =>
13181326
if tp.derivesFrom(defn.Caps_CapSet) then tp.captureSet
13191327
else empty
1320-
case tp @ Existential.Var(_) =>
1328+
case tp @ Existential.VarOLD(_) =>
1329+
tp.captureSet
1330+
case tp @ Existential.Vble(_) =>
13211331
tp.captureSet
13221332
case CapturingType(parent, refs) =>
13231333
recur(parent) ++ refs
@@ -1332,8 +1342,11 @@ object CaptureSet:
13321342
CaptureSet.ofTypeDeeply(parent.widen)
13331343
case tpd @ defn.RefinedFunctionOf(rinfo: MethodType) if followResult =>
13341344
ofType(tpd.parent, followResult = false) // pick up capture set from parent type
1335-
++ (recur(rinfo.resType) // add capture set of result
1336-
-- CaptureSet(rinfo.paramRefs.filter(_.isTracked)*)) // but disregard bound parameters
1345+
++ recur(rinfo.resType) // add capture set of result
1346+
.filter:
1347+
case TermParamRef(binder, _) => binder ne rinfo
1348+
case Existential.Vble(binder) => binder ne rinfo
1349+
case _ => true
13371350
case tpd @ AppliedType(tycon, args) =>
13381351
if followResult && defn.isNonRefinedFunction(tpd) then
13391352
recur(args.last)
@@ -1359,7 +1372,7 @@ object CaptureSet:
13591372
* capture sets. Nested existential sets are approximated with `cap`.
13601373
* NOTE: The traversal logic needs to be in sync with narrowCaps in CaptureOps, which
13611374
* replaces caps with reach capabilties. The one exception to this is invariant
1362-
* arguments. This have to be included to be conservative in dcs but must be
1375+
* arguments. These have to be included to be conservative in dcs but must be
13631376
* excluded in narrowCaps.
13641377
*/
13651378
def ofTypeDeeply(tp: Type, includeTypevars: Boolean = false)(using Context): CaptureSet =
@@ -1377,9 +1390,9 @@ object CaptureSet:
13771390
val upper = t.info.bounds.hi
13781391
if includeTypevars && upper.isExactlyAny then CaptureSet.fresh(t.symbol)
13791392
else this(cs, upper)
1380-
case t @ FunctionOrMethod(args, res @ Existential(_, _))
1381-
if args.forall(_.isAlwaysPure) =>
1382-
this(cs, Existential.toCap(res))
1393+
case t @ FunctionOrMethod(args, res) =>
1394+
if args.forall(_.isAlwaysPure) then this(cs, Existential.toCap(res))
1395+
else cs
13831396
case t @ Existential(_, _) =>
13841397
cs
13851398
case _ =>

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import CCState.*
2323
import StdNames.nme
2424
import NameKinds.{DefaultGetterName, WildcardParamName, UniqueNameKind}
2525
import reporting.{trace, Message, OverrideError}
26-
import Existential.derivedExistentialType
26+
import Existential.derivedExistentialTypeOLD
2727
import Annotations.Annotation
2828

2929
/** The capture checker */
@@ -850,7 +850,7 @@ class CheckCaptures extends Recheck, SymTransformer:
850850
// added capture set to result.
851851
augmentConstructorType(parent, initCs ++ refs)
852852
case core @ Existential(boundVar, core1) =>
853-
core.derivedExistentialType(augmentConstructorType(core1, initCs))
853+
core.derivedExistentialTypeOLD(augmentConstructorType(core1, initCs))
854854
case _ =>
855855
val (refined, cs) = addParamArgRefinements(core, initCs)
856856
refined.capturing(cs)
@@ -922,7 +922,7 @@ class CheckCaptures extends Recheck, SymTransformer:
922922
// which are less intelligible. An example is the line `a = x` in
923923
// neg-custom-args/captures/vars.scala. That's why this code is conditioned.
924924
// to apply only to closures that are not eta expansions.
925-
val res1 = Existential.toCapDeeply(res)
925+
val res1 = Existential.toCapDeeply(res) // TODO: why toCapDeeply?
926926
val pt1 = Existential.toCapDeeply(pt)
927927
// We need to open existentials here in order not to get vars mixed up in them
928928
// We do the proper check with existentials when we are finished with the closure block.
@@ -1433,7 +1433,7 @@ class CheckCaptures extends Recheck, SymTransformer:
14331433
// Get existentials and wildcards out of the way
14341434
actual match
14351435
case actual @ Existential(_, actualUnpacked) =>
1436-
return Existential.derivedExistentialType(actual):
1436+
return Existential.derivedExistentialTypeOLD(actual):
14371437
recur(actualUnpacked, expected, covariant)
14381438
case _ =>
14391439
expected match

0 commit comments

Comments
 (0)