@@ -106,14 +106,14 @@ object CheckCaptures:
106106 /** Check that a @retains annotation only mentions references that can be tracked.
107107 * This check is performed at Typer.
108108 */
109- def checkWellformed (parent : Tree , ann : Tree )(using Context ): Unit =
109+ def checkWellformedRetains (parent : Tree , ann : Tree )(using Context ): Unit =
110110 def check (elem : Type ): Unit = elem match
111111 case ref : TypeRef =>
112112 val refSym = ref.symbol
113113 if refSym.isType && ! refSym.info.derivesFrom(defn.Caps_CapSet ) then
114114 report.error(em " $elem is not a legal element of a capture set " , ann.srcPos)
115115 case ref : CoreCapability =>
116- if ! ref.isTrackableRef && ! ref.isCapRef then
116+ if ! ref.isTrackableRef && ! ref.isCapRef && ! ref.isLocalMutable then
117117 report.error(em " $elem cannot be tracked since it is not a parameter or local value " , ann.srcPos)
118118 case ReachCapability (ref) =>
119119 check(ref)
@@ -306,7 +306,7 @@ class CheckCaptures extends Recheck, SymTransformer:
306306 */
307307 private val useInfos = mutable.ArrayBuffer [(Tree , CaptureSet , Env )]()
308308
309- private var usedSet = util.EqHashMap [Tree , CaptureSet ]()
309+ private val usedSet = util.EqHashMap [Tree , CaptureSet ]()
310310
311311 /** The set of symbols that were rechecked via a completer */
312312 private val completed = new mutable.HashSet [Symbol ]
@@ -690,8 +690,15 @@ class CheckCaptures extends Recheck, SymTransformer:
690690 // Lazy vals are like parameterless methods: accessing them may trigger initialization
691691 // that uses captured references.
692692 includeCallCaptures(sym, sym.info, tree)
693- else if sym.exists && ! sym.isStatic then
694- markPathFree(sym.termRef, pt, tree)
693+ else
694+ if sym.isMutableVar && sym.owner.isTerm && pt != LhsProto then
695+ // When we have `var x: A^{c} = ...` where `x` is a local variable then
696+ // when dereferencing `x` we also need to charge `c`.
697+ // For fields it's not a problem since `c` would already have been
698+ // charged for the prefix `p` in `p.x`.
699+ markFree(sym.info.captureSet, tree)
700+ if sym.exists && ! sym.isStatic then
701+ markPathFree(sym.termRef, pt, tree)
695702 mapResultRoots(super .recheckIdent(tree, pt), tree.symbol)
696703
697704 override def recheckThis (tree : This , pt : Type )(using Context ): Type =
@@ -713,7 +720,7 @@ class CheckCaptures extends Recheck, SymTransformer:
713720 val sel = ref.select(pt.selector).asInstanceOf [TermRef ]
714721 markPathFree(sel, pt.pt, pt.select)
715722 case _ =>
716- markFree(ref.adjustReadOnly(pt), tree)
723+ markFree(ref.mapLocalMutable. adjustReadOnly(pt), tree)
717724
718725 /** The expected type for the qualifier of a selection. If the selection
719726 * could be part of a capability path or is a a read-only method, we return
@@ -1062,7 +1069,7 @@ class CheckCaptures extends Recheck, SymTransformer:
10621069 recheck(tree.rhs, lhsType.widen)
10631070 lhsType match
10641071 case lhsType @ TermRef (qualType, _)
1065- if (qualType ne NoPrefix ) && ! lhsType.symbol.hasAnnotation(defn.UntrackedCapturesAnnot ) =>
1072+ if ! lhsType.symbol.hasAnnotation(defn.UntrackedCapturesAnnot ) =>
10661073 checkUpdate(qualType, tree.srcPos)(i " Cannot assign to field ${lhsType.name} of ${qualType.showRef}" )
10671074 case _ =>
10681075 defn.UnitType
@@ -1135,6 +1142,13 @@ class CheckCaptures extends Recheck, SymTransformer:
11351142 openClosures = openClosures.tail
11361143 end recheckClosureBlock
11371144
1145+ /** Add var mirrors to the list of block-local symbols to avoid */
1146+ override def avoidLocals (tp : Type , symsToAvoid : => List [Symbol ])(using Context ): Type =
1147+ val locals = symsToAvoid
1148+ val varMirrors = locals.collect:
1149+ case local if local.termRef.isLocalMutable => local.varMirror
1150+ super .avoidLocals(tp, varMirrors ++ locals)
1151+
11381152 /** Elements of a SeqLiteral instantiate a Seq or Array parameter, so they
11391153 * should be boxed.
11401154 */
0 commit comments