Skip to content

Commit 23f9245

Browse files
committed
Refine class refinements
- Use a uniform criterion when to add them - Don't add them for @constructorOnly or @cc.untrackedCaptures arguments @untrackedCaptures is a new annotation
1 parent 316bdc3 commit 23f9245

File tree

5 files changed

+24
-40
lines changed

5 files changed

+24
-40
lines changed

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

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -467,41 +467,17 @@ extension (sym: Symbol)
467467
&& !sym.allowsRootCapture
468468
&& sym != defn.Caps_unsafeBox
469469
&& sym != defn.Caps_unsafeUnbox
470-
471-
/** Does this symbol define a level where we do not want to let local variables
472-
* escape into outer capture sets?
473-
*/
474-
def isLevelOwner(using Context): Boolean =
475-
sym.isClass
476-
|| sym.is(Method, butNot = Accessor)
477-
478-
/** The owner of the current level. Qualifying owners are
479-
* - methods, other than accessors
480-
* - classes, if they are not staticOwners
481-
* - _root_
482-
*/
483-
def levelOwner(using Context): Symbol =
484-
def recur(sym: Symbol): Symbol =
485-
if !sym.exists || sym.isRoot || sym.isStaticOwner then defn.RootClass
486-
else if sym.isLevelOwner then sym
487-
else recur(sym.owner)
488-
recur(sym)
489-
490-
/** The outermost symbol owned by both `sym` and `other`. if none exists
491-
* since the owning scopes of `sym` and `other` are not nested, invoke
492-
* `onConflict` to return a symbol.
493-
*/
494-
def maxNested(other: Symbol, onConflict: (Symbol, Symbol) => Context ?=> Symbol)(using Context): Symbol =
495-
if !sym.exists || other.isContainedIn(sym) then other
496-
else if !other.exists || sym.isContainedIn(other) then sym
497-
else onConflict(sym, other)
498-
499-
/** The innermost symbol owning both `sym` and `other`.
500-
*/
501-
def minNested(other: Symbol)(using Context): Symbol =
502-
if !other.exists || other.isContainedIn(sym) then sym
503-
else if !sym.exists || sym.isContainedIn(other) then other
504-
else sym.owner.minNested(other.owner)
470+
&& !defn.isPolymorphicAfterErasure(sym)
471+
472+
def isRefiningParamAccessor(using Context): Boolean =
473+
sym.is(ParamAccessor)
474+
&& {
475+
val param = sym.owner.primaryConstructor.paramSymss
476+
.nestedFind(_.name == sym.name)
477+
.getOrElse(NoSymbol)
478+
!param.hasAnnotation(defn.ConstructorOnlyAnnot)
479+
&& !param.hasAnnotation(defn.UntrackedCapturesAnnot)
480+
}
505481

506482
extension (tp: AnnotatedType)
507483
/** Is this a boxed capturing type? */

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,8 +550,8 @@ class CheckCaptures extends Recheck, SymTransformer:
550550
var allCaptures: CaptureSet =
551551
if core.derivesFromCapability then CaptureSet.universal else initCs
552552
for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
553-
val getter = cls.info.member(getterName).suchThat(_.is(ParamAccessor)).symbol
554-
if getter.termRef.isTracked && !getter.is(Private) then
553+
val getter = cls.info.member(getterName).suchThat(_.isRefiningParamAccessor).symbol
554+
if !getter.is(Private) && getter.termRef.isTracked then
555555
refined = RefinedType(refined, getterName, argType)
556556
allCaptures ++= argType.captureSet
557557
(refined, allCaptures)
@@ -764,7 +764,8 @@ class CheckCaptures extends Recheck, SymTransformer:
764764
val thisSet = cls.classInfo.selfType.captureSet.withDescription(i"of the self type of $cls")
765765
checkSubset(localSet, thisSet, tree.srcPos) // (2)
766766
for param <- cls.paramGetters do
767-
if !param.hasAnnotation(defn.ConstructorOnlyAnnot) then
767+
if !param.hasAnnotation(defn.ConstructorOnlyAnnot)
768+
&& !param.hasAnnotation(defn.UntrackedCapturesAnnot) then
768769
checkSubset(param.termRef.captureSet, thisSet, param.srcPos) // (3)
769770
for pureBase <- cls.pureBaseClass do // (4)
770771
def selfType = impl.body

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
6969
case _ => foldOver(x, tp)
7070
def apply(tp: Type): Boolean = apply(false, tp)
7171

72-
if symd.isAllOf(PrivateParamAccessor)
72+
if symd.symbol.isRefiningParamAccessor
73+
&& symd.is(Private)
7374
&& symd.owner.is(CaptureChecked)
74-
&& !symd.hasAnnotation(defn.ConstructorOnlyAnnot)
7575
&& containsCovarRetains(symd.symbol.originDenotation.info)
7676
then symd.flags &~ Private
7777
else symd.flags
@@ -186,6 +186,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
186186
if !defn.isFunctionClass(cls) && cls.is(CaptureChecked) =>
187187
cls.paramGetters.foldLeft(tp) { (core, getter) =>
188188
if atPhase(thisPhase.next)(getter.termRef.isTracked)
189+
&& getter.isRefiningParamAccessor
189190
&& !getter.is(Tracked)
190191
then
191192
val getterType =

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ class Definitions {
10531053
@tu lazy val UncheckedStableAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
10541054
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
10551055
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
1056+
@tu lazy val UntrackedCapturesAnnot: ClassSymbol = requiredClass("scala.caps.untrackedCaptures")
10561057
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
10571058
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
10581059
@tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter")

library/src/scala/caps.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ import annotation.experimental
2828
*/
2929
sealed trait Exists extends Capability
3030

31+
/** This should go into annotations. For now it is here, so that we
32+
* can experiment with it quickly between minor releases
33+
*/
34+
final class untrackedCaptures extends annotation.StaticAnnotation
35+
3136
object unsafe:
3237

3338
extension [T](x: T)

0 commit comments

Comments
 (0)