@@ -656,7 +656,7 @@ class CheckCaptures extends Recheck, SymTransformer:
656656 expected
657657
658658 /** Adapt `actual` type to `expected` type by inserting boxing and unboxing conversions
659- *
659+ *
660660 * @param alwaysConst always make capture set variables constant after adaptation
661661 */
662662 def adaptBoxed (actual : Type , expected : Type , pos : SrcPos , alwaysConst : Boolean = false )(using Context ): Type =
@@ -721,61 +721,52 @@ class CheckCaptures extends Recheck, SymTransformer:
721721 val arrow = if covariant then " ~~>" else " <~~"
722722 i " adapting $actual $arrow $expected"
723723
724- /** Destruct a capturing type `tp` to a tuple (cs, tp0, boxed),
725- * where `tp0` is not a capturing type.
726- *
727- * If `tp` is a nested capturing type, the return tuple always represents
728- * the innermost capturing type. The outer capture annotations can be
729- * reconstructed with the returned function.
730- */
731- def destructCapturingType (tp : Type , reconstruct : Type => Type = x => x): ((Type , CaptureSet , Boolean ), Type => Type ) =
732- tp.dealias match
733- case tp @ CapturingType (parent, cs) =>
734- if parent.dealias.isCapturingType then
735- destructCapturingType(parent, res => reconstruct(tp.derivedCapturingType(res, cs)))
736- else
737- ((parent, cs, tp.isBoxed), reconstruct)
738- case actual =>
739- val res = if tp.isFromJavaObject then tp else actual
740- ((res, CaptureSet (), false ), reconstruct)
741-
742724 def adapt (actual : Type , expected : Type , covariant : Boolean ): Type = trace(adaptInfo(actual, expected, covariant), recheckr, show = true ) {
743725 if expected.isInstanceOf [WildcardType ] then actual
744726 else
745- val ((parent, cs, actualIsBoxed), recon) = destructCapturingType(actual)
746-
747- val needsAdaptation = actualIsBoxed != expected.isBoxedCapturing
748- val insertBox = needsAdaptation && covariant != actualIsBoxed
749-
750- val (parent1, cs1) = parent match {
727+ // Decompose the actual type into the inner shape type, the capture set and the box status
728+ val styp = if actual.isFromJavaObject then actual else actual.stripCapturing
729+ val cs = actual.captureSet
730+ val boxed = actual.isBoxedCapturing
731+
732+ // A box/unbox should be inserted, if the actual box status mismatches with the expectation
733+ val needsAdaptation = boxed != expected.isBoxedCapturing
734+ // Whether to insert a box or an unbox?
735+ val insertBox = needsAdaptation && covariant != boxed
736+
737+ // Adapt the inner shape type: get the adapted shape type, and the capture set leaked during adaptation
738+ val (styp1, leaked) = styp match {
751739 case actual @ AppliedType (tycon, args) if defn.isNonRefinedFunction(actual) =>
752- val (parent1, leaked) = adaptFun(parent , args.init, args.last, expected, covariant, insertBox,
740+ adaptFun(actual , args.init, args.last, expected, covariant, insertBox,
753741 (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
754- (parent1, leaked ++ cs)
755742 case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
756743 // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere)
757- val (parent1, leaked) = adaptFun(parent , rinfo.paramInfos, rinfo.resType, expected, covariant, insertBox,
744+ adaptFun(actual , rinfo.paramInfos, rinfo.resType, expected, covariant, insertBox,
758745 (aargs1, ares1) =>
759746 rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
760747 .toFunctionType(isJava = false , alwaysDependent = true ))
761- (parent1, leaked ++ cs)
762748 case actual : MethodType =>
763- val (parent1, leaked) = adaptFun(parent , actual.paramInfos, actual.resType, expected, covariant, insertBox,
749+ adaptFun(actual , actual.paramInfos, actual.resType, expected, covariant, insertBox,
764750 (aargs1, ares1) =>
765751 actual.derivedLambdaType(paramInfos = aargs1, resType = ares1))
766- (parent1, leaked ++ cs)
767752 case actual @ RefinedType (p, nme, rinfo : PolyType ) if defn.isFunctionOrPolyType(actual) =>
768- val (parent1, leaked) = adaptTypeFun(parent , rinfo.resType, expected, covariant, insertBox,
753+ adaptTypeFun(actual , rinfo.resType, expected, covariant, insertBox,
769754 ares1 =>
770755 val rinfo1 = rinfo.derivedLambdaType(rinfo.paramNames, rinfo.paramInfos, ares1)
771756 val actual1 = actual.derivedRefinedType(p, nme, rinfo1)
772757 actual1
773758 )
774- (parent1, leaked ++ cs)
775759 case _ =>
776- (parent, cs )
760+ (styp, CaptureSet () )
777761 }
778762
763+ // Capture set of the term after adaptation
764+ val cs1 = cs ++ leaked
765+
766+ // Compute the adapted type
767+ def adaptedType (resultBoxed : Boolean ) =
768+ styp1.capturing(if alwaysConst then CaptureSet (cs1.elems) else cs1).forceBoxStatus(resultBoxed)
769+
779770 if needsAdaptation then
780771 val criticalSet = // the set which is not allowed to have `*`
781772 if covariant then cs1 // can't box with `*`
@@ -797,9 +788,9 @@ class CheckCaptures extends Recheck, SymTransformer:
797788 }
798789 if ! insertBox then // unboxing
799790 markFree(criticalSet, pos)
800- recon( CapturingType (parent1, if alwaysConst then CaptureSet (cs1.elems) else cs1, ! actualIsBoxed) )
791+ adaptedType( ! boxed )
801792 else
802- recon( CapturingType (parent1, if alwaysConst then CaptureSet (cs1.elems) else cs1, actualIsBoxed) )
793+ adaptedType(boxed )
803794 }
804795
805796 var actualw = actual.widenDealias
0 commit comments