diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala index 7692cf191bf9..349711ef21b0 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -232,7 +232,9 @@ extension (tp: Type) case tp @ ReachCapability(_) => tp.singletonCaptureSet case ReadOnlyCapability(ref) => - ref.deepCaptureSet(includeTypevars).readOnly + val refDcs = ref.deepCaptureSet(includeTypevars) + if refDcs.isConst then CaptureSet(refDcs.elems.map(_.readOnly)) + else refDcs // this case should not happen for correct programs case tp: SingletonCaptureRef if tp.isTrackableRef => tp.reach.singletonCaptureSet case _ => @@ -283,10 +285,20 @@ extension (tp: Type) * are of the form this.C but their pathroot is still this.C, not this. */ final def pathRoot(using Context): Type = tp.dealias match - case tp1: NamedType if tp1.symbol.maybeOwner.isClass && !tp1.symbol.is(TypeParam) => - tp1.prefix.pathRoot + case tp1: TermRef if tp1.symbol.maybeOwner.isClass => tp1.prefix.pathRoot + case tp1: TypeRef if !tp1.symbol.is(Param) => tp1.prefix.pathRoot case tp1 => tp1 + /** The first element of a path type, but stop at references extending + * SharedCapability. + */ + final def pathRootOrShared(using Context): Type = + if tp.derivesFromSharedCapability then tp + else tp.dealias match + case tp1: TermRef if tp1.symbol.maybeOwner.isClass => tp1.prefix.pathRoot + case tp1: TypeRef if !tp1.symbol.is(Param) => tp1.prefix.pathRoot + case tp1 => tp1 + /** If this part starts with `C.this`, the class `C`. * Otherwise, if it starts with a reference `r`, `r`'s owner. * Otherwise NoSymbol. diff --git a/compiler/src/dotty/tools/dotc/cc/SepCheck.scala b/compiler/src/dotty/tools/dotc/cc/SepCheck.scala index ad6205617b1d..b2318eb798dd 100644 --- a/compiler/src/dotty/tools/dotc/cc/SepCheck.scala +++ b/compiler/src/dotty/tools/dotc/cc/SepCheck.scala @@ -537,8 +537,9 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser: val badParams = mutable.ListBuffer[Symbol]() def currentOwner = role.dclSym.orElse(ctx.owner) for hiddenRef <- prune(refsToCheck, tpe, role) do - if !hiddenRef.derivesFromSharedCapability then - hiddenRef.pathRoot match + val proot = hiddenRef.pathRootOrShared + if !proot.widen.derivesFromSharedCapability then + proot match case ref: TermRef => val refSym = ref.symbol if currentOwner.enclosingMethodOrClass.isProperlyContainedIn(refSym.maybeOwner.enclosingMethodOrClass) then @@ -574,7 +575,7 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser: role match case _: TypeRole.Argument | _: TypeRole.Qualifier => for ref <- refsToCheck do - if !ref.derivesFromSharedCapability then + if !ref.pathRootOrShared.derivesFromSharedCapability then consumed.put(ref, pos) case _ => end checkConsumedRefs