@@ -455,7 +455,10 @@ class CheckCaptures extends Recheck, SymTransformer:
455455 markFree(sym, sym.termRef, tree)
456456
457457 def markFree (sym : Symbol , ref : Capability , tree : Tree )(using Context ): Unit =
458- if sym.exists && ref.isTracked then markFree(ref.singletonCaptureSet, tree)
458+ if sym.exists then markFree(ref, tree)
459+
460+ def markFree (ref : Capability , tree : Tree )(using Context ): Unit =
461+ if ref.isTracked then markFree(ref.singletonCaptureSet, tree)
459462
460463 /** Make sure the (projected) `cs` is a subset of the capture sets of all enclosing
461464 * environments. At each stage, only include references from `cs` that are outside
@@ -628,25 +631,33 @@ class CheckCaptures extends Recheck, SymTransformer:
628631 // If ident refers to a parameterless method, charge its cv to the environment
629632 includeCallCaptures(sym, sym.info, tree)
630633 else if ! sym.isStatic then
631- // Otherwise charge its symbol, but add all selections and also any `.rd`
632- // modifier implied by the expected type `pt`.
633- // Example: If we have `x` and the expected type says we select that with `.a.b`
634- // where `b` is a read-only method, we charge `x.a.b.rd` instead of `x`.
635- def addSelects (ref : TermRef , pt : Type ): Capability = pt match
636- case pt : PathSelectionProto if ref.isTracked =>
637- if pt.sym.isReadOnlyMethod then
638- ref.readOnly
639- else
640- // if `ref` is not tracked then the selection could not give anything new
641- // class SerializationProxy in stdlib-cc/../LazyListIterable.scala has an example where this matters.
642- addSelects(ref.select(pt.sym).asInstanceOf [TermRef ], pt.pt)
643- case _ => ref
644- var pathRef : Capability = addSelects(sym.termRef, pt)
645- if pathRef.derivesFromMutable && pt.isValueType && ! pt.isMutableType then
646- pathRef = pathRef.readOnly
647- markFree(sym, pathRef, tree)
634+ markFree(sym, pathRef(sym.termRef, pt), tree)
648635 mapResultRoots(super .recheckIdent(tree, pt), tree.symbol)
649636
637+ override def recheckThis (tree : This , pt : Type )(using Context ): Type =
638+ markFree(pathRef(tree.tpe.asInstanceOf [ThisType ], pt), tree)
639+ super .recheckThis(tree, pt)
640+
641+ /** Add all selections and also any `.rd modifier implied by the expected
642+ * type `pt` to `base`. Example:
643+ * If we have `x` and the expected type says we select that with `.a.b`
644+ * where `b` is a read-only method, we charge `x.a.b.rd` instead of `x`.
645+ */
646+ private def pathRef (base : TermRef | ThisType , pt : Type )(using Context ): Capability =
647+ def addSelects (ref : TermRef | ThisType , pt : Type ): Capability = pt match
648+ case pt : PathSelectionProto if ref.isTracked =>
649+ if pt.sym.isReadOnlyMethod then
650+ ref.readOnly
651+ else
652+ // if `ref` is not tracked then the selection could not give anything new
653+ // class SerializationProxy in stdlib-cc/../LazyListIterable.scala has an example where this matters.
654+ addSelects(ref.select(pt.sym).asInstanceOf [TermRef ], pt.pt)
655+ case _ => ref
656+ val ref : Capability = addSelects(base, pt)
657+ if ref.derivesFromMutable && pt.isValueType && ! pt.isMutableType
658+ then ref.readOnly
659+ else ref
660+
650661 /** The expected type for the qualifier of a selection. If the selection
651662 * could be part of a capability path or is a a read-only method, we return
652663 * a PathSelectionProto.
0 commit comments