@@ -394,11 +394,18 @@ extension (tp: Type)
394394 case _ =>
395395 false
396396
397- def derivesFromCapability (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Capability )
398- def derivesFromStateful (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Stateful )
399- def derivesFromShared (using Context ): Boolean = derivesFromCapTrait(defn.Caps_SharedCapability )
400- def derivesFromUnscoped (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Unscoped )
401- def derivesFromMutable (using Context ): Boolean = derivesFromCapTrait(defn.Caps_Mutable )
397+ def derivesFromCapability (using Context ): Boolean =
398+ derivesFromCapTrait(defn.Caps_Capability ) || isArrayUnderStrictMut
399+ def derivesFromStateful (using Context ): Boolean =
400+ derivesFromCapTrait(defn.Caps_Stateful ) || isArrayUnderStrictMut
401+ def derivesFromShared (using Context ): Boolean =
402+ derivesFromCapTrait(defn.Caps_SharedCapability )
403+ def derivesFromUnscoped (using Context ): Boolean =
404+ derivesFromCapTrait(defn.Caps_Unscoped ) || isArrayUnderStrictMut
405+ def derivesFromMutable (using Context ): Boolean =
406+ derivesFromCapTrait(defn.Caps_Mutable ) || isArrayUnderStrictMut
407+
408+ def isArrayUnderStrictMut (using Context ): Boolean = tp.classSymbol.isArrayUnderStrictMut
402409
403410 /** Drop @retains annotations everywhere */
404411 def dropAllRetains (using Context ): Type = // TODO we should drop retains from inferred types before unpickling
@@ -488,7 +495,8 @@ extension (tp: Type)
488495 tp
489496
490497 def inheritedClassifier (using Context ): ClassSymbol =
491- tp.classSymbols.map(_.classifier).foldLeft(defn.AnyClass )(leastClassifier)
498+ if tp.isArrayUnderStrictMut then defn.Caps_Unscoped
499+ else tp.classSymbols.map(_.classifier).foldLeft(defn.AnyClass )(leastClassifier)
492500
493501extension (tp : MethodType )
494502 /** A method marks an existential scope unless it is the prefix of a curried method */
@@ -553,10 +561,13 @@ extension (sym: Symbol)
553561 * - or it is a value class
554562 * - or it is an exception
555563 * - or it is one of Nothing, Null, or String
564+ * Arrays are not pure under strict mutability even though their self type is declared pure
565+ * in Arrays.scala.
556566 */
557567 def isPureClass (using Context ): Boolean = sym match
558568 case cls : ClassSymbol =>
559- cls.pureBaseClass.isDefined || defn.pureSimpleClasses.contains(cls)
569+ (cls.pureBaseClass.isDefined || defn.pureSimpleClasses.contains(cls))
570+ && ! cls.isArrayUnderStrictMut
560571 case _ =>
561572 false
562573
@@ -588,8 +599,8 @@ extension (sym: Symbol)
588599 && ! defn.isPolymorphicAfterErasure(sym)
589600 && ! defn.isTypeTestOrCast(sym)
590601
591- /** It's a parameter accessor that is not annotated @constructorOnly or @uncheckedCaptures
592- * and that is not a consume accessor .
602+ /** It's a parameter accessor for a parameter that that is not annotated
603+ * @constructorOnly or @uncheckedCaptures and that is not a consume parameter .
593604 */
594605 def isRefiningParamAccessor (using Context ): Boolean =
595606 sym.is(ParamAccessor )
@@ -600,6 +611,17 @@ extension (sym: Symbol)
600611 && ! param.hasAnnotation(defn.ConsumeAnnot )
601612 }
602613
614+ /** It's a parameter accessor that is tracked for capture checking. Excluded are
615+ * accessors for parameters annotated with constructorOnly or @uncheckedCaptures.
616+ */
617+ def isTrackedParamAccessor (using Context ): Boolean =
618+ sym.is(ParamAccessor )
619+ && {
620+ val param = sym.owner.primaryConstructor.paramNamed(sym.name)
621+ ! param.hasAnnotation(defn.ConstructorOnlyAnnot )
622+ && ! param.hasAnnotation(defn.UntrackedCapturesAnnot )
623+ }
624+
603625 def hasTrackedParts (using Context ): Boolean =
604626 ! CaptureSet .ofTypeDeeply(sym.info).isAlwaysEmpty
605627
@@ -642,6 +664,9 @@ extension (sym: Symbol)
642664 else if sym.name.is(TryOwnerName ) then i " an enclosing try expression "
643665 else sym.show
644666
667+ def isArrayUnderStrictMut (using Context ): Boolean =
668+ sym == defn.ArrayClass && ccConfig.strictMutability
669+
645670extension (tp : AnnotatedType )
646671 /** Is this a boxed capturing type? */
647672 def isBoxed (using Context ): Boolean = tp.annot match
0 commit comments