Skip to content

Commit 695e18f

Browse files
committed
Implement Mutable decomposition
Still missing: Make Mutable an Unscoped
1 parent 82c74ff commit 695e18f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+206
-220
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ object Capabilities:
564564
case _ => false
565565

566566
def derivesFromCapability(using Context): Boolean = derivesFromCapTrait(defn.Caps_Capability)
567-
def derivesFromMutable(using Context): Boolean = derivesFromCapTrait(defn.Caps_Mutable)
567+
def derivesFromStateful(using Context): Boolean = derivesFromCapTrait(defn.Caps_Stateful)
568568
def derivesFromShared(using Context): Boolean = derivesFromCapTrait(defn.Caps_SharedCapability)
569569

570570
/** The capture set consisting of exactly this reference */

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import tpd.*
1313
import Annotations.Annotation
1414
import CaptureSet.VarState
1515
import Capabilities.*
16-
import Mutability.isMutableType
16+
import Mutability.isStatefulType
1717
import StdNames.nme
1818
import config.Feature
1919
import NameKinds.TryOwnerName
@@ -395,7 +395,7 @@ extension (tp: Type)
395395
false
396396

397397
def derivesFromCapability(using Context): Boolean = derivesFromCapTrait(defn.Caps_Capability)
398-
def derivesFromMutable(using Context): Boolean = derivesFromCapTrait(defn.Caps_Mutable)
398+
def derivesFromStateful(using Context): Boolean = derivesFromCapTrait(defn.Caps_Stateful)
399399
def derivesFromShared(using Context): Boolean = derivesFromCapTrait(defn.Caps_SharedCapability)
400400
def derivesFromExclusive(using Context): Boolean = derivesFromCapTrait(defn.Caps_ExclusiveCapability)
401401

@@ -531,7 +531,7 @@ extension (cls: ClassSymbol)
531531
else defn.AnyClass
532532

533533
def isSeparate(using Context): Boolean =
534-
cls.typeRef.isMutableType
534+
cls.typeRef.isStatefulType || cls.derivesFrom(defn.Caps_Separate)
535535

536536
extension (sym: Symbol)
537537

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

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ sealed abstract class CaptureSet extends Showable:
5959
def mutability_=(x: Mutability): Unit =
6060
myMut = x
6161

62-
/** Mark this capture set as belonging to a Mutable type. Called when a new
62+
/** Mark this capture set as belonging to a Stateful type. Called when a new
6363
* CapturingType is formed. This is different from the setter `mutability_=`
64-
* in that it be defined with different behaviors:
64+
* in that it can be defined with different behaviors:
6565
*
66-
* - set mutability to Mutable (for normal Vars)
66+
* - set mutability to Writer (for normal Vars)
6767
* - take mutability from the set's sources (for DerivedVars)
6868
* - compute mutability on demand based on mutability of elements (for Consts)
6969
*/
70-
def associateWithMutable()(using Context): CaptureSet
70+
def associateWithStateful()(using Context): CaptureSet
7171

7272
/** Is this capture set constant (i.e. not an unsolved capture variable)?
7373
* Solved capture variables count as constant.
@@ -191,7 +191,7 @@ sealed abstract class CaptureSet extends Showable:
191191
newElems.forall(tryInclude(_, origin))
192192

193193
protected def mutableToReader(origin: CaptureSet)(using Context): Boolean =
194-
if mutability == Mutable then toReader() else true
194+
if mutability == Writer then toReader() else true
195195

196196
/** Add an element to this capture set, assuming it is not already accounted for,
197197
* and omitting any mapping or filtering.
@@ -315,8 +315,8 @@ sealed abstract class CaptureSet extends Showable:
315315
def adaptMutability(that: CaptureSet)(using Context): CaptureSet | Null =
316316
val m1 = this.mutability
317317
val m2 = that.mutability
318-
if m1 == Mutable && m2 == Reader then this.readOnly
319-
else if m1 == Reader && m2 == Mutable then
318+
if m1 == Writer && m2 == Reader then this.readOnly
319+
else if m1 == Reader && m2 == Writer then
320320
if that.toReader() then this else null
321321
else this
322322

@@ -542,13 +542,13 @@ object CaptureSet:
542542
type Deps = SimpleIdentitySet[CaptureSet]
543543

544544
enum Mutability:
545-
case Mutable, Reader, Ignored
545+
case Writer, Reader, Ignored
546546

547547
def | (that: Mutability): Mutability =
548548
if this == that then this
549549
else if this == Ignored || that == Ignored then Ignored
550550
else if this == Reader || that == Reader then Reader
551-
else Mutable
551+
else Writer
552552

553553
def & (that: Mutability): Mutability =
554554
if this == that then this
@@ -569,9 +569,9 @@ object CaptureSet:
569569
@sharable // sharable since the set is empty, so mutability won't be set
570570
val empty: CaptureSet.Const = Const(emptyRefs)
571571

572-
/** The empty capture set `{}` of a Mutable type, with Reader status */
573-
@sharable // sharable since the set is empty, so mutability won't be set
574-
val emptyOfMutable: CaptureSet.Const =
572+
/** The empty capture set `{}` of a Stateful type, with Reader status */
573+
@sharable // sharable since the set is empty, so mutability won't be re-set
574+
val emptyOfStateful: CaptureSet.Const =
575575
val cs = Const(emptyRefs)
576576
cs.mutability = Mutability.Reader
577577
cs
@@ -630,15 +630,15 @@ object CaptureSet:
630630

