@@ -100,6 +100,8 @@ class CCState:
100
100
101
101
private var openExistentialScopes : List [MethodType ] = Nil
102
102
103
+ private var capIsRoot : Boolean = false
104
+
103
105
object CCState :
104
106
105
107
opaque type Level = Int
@@ -144,6 +146,21 @@ object CCState:
144
146
else
145
147
op
146
148
149
+ /** Run `op` under the assumption that `cap` can subsume all other capabilties
150
+ * except Result capabilities. Every use of this method should be scrutinized
151
+ * for whether it introduces an unsoundness hole.
152
+ */
153
+ inline def withCapAsRoot [T ](op : => T )(using Context ): T =
154
+ if isCaptureCheckingOrSetup then
155
+ val ccs = ccState
156
+ val saved = ccs.capIsRoot
157
+ ccs.capIsRoot = true
158
+ try op finally ccs.capIsRoot = saved
159
+ else op
160
+
161
+ /** Is `caps.cap` a root capability that is allowed to subsume other capabilities? */
162
+ def capIsRoot (using Context ): Boolean = ccState.capIsRoot
163
+
147
164
/** The currently opened existential scopes */
148
165
def openExistentialScopes (using Context ): List [MethodType ] = ccState.openExistentialScopes
149
166
@@ -441,14 +458,30 @@ extension (tp: Type)
441
458
case AppliedType (tycon, _) => ! defn.isFunctionSymbol(tycon.typeSymbol)
442
459
case _ => false
443
460
444
- /** Tests whether the type derives from `caps.Capability`, which means
445
- * references of this type are maximal capabilities.
446
- */
447
- def derivesFromCapTrait (cls : ClassSymbol )(using Context ): Boolean = tp.dealias match
461
+ /** Tests whether all CapturingType parts of the type that are traversed for
462
+ * dcs computation satisfy at least one of two conditions:
463
+ * 1. They decorate classes that extend the given capability class `cls`, or
464
+ * 2. Their capture set is constant and consists only of capabilities
465
+ * the derive from `cls` in the sense of `derivesFromCapTrait`.
466
+ */
467
+ def derivesFromCapTraitDeeply (cls : ClassSymbol )(using Context ): Boolean =
468
+ val accumulate = new DeepTypeAccumulator [Boolean ]:
469
+ def capturingCase (acc : Boolean , parent : Type , refs : CaptureSet ) =
470
+ this (acc, parent)
471
+ && (parent.derivesFromCapTrait(cls)
472
+ || refs.isConst && refs.elems.forall(_.derivesFromCapTrait(cls)))
473
+ def abstractTypeCase (acc : Boolean , t : TypeRef , upperBound : Type ) =
474
+ this (acc, upperBound)
475
+ accumulate(true , tp)
476
+
477
+ /** Tests whether the type derives from capability class `cls`. */
478
+ def derivesFromCapTrait (cls : ClassSymbol )(using Context ): Boolean = tp.dealiasKeepAnnots match
448
479
case tp : (TypeRef | AppliedType ) =>
449
480
val sym = tp.typeSymbol
450
481
if sym.isClass then sym.derivesFrom(cls)
451
482
else tp.superType.derivesFromCapTrait(cls)
483
+ case ReachCapability (tp1) =>
484
+ tp1.widen.derivesFromCapTraitDeeply(cls)
452
485
case tp : (TypeProxy & ValueType ) =>
453
486
tp.superType.derivesFromCapTrait(cls)
454
487
case tp : AndType =>
@@ -545,7 +578,7 @@ extension (tp: Type)
545
578
var change = false
546
579
def apply (t : Type ) =
547
580
if variance <= 0 then t
548
- else t.dealiasKeepAnnots match
581
+ else t.dealias match
549
582
case t @ CapturingType (p, cs) if cs.containsRootCapability =>
550
583
change = true
551
584
val reachRef = if cs.isReadOnly then ref.reach.readOnly else ref.reach
@@ -804,33 +837,6 @@ object ReadOnlyCapability extends AnnotatedCapability(defn.ReadOnlyCapabilityAnn
804
837
object ReachCapability extends AnnotatedCapability (defn.ReachCapabilityAnnot ):
805
838
protected def unwrappable (using Context ) = Set (defn.MaybeCapabilityAnnot , defn.ReadOnlyCapabilityAnnot )
806
839
807
- /** Offers utility method to be used for type maps that follow aliases */
808
- trait ConservativeFollowAliasMap (using Context ) extends TypeMap :
809
-
810
- /** If `mapped` is a type alias, apply the map to the alias, while keeping
811
- * annotations. If the result is different, return it, otherwise return `mapped`.
812
- * Furthermore, if `original` is a LazyRef or TypeVar and the mapped result is
813
- * the same as the underlying type, keep `original`. This avoids spurious differences
814
- * which would lead to spurious dealiasing in the result
815
- */
816
- protected def applyToAlias (original : Type , mapped : Type ) =
817
- val mapped1 = mapped match
818
- case t : (TypeRef | AppliedType ) =>
819
- val t1 = t.dealiasKeepAnnots
820
- if t1 eq t then t
821
- else
822
- // If we see a type alias, map the alias type and keep it if it's different
823
- val t2 = apply(t1)
824
- if t2 ne t1 then t2 else t
825
- case _ =>
826
- mapped
827
- original match
828
- case original : (LazyRef | TypeVar ) if mapped1 eq original.underlying =>
829
- original
830
- case _ =>
831
- mapped1
832
- end ConservativeFollowAliasMap
833
-
834
840
/** An extractor for all kinds of function types as well as method and poly types.
835
841
* It includes aliases of function types such as `=>`. TODO: Can we do without?
836
842
* @return 1st half: The argument types or empty if this is a type function
@@ -884,3 +890,36 @@ object ContainsParam:
884
890
if tycon.typeSymbol == defn.Caps_ContainsTrait
885
891
&& cs.typeSymbol.isAbstractOrParamType => Some ((cs, ref))
886
892
case _ => None
893
+
894
+ /** A class encapsulating the assumulator logic needed for `CaptureSet.ofTypeDeeply`
895
+ * and `derivesFromCapTraitDeeply`.
896
+ * NOTE: The traversal logic needs to be in sync with narrowCaps in CaptureOps, which
897
+ * replaces caps with reach capabilties. There are two exceptions, however.
898
+ * - First, invariant arguments. These have to be included to be conservative
899
+ * in dcs but must be excluded in narrowCaps.
900
+ * - Second, unconstrained type variables are handled specially in `ofTypeDeeply`.
901
+ */
902
+ abstract class DeepTypeAccumulator [T ](using Context ) extends TypeAccumulator [T ]:
903
+ val seen = util.HashSet [Symbol ]()
904
+
905
+ protected def capturingCase (acc : T , parent : Type , refs : CaptureSet ): T
906
+
907
+ protected def abstractTypeCase (acc : T , t : TypeRef , upperBound : Type ): T
908
+
909
+ def apply (acc : T , t : Type ) =
910
+ if variance < 0 then acc
911
+ else t.dealias match
912
+ case t @ CapturingType (p, cs1) =>
913
+ capturingCase(acc, p, cs1)
914
+ case t : TypeRef if t.symbol.isAbstractOrParamType && ! seen.contains(t.symbol) =>
915
+ seen += t.symbol
916
+ abstractTypeCase(acc, t, t.info.bounds.hi)
917
+ case AnnotatedType (parent, _) =>
918
+ this (acc, parent)
919
+ case t @ FunctionOrMethod (args, res) =>
920
+ if args.forall(_.isAlwaysPure) then this (acc, root.resultToFresh(res))
921
+ else acc
922
+ case _ =>
923
+ foldOver(acc, t)
924
+ end DeepTypeAccumulator
925
+
0 commit comments