@@ -332,29 +332,31 @@ class CheckCaptures extends Recheck, SymTransformer:
332
332
* and Cr otherwise.
333
333
*/
334
334
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
358
360
end recheckApply
359
361
360
362
/** Handle an application of method `sym` with type `mt` to arguments of types `argTypes`.
@@ -460,10 +462,25 @@ class CheckCaptures extends Recheck, SymTransformer:
460
462
case _ =>
461
463
super .recheckBlock(block, pt)
462
464
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
+
463
479
override def recheckValDef (tree : ValDef , sym : Symbol )(using Context ): Unit =
464
480
try
465
481
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)
467
484
finally
468
485
if ! sym.is(Param ) then
469
486
// Parameters with inferred types belong to anonymous methods. We need to wait
@@ -765,7 +782,6 @@ class CheckCaptures extends Recheck, SymTransformer:
765
782
recon(CapturingType (parent1, cs1, actualIsBoxed))
766
783
}
767
784
768
-
769
785
var actualw = actual.widenDealias
770
786
actual match
771
787
case ref : CaptureRef if ref.isTracked =>
0 commit comments