@@ -596,51 +596,84 @@ class CheckCaptures extends Recheck, SymTransformer:
596596 * @param reconstruct how to rebuild the adapted function type
597597 */
598598 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 )
622661 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+
644677
645678 var actualw = actual.widenDealias
646679 actual match
@@ -651,7 +684,7 @@ class CheckCaptures extends Recheck, SymTransformer:
651684 // given `a: C T`, improve `C T` to `{a} T`
652685 case _ =>
653686 case _ =>
654- val adapted = adapt(actualw, expected, covariant = true )
687+ val adapted = adapt(actualw, expected, covariant = true , boxed = false )
655688 if adapted ne actualw then
656689 capt.println(i " adapt boxed $actual vs $expected ===> $adapted" )
657690 adapted
0 commit comments