@@ -596,51 +596,84 @@ class CheckCaptures extends Recheck, SymTransformer:
596
596
* @param reconstruct how to rebuild the adapted function type
597
597
*/
598
598
def adaptFun (actual : Type , aargs : List [Type ], ares : Type , expected : Type ,
599
- covariant : Boolean ,
600
- reconstruct : (List [Type ], Type ) => Type ): Type =
601
- val (eargs, eres) = expected.dealias match
602
- case defn.FunctionOf (eargs, eres, _, _) => (eargs, eres)
603
- case _ => (aargs.map(_ => WildcardType ), WildcardType )
604
- val aargs1 = aargs.zipWithConserve(eargs)(adapt(_, _, ! covariant))
605
- val ares1 = adapt(ares, eres, covariant)
606
- if (ares1 eq ares) && (aargs1 eq aargs) then actual
607
- else reconstruct(aargs1, ares1)
608
-
609
- def adapt (actual : Type , expected : Type , covariant : Boolean ): Type = actual.dealias match
610
- case actual @ CapturingType (parent, refs) =>
611
- val parent1 = adapt(parent, expected, covariant)
612
- if actual.isBoxed != expected.isBoxedCapturing then
613
- val criticalSet = // the set which is not allowed to have `*`
614
- if covariant then refs // can't box with `*`
615
- else expected.captureSet // can't unbox with `*`
616
- if criticalSet.isUniversal then
617
- // We can't box/unbox the universal capability. Leave `actual` as it is
618
- // so we get an error in checkConforms. This tends to give better error
619
- // messages than disallowing the root capability in `criticalSet`.
620
- capt.println(i " cannot box/unbox $actual vs $expected" )
621
- actual
599
+ covariant : Boolean , boxed : Boolean ,
600
+ reconstruct : (List [Type ], Type ) => Type ): (Type , Some [CaptureSet ]) =
601
+ val saved = curEnv
602
+ curEnv = Env (curEnv.owner, CaptureSet .Var (), isBoxed = false , if boxed then null else curEnv)
603
+
604
+ try
605
+ val (eargs, eres) = expected.dealias match
606
+ case defn.FunctionOf (eargs, eres, _, _) => (eargs, eres)
607
+ case _ => (aargs.map(_ => WildcardType ), WildcardType )
608
+ val aargs1 = aargs.zipWithConserve(eargs){ (aarg, earg) => adapt(aarg, earg, ! covariant, boxed = false ) }
609
+ val ares1 = adapt(ares, eres, covariant, boxed = false )
610
+
611
+ val resTp =
612
+ if (ares1 eq ares) && (aargs1 eq aargs) then actual
613
+ else reconstruct(aargs1, ares1)
614
+
615
+ curEnv.captured.asVar.markSolved()
616
+ (resTp, Some (curEnv.captured))
617
+ finally
618
+ curEnv = saved
619
+
620
+ // def adaptInfo(actual: Type, expected: Type, covariant: Boolean): String =
621
+ // val (l, r) = if covariant then (actual, expected) else (expected, actual)
622
+ // i"adapting $l ~~> $r"
623
+
624
+ def adapt (actual : Type , expected : Type , covariant : Boolean , boxed : Boolean ): Type =
625
+ val (actual1, cs1) = adapt1(actual, expected, covariant, boxed)
626
+ cs1 map { cs1 =>
627
+ actual1 match
628
+ case CapturingType (parent, cs0) =>
629
+ parent.derivedCapturingType(parent, cs0 ++ cs1.asConst)
630
+ case _ =>
631
+ CapturingType (actual1, cs1.asConst)
632
+ } getOrElse actual1
633
+
634
+ def adapt1 (actual : Type , expected : Type , covariant : Boolean , boxed : Boolean ): (Type , Option [CaptureSet ]) =
635
+ actual.dealias match
636
+ case actual @ CapturingType (parent, refs) =>
637
+ if actual.isBoxed != expected.isBoxedCapturing then
638
+ val isUnbox = covariant == actual.isBoxed
639
+ val (parent1, cs1) = adapt1(parent, expected, covariant, boxed = ! isUnbox)
640
+
641
+ val criticalSet = // the set which is not allowed to have `*`
642
+ if covariant then refs // can't box with `*`
643
+ else expected.captureSet // can't unbox with `*`
644
+ if criticalSet.isUniversal then
645
+ // We can't box/unbox the universal capability. Leave `actual` as it is
646
+ // so we get an error in checkConforms. This tends to give better error
647
+ // messages than disallowing the root capability in `criticalSet`.
648
+ capt.println(i " cannot box/unbox $actual vs $expected" )
649
+ (actual, None )
650
+ else
651
+ // Disallow future addition of `*` to `criticalSet`.
652
+ criticalSet.disallowRootCapability { () =>
653
+ report.error(
654
+ em """ $actual cannot be box-converted to $expected
655
+ |since one of their capture sets contains the root capability `*` """ ,
656
+ pos)
657
+ }
658
+ if isUnbox then markFree(refs, pos)
659
+ val tp1 = CapturingType (parent1, cs1 map { refs ++ _ } getOrElse refs, boxed = ! actual.isBoxed)
660
+ (tp1, None )
622
661
else
623
- // Disallow future addition of `*` to `criticalSet`.
624
- criticalSet.disallowRootCapability { () =>
625
- report.error(
626
- em """ $actual cannot be box-converted to $expected
627
- |since one of their capture sets contains the root capability `*` """ ,
628
- pos)
629
- }
630
- if covariant == actual.isBoxed then markFree(refs, pos)
631
- CapturingType (parent1, refs, boxed = ! actual.isBoxed)
632
- else
633
- actual.derivedCapturingType(parent1, refs)
634
- case actual @ AppliedType (tycon, args) if defn.isNonRefinedFunction(actual) =>
635
- adaptFun(actual, args.init, args.last, expected, covariant,
636
- (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
637
- case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
638
- // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere)
639
- adaptFun(actual, rinfo.paramInfos, rinfo.resType, expected, covariant,
640
- (aargs1, ares1) =>
641
- rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
642
- .toFunctionType(isJava = false , alwaysDependent = true ))
643
- case _ => actual
662
+ val (parent1, cs1) = adapt1(parent, expected, covariant, boxed = false )
663
+ val refs1 = cs1.map(refs ++ _.asConst).getOrElse(refs)
664
+ val tp1 = actual.derivedCapturingType(parent1, refs1)
665
+ (tp1, None )
666
+ case actual @ AppliedType (tycon, args) if defn.isNonRefinedFunction(actual) =>
667
+ adaptFun(actual, args.init, args.last, expected, covariant, boxed,
668
+ (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
669
+ case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
670
+ // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere)
671
+ adaptFun(actual, rinfo.paramInfos, rinfo.resType, expected, covariant, boxed,
672
+ (aargs1, ares1) =>
673
+ rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
674
+ .toFunctionType(isJava = false , alwaysDependent = true ))
675
+ case _ => (actual, None )
676
+
644
677
645
678
var actualw = actual.widenDealias
646
679
actual match
@@ -651,7 +684,7 @@ class CheckCaptures extends Recheck, SymTransformer:
651
684
// given `a: C T`, improve `C T` to `{a} T`
652
685
case _ =>
653
686
case _ =>
654
- val adapted = adapt(actualw, expected, covariant = true )
687
+ val adapted = adapt(actualw, expected, covariant = true , boxed = false )
655
688
if adapted ne actualw then
656
689
capt.println(i " adapt boxed $actual vs $expected ===> $adapted" )
657
690
adapted
0 commit comments