631631
private var isComplete = true
632632

633-
def associateWithMutable()(using Context): CaptureSet =
634-
if elems.isEmpty then emptyOfMutable
633+
def associateWithStateful()(using Context): CaptureSet =
634+
if elems.isEmpty then emptyOfStateful
635635
else
636636
isComplete = false // delay computation of Mutability status
637637
this
638638

639639
override def mutability(using Context): Mutability =
640640
if !isComplete then
641-
myMut = if maybeExclusive then Mutable else Reader
641+
myMut = if maybeExclusive then Writer else Reader
642642
isComplete = true
643643
myMut
644644

@@ -652,7 +652,7 @@ object CaptureSet:
652652
else ""
653653

654654
private def capImpliedByCapability(parent: Type)(using Context): Capability =
655-
if parent.derivesFromMutable then GlobalCap.readOnly else GlobalCap
655+
if parent.derivesFromStateful then GlobalCap.readOnly else GlobalCap
656656

657657
/* The same as {cap} but generated implicitly for references of Capability subtypes.
658658
*/
@@ -665,13 +665,14 @@ object CaptureSet:
665665
* nulls, this provides more lenient checking against compilation units that
666666
* were not yet compiled with capture checking on.
667667
*/
668-
@sharable // sharable since the set is empty, so setMutable is a no-op
668+
@sharable
669669
object Fluid extends Const(emptyRefs):
670670
override def isAlwaysEmpty(using Context) = false
671671
override def addThisElem(elem: Capability)(using Context, VarState) = true
672672
override def toReader()(using Context) = true
673673
override def accountsFor(x: Capability)(using Context)(using VarState): Boolean = true
674674
override def mightAccountFor(x: Capability)(using Context): Boolean = true
675+
override def mutability_=(x: Mutability): Unit = ()
675676
override def toString = "<fluid>"
676677
end Fluid
677678

@@ -727,8 +728,8 @@ object CaptureSet:
727728
*/
728729
var deps: Deps = SimpleIdentitySet.empty
729730

730-
def associateWithMutable()(using Context): CaptureSet =
731-
mutability = Mutable
731+
def associateWithStateful()(using Context): CaptureSet =
732+
mutability = Writer
732733
this
733734

734735
def isConst(using Context) = solved >= ccState.iterationId
@@ -846,7 +847,7 @@ object CaptureSet:
846847
if isConst then failWith(MutAdaptFailure(this))
847848
else
848849
mutability = Reader
849-
TypeComparer.logUndoAction(() => mutability = Mutable)
850+
TypeComparer.logUndoAction(() => mutability = Writer)
850851
deps.forall(_.mutableToReader(this))
851852

852853
private def isPartOf(binder: Type)(using Context): Boolean =
@@ -933,7 +934,7 @@ object CaptureSet:
933934
def markSolved(provisional: Boolean)(using Context): Unit =
934935
solved = if provisional then ccState.iterationId else Int.MaxValue
935936
deps.foreach(_.propagateSolved(provisional))
936-
if mutability == Mutable && !maybeExclusive then mutability = Reader
937+
if mutability == Writer && !maybeExclusive then mutability = Reader
937938

