Skip to content

Commit edfe896

Browse files
committed
Revert "Polishings"
This reverts commit 0a37cc1.
1 parent 2bfafe5 commit edfe896

File tree

18 files changed

+77
-133
lines changed

18 files changed

+77
-133
lines changed

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

+4-18
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,7 @@ extension (tp: Type)
232232
case tp @ ReachCapability(_) =>
233233
tp.singletonCaptureSet
234234
case ReadOnlyCapability(ref) =>
235-
val refDcs = ref.deepCaptureSet(includeTypevars)
236-
if refDcs.isConst then CaptureSet(refDcs.elems.map(_.readOnly))
237-
else refDcs // this case should not happen for correct programs
235+
ref.deepCaptureSet(includeTypevars)
238236
case tp: SingletonCaptureRef if tp.isTrackableRef =>
239237
tp.reach.singletonCaptureSet
240238
case _ =>
@@ -281,19 +279,17 @@ extension (tp: Type)
281279
case _ =>
282280
tp
283281

284-
/** The first element of this path type. Note that class parameter references
285-
* are of the form this.C but their pathroot is still this.C, not this.
286-
*/
282+
/** The first element of this path type */
287283
final def pathRoot(using Context): Type = tp.dealias match
288284
case tp1: TermRef if tp1.symbol.maybeOwner.isClass => tp1.prefix.pathRoot
289285
case tp1: TypeRef if !tp1.symbol.is(Param) => tp1.prefix.pathRoot
290286
case tp1 => tp1
291287

292288
/** The first element of a path type, but stop at references extending
293-
* SharedCapability.
289+
* SharableCapability
294290
*/
295291
final def pathRootOrShared(using Context): Type =
296-
if tp.derivesFromSharedCapability then tp
292+
if tp.derivesFrom(defn.Caps_SharedCapability) then tp
297293
else tp.dealias match
298294
case tp1: TermRef if tp1.symbol.maybeOwner.isClass => tp1.prefix.pathRoot
299295
case tp1: TypeRef if !tp1.symbol.is(Param) => tp1.prefix.pathRoot
@@ -431,7 +427,6 @@ extension (tp: Type)
431427

432428
def derivesFromCapability(using Context): Boolean = derivesFromCapTrait(defn.Caps_Capability)
433429
def derivesFromMutable(using Context): Boolean = derivesFromCapTrait(defn.Caps_Mutable)
434-
def derivesFromSharedCapability(using Context): Boolean = derivesFromCapTrait(defn.Caps_SharedCapability)
435430

436431
/** Drop @retains annotations everywhere */
437432
def dropAllRetains(using Context): Type = // TODO we should drop retains from inferred types before unpickling
@@ -471,11 +466,6 @@ extension (tp: Type)
471466
* is the union of all capture sets that appear in covariant position in the
472467
* type of `x`. If `x` and `y` are different variables then `{x*}` and `{y*}`
473468
* are unrelated.
474-
*
475-
* Reach capabilities cannot wrap read-only capabilities or maybe capabilities.
476-
* We have
477-
* (x.rd).reach = x*.rd
478-
* (x.rd)? = (x*)?
479469
*/
480470
def reach(using Context): CaptureRef = tp match
481471
case tp @ AnnotatedType(tp1: CaptureRef, annot)
@@ -493,10 +483,6 @@ extension (tp: Type)
493483
/** If `x` is a capture ref, its read-only capability `x.rd`, represented internally
494484
* as `x @readOnlyCapability`. We have {x.rd} <: {x}. If `x` is a reach capability `y*`,
495485
* then its read-only version is `x.rd*`.
496-
*
497-
* Read-only capabilities cannot wrap maybe capabilities
498-
* but they can wrap reach capabilities. We have
499-
* (x?).readOnly = (x.rd)?
500486
*/
501487
def readOnly(using Context): CaptureRef = tp match
502488
case tp @ AnnotatedType(tp1: CaptureRef, annot)

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

+5-9
Original file line numberDiff line numberDiff line change
@@ -100,25 +100,19 @@ trait CaptureRef extends TypeProxy, ValueType:
100100
/** Is this reference the generic root capability `cap` or a Fresh.Cap instance? */
101101
final def isCapOrFresh(using Context): Boolean = isCap || isFresh
102102

