@@ -332,29 +332,31 @@ class CheckCaptures extends Recheck, SymTransformer:
332332 * and Cr otherwise.
333333 */
334334 override def recheckApply (tree : Apply , pt : Type )(using Context ): Type =
335- includeCallCaptures(tree.symbol, tree.srcPos)
336- tree match
337- case Apply (fn, arg :: Nil ) if fn.symbol == defn.Caps_unsafeUnbox =>
338- val argType0 = recheckStart(arg, pt).unbox
339- val argType = super .recheckFinish(argType0, arg, pt)
340- super .recheckFinish(argType, tree, pt)
341- case _ =>
342- super .recheckApply(tree, pt) match
343- case appType @ CapturingType (appType1, refs) =>
344- tree.fun match
345- case Select (qual, _)
346- if ! tree.fun.symbol.isConstructor
347- && ! qual.tpe.isBoxedCapturing
348- && ! tree.args.exists(_.tpe.isBoxedCapturing)
349- && qual.tpe.captureSet.mightSubcapture(refs)
350- && tree.args.forall(_.tpe.captureSet.mightSubcapture(refs))
351- =>
352- val callCaptures = tree.args.foldLeft(qual.tpe.captureSet)((cs, arg) =>
353- cs ++ arg.tpe.captureSet)
354- appType.derivedCapturingType(appType1, callCaptures)
355- .showing(i " narrow $tree: $appType, refs = $refs, qual = ${qual.tpe.captureSet} --> $result" , capt)
356- case _ => appType
357- case appType => appType
335+ val meth = tree.fun.symbol
336+ includeCallCaptures(meth, tree.srcPos)
337+ if meth == defn.Caps_unsafeBox || meth == defn.Caps_unsafeUnbox then
338+ val arg :: Nil = tree.args: @ unchecked
339+ val argType0 = recheckStart(arg, pt)
340+ .forceBoxStatus(boxed = meth == defn.Caps_unsafeBox )
341+ val argType = super .recheckFinish(argType0, arg, pt)
342+ super .recheckFinish(argType, tree, pt)
343+ else
344+ super .recheckApply(tree, pt) match
345+ case appType @ CapturingType (appType1, refs) =>
346+ tree.fun match
347+ case Select (qual, _)
348+ if ! tree.fun.symbol.isConstructor
349+ && ! qual.tpe.isBoxedCapturing
350+ && ! tree.args.exists(_.tpe.isBoxedCapturing)
351+ && qual.tpe.captureSet.mightSubcapture(refs)
352+ && tree.args.forall(_.tpe.captureSet.mightSubcapture(refs))
353+ =>
354+ val callCaptures = tree.args.foldLeft(qual.tpe.captureSet)((cs, arg) =>
355+ cs ++ arg.tpe.captureSet)
356+ appType.derivedCapturingType(appType1, callCaptures)
357+ .showing(i " narrow $tree: $appType, refs = $refs, qual = ${qual.tpe.captureSet} --> $result" , capt)
358+ case _ => appType
359+ case appType => appType
358360 end recheckApply
359361
360362 /** Handle an application of method `sym` with type `mt` to arguments of types `argTypes`.
@@ -460,10 +462,25 @@ class CheckCaptures extends Recheck, SymTransformer:
460462 case _ =>
461463 super .recheckBlock(block, pt)
462464
465+ /** If `rhsProto` has `*` as its capture set, wrap `rhs` in a `unsafeBox`.
466+ * Used to infer `unsafeBox` for expressions that get assigned to variables
467+ * that have universal capture set.
468+ */
469+ def maybeBox (rhs : Tree , rhsProto : Type )(using Context ): Tree =
470+ if rhsProto.captureSet.isUniversal then
471+ ref(defn.Caps_unsafeBox ).appliedToType(rhsProto).appliedTo(rhs)
472+ else rhs
473+
474+ override def recheckAssign (tree : Assign )(using Context ): Type =
475+ val rhsProto = recheck(tree.lhs).widen
476+ recheck(maybeBox(tree.rhs, rhsProto), rhsProto)
477+ defn.UnitType
478+
463479 override def recheckValDef (tree : ValDef , sym : Symbol )(using Context ): Unit =
464480 try
465481 if ! sym.is(Module ) then // Modules are checked by checking the module class
466- super .recheckValDef(tree, sym)
482+ if sym.is(Mutable ) then recheck(maybeBox(tree.rhs, sym.info), sym.info)
483+ else super .recheckValDef(tree, sym)
467484 finally
468485 if ! sym.is(Param ) then
469486 // Parameters with inferred types belong to anonymous methods. We need to wait
@@ -765,7 +782,6 @@ class CheckCaptures extends Recheck, SymTransformer:
765782 recon(CapturingType (parent1, cs1, actualIsBoxed))
766783 }
767784
768-
769785 var actualw = actual.widenDealias
770786 actual match
771787 case ref : CaptureRef if ref.isTracked =>
0 commit comments