@@ -656,7 +656,7 @@ class CheckCaptures extends Recheck, SymTransformer:
656
656
expected
657
657
658
658
/** Adapt `actual` type to `expected` type by inserting boxing and unboxing conversions
659
- *
659
+ *
660
660
* @param alwaysConst always make capture set variables constant after adaptation
661
661
*/
662
662
def adaptBoxed (actual : Type , expected : Type , pos : SrcPos , alwaysConst : Boolean = false )(using Context ): Type =
@@ -721,61 +721,52 @@ class CheckCaptures extends Recheck, SymTransformer:
721
721
val arrow = if covariant then " ~~>" else " <~~"
722
722
i " adapting $actual $arrow $expected"
723
723
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
-
742
724
def adapt (actual : Type , expected : Type , covariant : Boolean ): Type = trace(adaptInfo(actual, expected, covariant), recheckr, show = true ) {
743
725
if expected.isInstanceOf [WildcardType ] then actual
744
726
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 {
751
739
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,
753
741
(aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
754
- (parent1, leaked ++ cs)
755
742
case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
756
743
// 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,
758
745
(aargs1, ares1) =>
759
746
rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
760
747
.toFunctionType(isJava = false , alwaysDependent = true ))
761
- (parent1, leaked ++ cs)
762
748
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,
764
750
(aargs1, ares1) =>
765
751
actual.derivedLambdaType(paramInfos = aargs1, resType = ares1))
766
- (parent1, leaked ++ cs)
767
752
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,
769
754
ares1 =>
770
755
val rinfo1 = rinfo.derivedLambdaType(rinfo.paramNames, rinfo.paramInfos, ares1)
771
756
val actual1 = actual.derivedRefinedType(p, nme, rinfo1)
772
757
actual1
773
758
)
774
- (parent1, leaked ++ cs)
775
759
case _ =>
776
- (parent, cs )
760
+ (styp, CaptureSet () )
777
761
}
778
762
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
+
779
770
if needsAdaptation then
780
771
val criticalSet = // the set which is not allowed to have `*`
781
772
if covariant then cs1 // can't box with `*`
@@ -797,9 +788,9 @@ class CheckCaptures extends Recheck, SymTransformer:
797
788
}
798
789
if ! insertBox then // unboxing
799
790
markFree(criticalSet, pos)
800
- recon( CapturingType (parent1, if alwaysConst then CaptureSet (cs1.elems) else cs1, ! actualIsBoxed) )
791
+ adaptedType( ! boxed )
801
792
else
802
- recon( CapturingType (parent1, if alwaysConst then CaptureSet (cs1.elems) else cs1, actualIsBoxed) )
793
+ adaptedType(boxed )
803
794
}
804
795
805
796
var actualw = actual.widenDealias
0 commit comments