103-
/** Is this reference one of the generic root capabilities `cap` or `cap.rd` ? */
103+
/** Is this reference one the generic root capabilities `cap` or `cap.rd` ? */
104104
final def isRootCapability(using Context): Boolean = this match
105105
case ReadOnlyCapability(tp1) => tp1.isCapOrFresh
106106
case _ => isCapOrFresh
107107

108-
/** Is this reference a capability that does not derive from another capability?
109-
* Includes read-only versions of maximal capabilities.
110-
*/
108+
/** Is this reference capability that does not derive from another capability ? */
111109
final def isMaxCapability(using Context): Boolean = this match
112110
case tp: TermRef => tp.isCap || tp.info.derivesFrom(defn.Caps_Exists)
113111
case tp: TermParamRef => tp.underlying.derivesFrom(defn.Caps_Exists)
114112
case Fresh.Cap(_) => true
115113
case ReadOnlyCapability(tp1) => tp1.isMaxCapability
116114
case _ => false
117115

118-
/** An exclusive capability is a capability that derives
119-
* indirectly from a maximal capability without goinh through
120-
* a read-only capability first.
121-
*/
122116
final def isExclusive(using Context): Boolean =
123117
!isReadOnly && (isMaxCapability || captureSetOfInfo.isExclusive)
124118

@@ -165,6 +159,8 @@ trait CaptureRef extends TypeProxy, ValueType:
165159
* X: CapSet^c1...CapSet^c2, (CapSet^c1) subsumes y ==> X subsumes y
166160
* Y: CapSet^c1...CapSet^c2, x subsumes (CapSet^c2) ==> x subsumes Y
167161
* Contains[X, y] ==> X subsumes y
162+
*
163+
* TODO: Move to CaptureSet
168164
*/
169165
final def subsumes(y: CaptureRef)(using ctx: Context, vs: VarState = VarState.Separate): Boolean =
170166

@@ -243,7 +239,7 @@ trait CaptureRef extends TypeProxy, ValueType:
243239
end subsumes
244240

245241
/** This is a maximal capabaility that subsumes `y` in given context and VarState.
246-
* @param canAddHidden If true we allow maximal capabilities to subsume all other capabilities.
242+
* @param canAddHidden If true we allow maximal capabilties to subsume all other capabilities.
247243
* We add those capabilities to the hidden set if this is Fresh.Cap
248244
* If false we only accept `y` elements that are already in the
249245
* hidden set of this Fresh.Cap. The idea is that in a VarState that

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,7 @@ object CaptureSet:
636636
*/
637637
def solve()(using Context): Unit =
638638
if !isConst then
639-
val approx = upperApprox(empty)
640-
.map(Fresh.FromCap(NoSymbol).inverse) // Fresh.Cap --> cap
639+
val approx = upperApprox(empty).map(Fresh.FromCap(NoSymbol).inverse)
641640
.showing(i"solve $this = $result", capt)
642641
//println(i"solving var $this $approx ${approx.isConst} deps = ${deps.toList}")
643642
val newElems = approx.elems -- elems
@@ -1140,7 +1139,6 @@ object CaptureSet:
11401139

11411140
/** A template for maps on capabilities where f(c) <: c and f(f(c)) = c */
11421141
private abstract class NarrowingCapabilityMap(using Context) extends BiTypeMap:
1143-
11441142
def mapRef(ref: CaptureRef): CaptureRef
11451143

11461144
def apply(t: Type) = t match

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

+22-38
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,8 @@ class CheckCaptures extends Recheck, SymTransformer:
519519
def includeCallCaptures(sym: Symbol, resType: Type, tree: Tree)(using Context): Unit = resType match
520520
case _: MethodOrPoly => // wait until method is fully applied
521521
case _ =>
522-
if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), tree)
522+
if sym.exists then
523+
if curEnv.isOpen then markFree(capturedVars(sym), tree)
523524

