Skip to content

Commit efa14d5

Browse files
committed
Add a prefix to FreshCaps
The prefix is mapped as a normal type. It determines whether the hidden set allows to add new elements. ThisType and NoPrefix prefixes allow it, other prefixes forbid it.
1 parent 3c9d209 commit efa14d5

File tree

5 files changed

+44
-10
lines changed

5 files changed

+44
-10
lines changed

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

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,21 @@ object Capabilities:
148148
* @param origin an indication where and why the FreshCap was created, used
149149
* for diagnostics
150150
*/
151-
case class FreshCap private (owner: Symbol, origin: Origin)(using @constructorOnly ctx: Context) extends RootCapability:
152-
val hiddenSet = CaptureSet.HiddenSet(owner, this: @unchecked)
151+
case class FreshCap(val prefix: Type)
152+
(val owner: Symbol, val origin: Origin, origHidden: CaptureSet.HiddenSet | Null)
153+
(using @constructorOnly ctx: Context)
154+
extends RootCapability:
155+
val hiddenSet =
156+
if origHidden == null then CaptureSet.HiddenSet(owner, this: @unchecked)
157+
else origHidden
153158
// fails initialization check without the @unchecked
154159

160+
def derivedFreshCap(newPrefix: Type)(using Context): FreshCap =
161+
if newPrefix eq prefix then this
162+
else FreshCap(newPrefix)(owner, origin, hiddenSet)
163+
164+
//assert(rootId != 10, i"fresh $prefix, ${ctx.owner}")
165+
155166
/** Is this fresh cap (definitely) classified? If that's the case, the
156167
* classifier cannot be changed anymore.
157168
* We need to distinguish `FreshCap`s that can still be classified from
@@ -198,8 +209,10 @@ object Capabilities:
198209
i"a fresh root capability$classifierStr$originStr"
199210

200211
object FreshCap:
212+
def apply(prefix: Type, origin: Origin)(using Context): FreshCap =
213+
new FreshCap(prefix)(ctx.owner, origin, null)
201214
def apply(origin: Origin)(using Context): FreshCap =
202-
FreshCap(ctx.owner, origin)
215+
apply(ctx.owner.skipWeakOwner.thisType, origin)
203216

204217
/** A root capability associated with a function type. These are conceptually
205218
* existentially quantified over the function's result type.
@@ -703,12 +716,24 @@ object Capabilities:
703716
(this eq y)
704717
|| this.match
705718
case x: FreshCap =>
719+
def classifierOK =
720+
if y.tryClassifyAs(x.hiddenSet.classifier) then true
721+
else
722+
capt.println(i"$y cannot be classified as $x")
723+
false
724+
725+
def prefixAllowsAddHidden: Boolean = x.prefix match
726+
case NoPrefix | _: ThisType => true
727+
case _ if CCState.collapseFresh => true
728+
case pre =>
729+
capt.println(i"fresh not open $x, ${x.rootId}, $pre, ${x.ccOwner.skipWeakOwner.thisType}")
730+
false
731+
706732
vs.ifNotSeen(this)(x.hiddenSet.elems.exists(_.subsumes(y)))
707733
|| x.acceptsLevelOf(y)
708-
&& ( y.tryClassifyAs(x.hiddenSet.classifier)
709-
|| { capt.println(i"$y cannot be classified as $x"); false }
710-
)
734+
&& classifierOK
711735
&& canAddHidden
736+
&& prefixAllowsAddHidden
712737
&& vs.addHidden(x.hiddenSet, y)
713738
case x: ResultCap =>
714739
val result = y match

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,10 @@ object CaptureSet:
559559
def universal(using Context): Const =
560560
Const(SimpleIdentitySet(GlobalCap))
561561

562+
def fresh(prefix: Type, origin: Origin)(using Context): Const =
563+
FreshCap(prefix, origin).singletonCaptureSet
562564
def fresh(origin: Origin)(using Context): Const =
563-
FreshCap(origin).singletonCaptureSet
565+
fresh(ctx.owner.thisType, origin)
564566

565567
/** The shared capture set `{cap.rd}` */
566568
def shared(using Context): Const =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
694694
if cls.derivesFrom(defn.Caps_Capability) then
695695
// If cls is a capability class, we need to add a fresh readonly capability to
696696
// ensure we cannot treat the class as pure.
697-
CaptureSet.fresh(Origin.InDecl(cls)).readOnly.subCaptures(cs)
697+
CaptureSet.fresh(cls.thisType, Origin.InDecl(cls)).readOnly.subCaptures(cs)
698698
CapturingType(cinfo.selfType, cs)
699699

700700
// Compute new parent types

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6312,6 +6312,8 @@ object Types extends TypeUtils {
63126312
null
63136313

63146314
def mapCapability(c: Capability, deep: Boolean = false): Capability | (CaptureSet, Boolean) = c match
6315+
case c @ FreshCap(prefix) =>
6316+
c.derivedFreshCap(apply(prefix))
63156317
case c: RootCapability => c
63166318
case Reach(c1) =>
63176319
mapCapability(c1, deep = true)

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,13 @@ class PlainPrinter(_ctx: Context) extends Printer {
496496
def classified =
497497
if c.hiddenSet.classifier == defn.AnyClass then ""
498498
else s" classified as ${c.hiddenSet.classifier.name.show}"
499-
if ccVerbose then s"<fresh$idStr in ${c.ccOwner} hiding " ~ toTextCaptureSet(c.hiddenSet) ~ classified ~ ">"
500-
else "cap"
499+
def prefixTxt: Text = c.prefix match
500+
case NoPrefix | _: ThisType => ""
501+
case pre => pre.show ~ "."
502+
def core: Text =
503+
if ccVerbose then s"<fresh$idStr in ${c.ccOwner} hiding " ~ toTextCaptureSet(c.hiddenSet) ~ classified ~ ">"
504+
else "cap"
505+
prefixTxt ~ core
501506
case tp: TypeProxy =>
502507
homogenize(tp) match
503508
case tp: SingletonType => toTextRef(tp)

0 commit comments

Comments
 (0)