938939

939940
var skippedMaps: Set[TypeMap] = Set.empty
@@ -1046,7 +1047,7 @@ object CaptureSet:
10461047
addAsDependentTo(source)
10471048

10481049
/** Mutability is same as in source, except for readOnly */
1049-
override def associateWithMutable()(using Context): CaptureSet = this
1050+
override def associateWithStateful()(using Context): CaptureSet = this
10501051

10511052
override def mutableToReader(origin: CaptureSet)(using Context): Boolean =
10521053
super.mutableToReader(origin)
@@ -1175,8 +1176,8 @@ object CaptureSet:
11751176
super.mutableToReader(origin)
11761177
&& {
11771178
if (origin eq cs1) || (origin eq cs2) then true
1178-
else if cs1.isConst && cs1.mutability == Mutable then cs2.mutableToReader(this)
1179-
else if cs2.isConst && cs2.mutability == Mutable then cs1.mutableToReader(this)
1179+
else if cs1.isConst && cs1.mutability == Writer then cs2.mutableToReader(this)
1180+
else if cs2.isConst && cs2.mutability == Writer then cs1.mutableToReader(this)
11801181
else true
11811182
}
11821183

@@ -1403,7 +1404,7 @@ object CaptureSet:
14031404
else i"$elem cannot be included in $cs"
14041405
end IncludeFailure
14051406