524525
/** Under the sealed policy, disallow the root capability in type arguments.
525526
* Type arguments come either from a TypeApply node or from an AppliedType
@@ -555,21 +556,16 @@ class CheckCaptures extends Recheck, SymTransformer:
555556
if param.isUseParam then markFree(arg.nuType.deepCaptureSet, errTree)
556557
end disallowCapInTypeArgs
557558

558-
/** Rechecking idents involves:
559-
* - adding call captures for idents referring to methods
560-
* - marking as free the identifier with any selections or .rd
561-
* modifiers implied by the expected type
562-
*/
563559
override def recheckIdent(tree: Ident, pt: Type)(using Context): Type =
564560
val sym = tree.symbol
565561
if sym.is(Method) then
566562
// If ident refers to a parameterless method, charge its cv to the environment
567563
includeCallCaptures(sym, sym.info, tree)
568564
else if !sym.isStatic then
569-
// Otherwise charge its symbol, but add all selections and also any `.rd`
570-
// modifier implied by the expected type `pt`.
571-
// Example: If we have `x` and the expected type says we select that with `.a.b`
572-
// where `b` is a read-only method, we charge `x.a.b.rd` instead of `x`.
565+
// Otherwise charge its symbol, but add all selections implied by the e
566+
// expected type `pt`.
567+
// Example: If we have `x` and the expected type says we select that with `.a.b`,
568+
// we charge `x.a.b` instead of `x`.
573569
def addSelects(ref: TermRef, pt: Type): CaptureRef = pt match
574570
case pt: PathSelectionProto if ref.isTracked =>
575571
if pt.sym.isReadOnlyMethod then
@@ -586,8 +582,7 @@ class CheckCaptures extends Recheck, SymTransformer:
586582
super.recheckIdent(tree, pt)
587583

588584
/** The expected type for the qualifier of a selection. If the selection
589-
* could be part of a capability path or is a a read-only method, we return
590-
* a PathSelectionProto.
585+
* could be part of a capabaility path, we return a PathSelectionProto.
591586
*/
592587
override def selectionProto(tree: Select, pt: Type)(using Context): Type =
593588
val sym = tree.symbol
@@ -621,9 +616,6 @@ class CheckCaptures extends Recheck, SymTransformer:
621616
}
622617
case _ => denot
623618

