@@ -102,7 +102,7 @@ object CheckCaptures:
102102 end SubstParamsMap
103103
104104 /** A prototype that indicates selection with an immutable value */
105- class PathSelectionProto (val sym : Symbol , val pt : Type )(using Context ) extends WildcardSelectionProto
105+ class PathSelectionProto (val select : Select , val pt : Type )(using Context ) extends WildcardSelectionProto
106106
107107 /** Check that a @retains annotation only mentions references that can be tracked.
108108 * This check is performed at Typer.
@@ -653,11 +653,15 @@ class CheckCaptures extends Recheck, SymTransformer:
653653 // If ident refers to a parameterless method, charge its cv to the environment
654654 includeCallCaptures(sym, sym.info, tree)
655655 else if ! sym.isStatic then
656- markFree(sym, pathRef(sym.termRef, pt), tree)
656+ if ccConfig.newScheme && sym.exists
657+ then markPathFree(sym.termRef, pt, tree)
658+ else markFree(sym, pathRef(sym.termRef, pt), tree)
657659 mapResultRoots(super .recheckIdent(tree, pt), tree.symbol)
658660
659661 override def recheckThis (tree : This , pt : Type )(using Context ): Type =
660- markFree(pathRef(tree.tpe.asInstanceOf [ThisType ], pt), tree)
662+ if ccConfig.newScheme
663+ then markPathFree(tree.tpe.asInstanceOf [ThisType ], pt, tree)
664+ else markFree(pathRef(tree.tpe.asInstanceOf [ThisType ], pt), tree)
661665 super .recheckThis(tree, pt)
662666
663667 /** Add all selections and also any `.rd modifier implied by the expected
@@ -668,18 +672,38 @@ class CheckCaptures extends Recheck, SymTransformer:
668672 private def pathRef (base : TermRef | ThisType , pt : Type )(using Context ): Capability =
669673 def addSelects (ref : TermRef | ThisType , pt : Type ): Capability = pt match
670674 case pt : PathSelectionProto if ref.isTracked =>
671- if pt.sym .isReadOnlyMethod then
675+ if pt.select.symbol .isReadOnlyMethod then
672676 ref.readOnly
673677 else
674678 // if `ref` is not tracked then the selection could not give anything new
675679 // class SerializationProxy in stdlib-cc/../LazyListIterable.scala has an example where this matters.
676- addSelects(ref.select(pt.sym ).asInstanceOf [TermRef ], pt.pt)
680+ addSelects(ref.select(pt.select.symbol ).asInstanceOf [TermRef ], pt.pt)
677681 case _ => ref
678682 val ref : Capability = addSelects(base, pt)
679683 if ref.derivesFromMutable && pt.isValueType && ! pt.isMutableType
680684 then ref.readOnly
681685 else ref
682686
687+ /** Add all selections and also any `.rd modifier implied by the expected
688+ * type `pt` to `base`. Example:
689+ * If we have `x` and the expected type says we select that with `.a.b`
690+ * where `b` is a read-only method, we charge `x.a.b.rd` instead of `x`.
691+ */
692+ private def markPathFree (ref : TermRef | ThisType , pt : Type , tree : Tree )(using Context ): Unit =
693+ pt match
694+ case pt : PathSelectionProto if ref.isTracked =>
695+ // if `ref` is not tracked then the selection could not give anything new
696+ // class SerializationProxy in stdlib-cc/../LazyListIterable.scala has an example where this matters.
697+ if pt.select.symbol.isReadOnlyMethod then
698+ markFree(ref.readOnly, tree)
699+ else
700+ markPathFree(ref.select(pt.select.symbol).asInstanceOf [TermRef ], pt.pt, pt.select)
701+ case _ =>
702+ if ref.derivesFromMutable && pt.isValueType && ! pt.isMutableType then
703+ markFree(ref.readOnly, tree)
704+ else
705+ markFree(ref, tree)
706+
683707 /** The expected type for the qualifier of a selection. If the selection
684708 * could be part of a capability path or is a a read-only method, we return
685709 * a PathSelectionProto.
@@ -688,7 +712,7 @@ class CheckCaptures extends Recheck, SymTransformer:
688712 val sym = tree.symbol
689713 if ! sym.isOneOf(UnstableValueFlags ) && ! sym.isStatic
690714 || sym.isReadOnlyMethod
691- then PathSelectionProto (sym , pt)
715+ then PathSelectionProto (tree , pt)
692716 else super .selectionProto(tree, pt)
693717
694718 /** A specialized implementation of the selection rule.
@@ -1820,7 +1844,7 @@ class CheckCaptures extends Recheck, SymTransformer:
18201844 private def noWiden (actual : Type , expected : Type )(using Context ): Boolean =
18211845 actual.isSingleton
18221846 && expected.match
1823- case expected : PathSelectionProto => ! expected.sym .isOneOf(UnstableValueFlags )
1847+ case expected : PathSelectionProto => ! expected.select.symbol .isOneOf(UnstableValueFlags )
18241848 case _ => expected.stripCapturing.isSingleton || expected == LhsProto
18251849
18261850 /** Adapt `actual` type to `expected` type. This involves:
0 commit comments