1406-
/** Failure indicating that a read-only capture set of a mutable type cannot be
1407+
/** Failure indicating that a read-only capture set of a stateful type cannot be
14071408
* widened to an exclusive set.
14081409
* @param cs the exclusive set in question
14091410
* @param lo the lower type of the orginal type comparison, or NoType if not known
@@ -1412,7 +1413,7 @@ object CaptureSet:
14121413
case class MutAdaptFailure(cs: CaptureSet, lo: Type = NoType, hi: Type = NoType) extends Note:
14131414

14141415
def render(using Context): String =
1415-
def ofType(tp: Type) = if tp.exists then i"of the mutable type $tp" else "of a mutable type"
1416+
def ofType(tp: Type) = if tp.exists then i"of the stateful type $tp" else "of a stateful type"
14161417
i"""
14171418
|
14181419
|Note that $cs is an exclusive capture set ${ofType(hi)},

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ object CapturingType:
4141
apply(parent1, refs ++ refs1, boxed)
4242
case _ =>
4343
val refs1 =
44-
if parent.derivesFromMutable then refs.associateWithMutable() else refs
44+
if parent.derivesFromStateful then refs.associateWithStateful() else refs
4545
refs1.adoptClassifier(parent.inheritedClassifier)
4646
AnnotatedType(parent, CaptureAnnotation(refs1, boxed)(defn.RetainsAnnot))
4747

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ class CheckCaptures extends Recheck, SymTransformer:
597597
if nextEnv != null && !nextEnv.owner.isStaticOwner then
598598
if nextEnv.owner != env.owner
599599
&& env.owner.isReadOnlyMember
600-
&& env.owner.owner.derivesFrom(defn.Caps_Mutable)
600+
&& env.owner.owner.derivesFrom(defn.Caps_Stateful)
601601
then
602602
checkReadOnlyMethod(included, env.owner)
603603
recur(included, nextEnv, env)
@@ -961,7 +961,7 @@ class CheckCaptures extends Recheck, SymTransformer:
961961
/** The additional capture set implied by the capture sets of its fields. This
962962
* is either empty or, if some fields have a terminal capability in their span
963963
* capture sets, it consists of a single fresh cap that subsumes all these terminal
964-
* capabiltities. Class parameters are not counted. If the type is a mutable type,
964+
* capabiltities. Class parameters are not counted. If the type externds Separate,
965965
* we add a fresh cap in any case -- this is because we can currently hide
966966
* mutability in array vals, an example is neg-customargs/captures/matrix.scala.
967967
*/
@@ -1164,10 +1164,10 @@ class CheckCaptures extends Recheck, SymTransformer:
11641164
tree.tpt.nuType, NoSymbol, i"Mutable $sym", "have type", addendum, sym.srcPos)
11651165
if ccConfig.noUnsafeMutableFields
11661166
&& sym.owner.isClass
1167-
&& !sym.owner.derivesFrom(defn.Caps_Mutable)
1167+
&& !sym.owner.derivesFrom(defn.Caps_Stateful)
11681168
&& !sym.hasAnnotation(defn.UntrackedCapturesAnnot) then
11691169
report.error(
1170-
em"""Mutable $sym is defined in a class that does not extend `Mutable`.
1170+
em"""Mutable $sym is defined in a class that does not extend `Stateful`.
11711171
|The variable needs to be annotated with `untrackedCaptures` to allow this.""",
11721172
tree.namePos)
11731173

@@ -1865,7 +1865,7 @@ class CheckCaptures extends Recheck, SymTransformer:
18651865
if needsAdaptation && !insertBox then // we are unboxing
18661866
val criticalSet = // the set with which we unbox
18671867
if covariant then
1868-
if expected.expectsReadOnly && actual.derivesFromMutable
1868+
if expected.expectsReadOnly && actual.derivesFromStateful
18691869
then captures.readOnly
18701870
else captures
18711871
else expected.captureSet // contravarant: we unbox with captures of epected type
@@ -2240,18 +2240,18 @@ class CheckCaptures extends Recheck, SymTransformer:
22402240
end for
22412241
end checkEscapingUses
22422242

2243-
/** Check all parent class constructors of classes extending Mutable
2244-
* either also extend Mutable or are read-only.
2243+
/** Check all parent class constructors of classes extending Stateful
2244+
* either also extend Stateful or are read-only.
22452245
*
22462246
* A parent class constructor is _read-only_ if the following conditions are met
22472247
* 1. The class does not retain any exclusive capabilities from its environment.
22482248
* 2. The constructor does not take arguments that retain exclusive capabilities.
22492249
* 3. The class does not does not have fields that retain exclusive universal capabilities.
22502250
*/
2251-
def checkMutableInheritance(cls: ClassSymbol, parents: List[Tree])(using Context): Unit =
2252-
if cls.derivesFrom(defn.Caps_Mutable) then
2251+
def checkStatefulInheritance(cls: ClassSymbol, parents: List[Tree])(using Context): Unit =
2252+
if cls.derivesFrom(defn.Caps_Stateful) then
22532253
for parent <- parents do
2254-
if !parent.tpe.derivesFromMutable then
2254+
if !parent.tpe.derivesFromStateful then
22552255
val pcls = parent.nuType.classSymbol
22562256
val parentIsExclusive =
22572257
if parent.isType then
@@ -2261,17 +2261,17 @@ class CheckCaptures extends Recheck, SymTransformer:
22612261
else parent.nuType.captureSet.isExclusive
22622262
if parentIsExclusive then
22632263
report.error(
2264-
em"""illegal inheritance: $cls which extends `Mutable` is not allowed to also extend $pcls
2265-
|since $pcls retains exclusive capabilities but does not extend `Mutable`.""",
2264+
em"""illegal inheritance: $cls which extends `Stateful` is not allowed to also extend $pcls
2265+
|since $pcls retains exclusive capabilities but does not extend `Stateful`.""",
22662266
parent.srcPos)
22672267

22682268
/** Checks to run after the rechecking pass:
22692269
* - Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
22702270
* - Check that no uses refer to reach capabilities of parameters of enclosing
22712271
* methods or classes.
22722272
* - Run the separation checker under language.experimental.separationChecking
2273-
* - Check that classes extending Mutable do not extend other classes that do
2274-
* not extend Mutable yet retain exclusive capabilities
2273+
* - Check that classes extending Stateful do not extend other classes that do
2274+
* not extend Stateful yet retain exclusive capabilities
22752275
*/
22762276
def postCheck(unit: tpd.Tree)(using Context): Unit =
22772277
val checker = new TreeTraverser:
@@ -2296,7 +2296,7 @@ class CheckCaptures extends Recheck, SymTransformer:
22962296
args.lazyZip(tl.paramNames).foreach(checkTypeParam(_, _, fun.symbol))
22972297
case _ =>
22982298
case TypeDef(_, impl: Template) =>
2299-
checkMutableInheritance(tree.symbol.asClass, impl.parents)
2299+
checkStatefulInheritance(tree.symbol.asClass, impl.parents)
23002300
case _ =>
23012301
end checker
23022302

0 commit comments

Comments
 (0)