624-
// Don't allow update methods to be called unless the qualifier captures
625-
// contain an exclusive referenece. TODO This should probabkly rolled into
626-
// qualifier logic once we have it.
627619
if tree.symbol.isUpdateMethod && !qualType.captureSet.isExclusive then
628620
report.error(
629621
em"""cannot call update ${tree.symbol} from $qualType,
@@ -659,8 +651,8 @@ class CheckCaptures extends Recheck, SymTransformer:
659651
selType
660652
}//.showing(i"recheck sel $tree, $qualType = $result")
661653

662-
/** Hook for massaging a function before it is applied. Copies all @use and @consume
663-
* annotations on method parameter symbols to the corresponding paramInfo types.
654+
/** Hook for massaging a function before it is applied. Copies all @use annotations
655+
* on method parameter symbols to the corresponding paramInfo types.
664656
*/
665657
override def prepareFunction(funtpe: MethodType, meth: Symbol)(using Context): MethodType =
666658
val paramInfosWithUses =
@@ -690,8 +682,7 @@ class CheckCaptures extends Recheck, SymTransformer:
690682
includeCallCaptures(meth, res, tree)
691683
res
692684

693-
/** Recheck argument against a "freshened" version of `formal` where toplevel `cap`
694-
* occurrences are replaced by `Fresh.Cap`. Also, if formal parameter carries a `@use`,
685+
/** Recheck argument, and, if formal parameter carries a `@use`,
695686
* charge the deep capture set of the actual argument to the environment.
696687
*/
697688
protected override def recheckArg(arg: Tree, formal: Type)(using Context): Type =
@@ -782,21 +773,16 @@ class CheckCaptures extends Recheck, SymTransformer:
782773

783774
/** First half of result pair:
784775
* Refine the type of a constructor call `new C(t_1, ..., t_n)`
785-
* to C{val x_1: @refineOverride T_1, ..., x_m: @refineOverride T_m}
786-
* where x_1, ..., x_m are the tracked parameters of C and
787-
* T_1, ..., T_m are the types of the corresponding arguments. The @refineOveride
788-
* annotations avoid problematic intersections of capture sets when those
789-
* parameters are selected.
776+
* to C{val x_1: T_1, ..., x_m: T_m} where x_1, ..., x_m are the tracked
777+
* parameters of C and T_1, ..., T_m are the types of the corresponding arguments.
790778
*
791779
* Second half: union of initial capture set and all capture sets of arguments
792-
* to tracked parameters. The initial capture set `initCs` is augmented with
793-
* - Fresh.Cap if `core` extends Mutable
794-
* - Fresh.Cap.rd if `core` extends Capability
780+
* to tracked parameters.
795781
*/
796782
def addParamArgRefinements(core: Type, initCs: CaptureSet): (Type, CaptureSet) =
797783
var refined: Type = core
798784
var allCaptures: CaptureSet =
799-
if core.derivesFromMutable then initCs ++ CaptureSet.fresh()
785+
if core.derivesFromMutable then CaptureSet.fresh()
800786
else if core.derivesFromCapability then initCs ++ Fresh.Cap().readOnly.singletonCaptureSet
801787
else initCs
802788
for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
@@ -1502,7 +1488,7 @@ class CheckCaptures extends Recheck, SymTransformer:
15021488
/** If actual is a capturing type T^C extending Mutable, and expected is an
15031489
* unboxed non-singleton value type not extending mutable, narrow the capture
15041490
* set `C` to `ro(C)`.
1505-
* The unboxed condition ensures that the expected type is not a type variable
1491+
* The unboxed condition ensures that the expected is not a type variable
15061492
* that's upper bounded by a read-only type. In this case it would not be sound
15071493
* to narrow to the read-only set, since that set can be propagated
15081494
* by the type variable instantiation.
@@ -1528,9 +1514,9 @@ class CheckCaptures extends Recheck, SymTransformer:
15281514
actual
15291515
else
15301516
val improvedVAR = improveCaptures(actual.widen.dealiasKeepAnnots, actual)
1531-
val improved = improveReadOnly(improvedVAR, expected)
1517+
val improvedRO = improveReadOnly(improvedVAR, expected)
15321518
val adapted = adaptBoxed(
1533-
improved.withReachCaptures(actual), expected, tree,
1519+
improvedRO.withReachCaptures(actual), expected, tree,
15341520
covariant = true, alwaysConst = false, boxErrors)
15351521
if adapted eq improvedVAR // no .rd improvement, no box-adaptation
15361522
then actual // might as well use actual instead of improved widened
@@ -1577,19 +1563,17 @@ class CheckCaptures extends Recheck, SymTransformer:
15771563

15781564
/** Check that overrides don't change the @use or @consume status of their parameters */
15791565
override def additionalChecks(member: Symbol, other: Symbol)(using Context): Unit =
1566+
def fail(msg: String) =
1567+
report.error(
1568+
OverrideError(msg, self, member, other, self.memberInfo(member), self.memberInfo(other)),
1569+
if member.owner == clazz then member.srcPos else clazz.srcPos)
15801570
for
15811571
(params1, params2) <- member.rawParamss.lazyZip(other.rawParamss)
15821572
(param1, param2) <- params1.lazyZip(params2)
15831573
do
15841574
def checkAnnot(cls: ClassSymbol) =
15851575
if param1.hasAnnotation(cls) != param2.hasAnnotation(cls) then
1586-
report.error(
1587-
OverrideError(
1588-
i"has a parameter ${param1.name} with different @${cls.name} status than the corresponding parameter in the overridden definition",
1589-
self, member, other, self.memberInfo(member), self.memberInfo(other)
1590-
),
1591-
if member.owner == clazz then member.srcPos else clazz.srcPos)
1592-
1576+
fail(i"has a parameter ${param1.name} with different @${cls.name} status than the corresponding parameter in the overridden definition")
15931577
checkAnnot(defn.UseAnnot)
15941578
checkAnnot(defn.ConsumeAnnot)
15951579
end OverridingPairsCheckerCC

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ object Existential:
252252
tp1.derivedAnnotatedType(toCap(parent), ann)
253253
case _ => tp
254254

255-
/** Map existentials at the top-level and in all nested result types to `Fresh.Cap`
255+
/** Map existentials at the top-level and in all nested result types to `cap`
256256
*/
257257
def toCapDeeply(tp: Type)(using Context): Type = tp.dealiasKeepAnnots match
258258
case Existential(boundVar, unpacked) =>

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

+3-12
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,11 @@ import util.SimpleIdentitySet.empty
1616
import CaptureSet.{Refs, emptySet, NarrowingCapabilityMap}
1717
import dotty.tools.dotc.util.SimpleIdentitySet
1818

19-
/** A module for handling Fresh types. Fresh.Cap instances are top type that keep
20-
* track of what they hide when capabilities get widened by subsumption to fresh.
21-
* The module implements operations to convert between regular caps.cap and
22-
* Fresh.Cap instances. Fresh.Cap is encoded as `caps.cap @freshCapability(...)` where
23-
* `freshCapability(...)` is a special kind of annotation of type `Fresh.Annot`
24-
* that contains a hidden set.
25-
*/
19+
/** Handling fresh in CC:
20+
21+
*/
2622
object Fresh:
2723

28-
/** The annotation of a Fresh.Cap instance */
2924
case class Annot(hidden: CaptureSet.HiddenSet) extends Annotation:
3025
override def symbol(using Context) = defn.FreshCapabilityAnnot
3126
override def tree(using Context) = New(symbol.typeRef, Nil)
@@ -37,17 +32,13 @@ object Fresh:
3732
case _ => false
3833
end Annot
3934

40-
/** The initial elements (either 0 or 1) of a hidden set created for given `owner`.
41-
* If owner `x` is a trackable this is `x*` if reach` is true, or `x` otherwise.
42-
*/
4335
private def ownerToHidden(owner: Symbol, reach: Boolean)(using Context): Refs =
4436
val ref = owner.termRef
4537
if reach then
4638
if ref.isTrackableRef then SimpleIdentitySet(ref.reach) else emptySet
4739
else
4840
if ref.isTracked then SimpleIdentitySet(ref) else emptySet
4941

50-
/** An extractor for "fresh" capabilities */
5142
object Cap:
5243

5344
def apply(initialHidden: Refs = emptySet)(using Context): CaptureRef =

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
411411
def currentOwner = role.dclSym.orElse(ctx.owner)
412412
for hiddenRef <- prune(refsToCheck, tpe, role) do
413413
val proot = hiddenRef.pathRootOrShared
414-
if !proot.widen.derivesFromSharedCapability then
414+
if !proot.widen.derivesFrom(defn.Caps_SharedCapability) then
415415
proot match
416416
case ref: TermRef =>
417417
val refSym = ref.symbol
@@ -448,7 +448,7 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
448448
role match
449449
case _: TypeRole.Argument | _: TypeRole.Qualifier =>
450450
for ref <- refsToCheck do
451-
if !ref.pathRootOrShared.derivesFromSharedCapability then
451+
if !ref.pathRootOrShared.derivesFrom(defn.Caps_SharedCapability) then
452452
consumed.put(ref, pos)
453453
case _ =>
454454
end checkConsumedRefs

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

+1-9
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,10 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
345345
parent
346346
case _ => tp
347347

348-
/** Check that types extending SharedCapability don't have a `cap` in their capture set.
349-
* TODO This is not enough.
350-
* We need to also track that we cannot get exclusive capabilities in paths
351-
* where some prefix derives from SharedCapability. Also, can we just
352-
* exclude `cap`, or do we have to extend this to all exclusive capabilties?
353-
* The problem is that we know what is exclusive in general only after capture
354-
* checking, not before.
355-
*/
356348
def checkSharedOK(tp: Type): tp.type =
357349
tp match
358350
case CapturingType(parent, refs)
359-
if refs.isUniversal && parent.derivesFromSharedCapability =>
351+
if refs.isUniversal && parent.derivesFrom(defn.Caps_SharedCapability) =>
360352
fail(em"$tp extends SharedCapability, so it cannot capture `cap`")
361353
case _ =>
362354
tp

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

+2
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,8 @@ class Definitions {
11151115
@tu lazy val SilentAnnots: Set[Symbol] =
11161116
Set(InlineParamAnnot, ErasedParamAnnot, RefineOverrideAnnot)
11171117

1118+
@tu lazy val ccParamOnlyAnnotations: Set[Symbol] = Set(UseAnnot, ConsumeAnnot)
1119+
11181120
// A list of annotations that are commonly used to indicate that a field/method argument or return
11191121
// type is not null. These annotations are used by the nullification logic in JavaNullInterop to
11201122
// improve the precision of type nullification.

compiler/src/dotty/tools/dotc/typer/Checking.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ object Checking {
606606
if sym.isWrappedToplevelDef && !sym.isType && sym.flags.is(Infix, butNot = Extension) then
607607
fail(ModifierNotAllowedForDefinition(Flags.Infix, s"A top-level ${sym.showKind} cannot be infix."))
608608
if sym.isUpdateMethod && !sym.owner.derivesFrom(defn.Caps_Mutable) then
609-
fail(em"Update methods can only be used as members of classes extending the `Mutable` trait")
609+
fail(em"Update methods can only be used as members of classes deriving from the `Mutable` trait")
610610
checkApplicable(Erased,
611611
!sym.is(Lazy, butNot = Given)
612612
&& !sym.isMutableVarOrAccessor

0 commit comments

Comments
 (0)