@@ -42,12 +42,20 @@ object CheckCaptures:
42
42
end Pre
43
43
44
44
/** A class describing environments.
45
- * @param owner the current owner
46
- * @param captured the caputure set containing all references to tracked free variables outside of boxes
47
- * @param isBoxed true if the environment is inside a box (in which case references are not counted)
48
- * @param outer0 the next enclosing environment
45
+ * @param owner the current owner
46
+ * @param nestedInOwner true if the environment is a temporary one nested in the owner's environment,
47
+ * and does not have an actual owner symbol (this happens when doing box adaptation).
48
+ * @param captured the caputure set containing all references to tracked free variables outside of boxes
49
+ * @param isBoxed true if the environment is inside a box (in which case references are not counted)
50
+ * @param outer0 the next enclosing environment
49
51
*/
50
- case class Env (owner : Symbol , captured : CaptureSet , isBoxed : Boolean , outer0 : Env | Null ):
52
+ case class Env (
53
+ owner : Symbol ,
54
+ nestedInOwner : Boolean ,
55
+ captured : CaptureSet ,
56
+ isBoxed : Boolean ,
57
+ outer0 : Env | Null
58
+ ):
51
59
def outer = outer0.nn
52
60
53
61
def isOutermost = outer0 == null
@@ -204,7 +212,7 @@ class CheckCaptures extends Recheck, SymTransformer:
204
212
report.error(i " $header included in allowed capture set ${res.blocking}" , pos)
205
213
206
214
/** The current environment */
207
- private var curEnv : Env = Env (NoSymbol , CaptureSet .empty, isBoxed = false , null )
215
+ private var curEnv : Env = Env (NoSymbol , false , CaptureSet .empty, isBoxed = false , null )
208
216
209
217
private val myCapturedVars : util.EqHashMap [Symbol , CaptureSet ] = EqHashMap ()
210
218
@@ -249,8 +257,12 @@ class CheckCaptures extends Recheck, SymTransformer:
249
257
if ! cs.isAlwaysEmpty then
250
258
forallOuterEnvsUpTo(ctx.owner.topLevelClass) { env =>
251
259
val included = cs.filter {
252
- case ref : TermRef => env.owner.isProperlyContainedIn(ref.symbol.owner)
253
- case ref : ThisType => env.owner.isProperlyContainedIn(ref.cls)
260
+ case ref : TermRef =>
261
+ (env.nestedInOwner || env.owner != ref.symbol.owner)
262
+ && env.owner.isContainedIn(ref.symbol.owner)
263
+ case ref : ThisType =>
264
+ (env.nestedInOwner || env.owner != ref.cls)
265
+ && env.owner.isContainedIn(ref.cls)
254
266
case _ => false
255
267
}
256
268
capt.println(i " Include call capture $included in ${env.owner}" )
@@ -439,7 +451,7 @@ class CheckCaptures extends Recheck, SymTransformer:
439
451
if ! Synthetics .isExcluded(sym) then
440
452
val saved = curEnv
441
453
val localSet = capturedVars(sym)
442
- if ! localSet.isAlwaysEmpty then curEnv = Env (sym, localSet, isBoxed = false , curEnv)
454
+ if ! localSet.isAlwaysEmpty then curEnv = Env (sym, false , localSet, isBoxed = false , curEnv)
443
455
try super .recheckDefDef(tree, sym)
444
456
finally
445
457
interpolateVarsIn(tree.tpt)
@@ -455,7 +467,7 @@ class CheckCaptures extends Recheck, SymTransformer:
455
467
val localSet = capturedVars(cls)
456
468
for parent <- impl.parents do // (1)
457
469
checkSubset(capturedVars(parent.tpe.classSymbol), localSet, parent.srcPos)
458
- if ! localSet.isAlwaysEmpty then curEnv = Env (cls, localSet, isBoxed = false , curEnv)
470
+ if ! localSet.isAlwaysEmpty then curEnv = Env (cls, false , localSet, isBoxed = false , curEnv)
459
471
try
460
472
val thisSet = cls.classInfo.selfType.captureSet.withDescription(i " of the self type of $cls" )
461
473
checkSubset(localSet, thisSet, tree.srcPos) // (2)
@@ -502,7 +514,7 @@ class CheckCaptures extends Recheck, SymTransformer:
502
514
override def recheck (tree : Tree , pt : Type = WildcardType )(using Context ): Type =
503
515
if tree.isTerm && pt.isBoxedCapturing then
504
516
val saved = curEnv
505
- curEnv = Env (curEnv.owner, CaptureSet .Var (), isBoxed = true , curEnv)
517
+ curEnv = Env (curEnv.owner, false , CaptureSet .Var (), isBoxed = true , curEnv)
506
518
try super .recheck(tree, pt)
507
519
finally curEnv = saved
508
520
else
@@ -595,12 +607,11 @@ class CheckCaptures extends Recheck, SymTransformer:
595
607
* to `expected` type.
596
608
* @param reconstruct how to rebuild the adapted function type
597
609
*/
598
- def adaptFun (actualTp : ( Type , CaptureSet ) , aargs : List [Type ], ares : Type , expected : Type ,
610
+ def adaptFun (actual : Type , aargs : List [Type ], ares : Type , expected : Type ,
599
611
covariant : Boolean , boxed : Boolean ,
600
612
reconstruct : (List [Type ], Type ) => Type ): (Type , CaptureSet ) =
601
- val (actual, cs0) = actualTp
602
613
val saved = curEnv
603
- curEnv = Env (curEnv.owner, CaptureSet .Var (), isBoxed = false , if boxed then null else curEnv)
614
+ curEnv = Env (curEnv.owner, true , CaptureSet .Var (), isBoxed = false , if boxed then null else curEnv)
604
615
605
616
try
606
617
val (eargs, eres) = expected.dealias match
@@ -618,17 +629,16 @@ class CheckCaptures extends Recheck, SymTransformer:
618
629
else reconstruct(aargs1, ares1)
619
630
620
631
curEnv.captured.asVar.markSolved()
621
- (resTp, curEnv.captured ++ cs0 )
632
+ (resTp, curEnv.captured)
622
633
finally
623
634
curEnv = saved
624
635
625
636
def adaptTypeFun (
626
- actualTp : ( Type , CaptureSet ) , ares : Type , expected : Type ,
637
+ actual : Type , ares : Type , expected : Type ,
627
638
covariant : Boolean , boxed : Boolean ,
628
639
reconstruct : Type => Type ): (Type , CaptureSet ) =
629
- val (actual, cs0) = actualTp
630
640
val saved = curEnv
631
- curEnv = Env (curEnv.owner, CaptureSet .Var (), isBoxed = false , if boxed then null else curEnv)
641
+ curEnv = Env (curEnv.owner, true , CaptureSet .Var (), isBoxed = false , if boxed then null else curEnv)
632
642
633
643
try
634
644
val eres = expected.dealias.stripCapturing match
@@ -642,7 +652,7 @@ class CheckCaptures extends Recheck, SymTransformer:
642
652
else reconstruct(ares1)
643
653
644
654
curEnv.captured.asVar.markSolved()
645
- (resTp, curEnv.captured ++ cs0 )
655
+ (resTp, curEnv.captured)
646
656
finally
647
657
curEnv = saved
648
658
end adaptTypeFun
@@ -651,8 +661,8 @@ class CheckCaptures extends Recheck, SymTransformer:
651
661
val arrow = if covariant then " ~~>" else " <~~"
652
662
i " adapting $actual $arrow $expected"
653
663
654
- def adapt ( actual : Type , expected : Type , covariant : Boolean ) : Type = trace(adaptInfo(actual, expected, covariant ), recheckr, show = true ) {
655
- def destructCapturingType ( tp : Type , reconstruct : Type => Type ) : (( Type , CaptureSet , Boolean ), Type => Type ) = tp.dealias match
664
+ def destructCapturingType ( tp : Type , reconstruct : Type => Type = x => x) : (( Type , CaptureSet , Boolean ), Type => Type ) =
665
+ tp.dealias match
656
666
case tp @ CapturingType (parent, cs) =>
657
667
if parent.dealias.isCapturingType then
658
668
destructCapturingType(parent, res => reconstruct(tp.derivedCapturingType(res, cs)))
@@ -661,72 +671,67 @@ class CheckCaptures extends Recheck, SymTransformer:
661
671
case actual =>
662
672
((actual, CaptureSet (), false ), reconstruct)
663
673
664
- if expected. isInstanceOf [ WildcardType ] then
665
- actual
674
+ def adapt ( actual : Type , expected : Type , covariant : Boolean ) : Type = trace(adaptInfo(actual, expected, covariant), recheckr, show = true ) {
675
+ if expected. isInstanceOf [ WildcardType ] then actual
666
676
else
667
- val (actualTp, recon) = destructCapturingType(actual, x => x)
668
- val (parent1, cs1, isBoxed1) = adaptCapturingType(actualTp, expected, covariant)
669
- recon(CapturingType (parent1, cs1, isBoxed1))
670
- }
671
-
672
- def adaptCapturingType (
673
- actual : (Type , CaptureSet , Boolean ),
674
- expected : Type ,
675
- covariant : Boolean
676
- ): (Type , CaptureSet , Boolean ) =
677
- val (parent, cs, actualIsBoxed) = actual
678
-
679
- val needsAdaptation = actualIsBoxed != expected.isBoxedCapturing
680
- val insertBox = needsAdaptation && covariant != actualIsBoxed
681
-
682
- val (parent1, cs1) = parent match {
683
- case actual @ AppliedType (tycon, args) if defn.isNonRefinedFunction(actual) =>
684
- adaptFun((parent, cs), args.init, args.last, expected, covariant, insertBox,
685
- (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
686
- case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
687
- // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere)
688
- adaptFun((parent, cs), rinfo.paramInfos, rinfo.resType, expected, covariant, insertBox,
689
- (aargs1, ares1) =>
690
- rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
691
- .toFunctionType(isJava = false , alwaysDependent = true ))
692
- case actual : MethodType =>
693
- adaptFun((parent, cs), actual.paramInfos, actual.resType, expected, covariant, insertBox,
694
- (aargs1, ares1) =>
695
- actual.derivedLambdaType(paramInfos = aargs1, resType = ares1))
696
- case actual @ RefinedType (p, nme, rinfo : PolyType ) if defn.isFunctionOrPolyType(actual) =>
697
- adaptTypeFun((parent, cs), rinfo.resType, expected, covariant, insertBox,
698
- ares1 =>
699
- val rinfo1 = rinfo.derivedLambdaType(rinfo.paramNames, rinfo.paramInfos, ares1)
700
- val actual1 = actual.derivedRefinedType(p, nme, rinfo1)
701
- actual1
702
- )
703
- case _ =>
704
- (parent, cs)
705
- }
677
+ val ((parent, cs, actualIsBoxed), recon) = destructCapturingType(actual)
678
+
679
+ val needsAdaptation = actualIsBoxed != expected.isBoxedCapturing
680
+ val insertBox = needsAdaptation && covariant != actualIsBoxed
681
+
682
+ val (parent1, cs1) = parent match {
683
+ case actual @ AppliedType (tycon, args) if defn.isNonRefinedFunction(actual) =>
684
+ val (parent1, cs1) = adaptFun(parent, args.init, args.last, expected, covariant, insertBox,
685
+ (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1))
686
+ (parent1, cs1 ++ cs)
687
+ case actual @ RefinedType (_, _, rinfo : MethodType ) if defn.isFunctionType(actual) =>
688
+ // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere)
689
+ val (parent1, cs1) = adaptFun(parent, rinfo.paramInfos, rinfo.resType, expected, covariant, insertBox,
690
+ (aargs1, ares1) =>
691
+ rinfo.derivedLambdaType(paramInfos = aargs1, resType = ares1)
692
+ .toFunctionType(isJava = false , alwaysDependent = true ))
693
+ (parent1, cs1 ++ cs)
694
+ case actual : MethodType =>
695
+ val (parent1, cs1) = adaptFun(parent, actual.paramInfos, actual.resType, expected, covariant, insertBox,
696
+ (aargs1, ares1) =>
697
+ actual.derivedLambdaType(paramInfos = aargs1, resType = ares1))
698
+ (parent1, cs1 ++ cs)
699
+ case actual @ RefinedType (p, nme, rinfo : PolyType ) if defn.isFunctionOrPolyType(actual) =>
700
+ val (parent1, cs1) = adaptTypeFun(parent, rinfo.resType, expected, covariant, insertBox,
701
+ ares1 =>
702
+ val rinfo1 = rinfo.derivedLambdaType(rinfo.paramNames, rinfo.paramInfos, ares1)
703
+ val actual1 = actual.derivedRefinedType(p, nme, rinfo1)
704
+ actual1
705
+ )
706
+ (parent1, cs1 ++ cs)
707
+ case _ =>
708
+ (parent, cs)
709
+ }
706
710
707
- if needsAdaptation then
708
- val criticalSet = // the set which is not allowed to have `*`
709
- if covariant then cs1 // can't box with `*`
710
- else expected.captureSet // can't unbox with `*`
711
- if criticalSet.isUniversal then
712
- // We can't box/unbox the universal capability. Leave `actual` as it is
713
- // so we get an error in checkConforms. This tends to give better error
714
- // messages than disallowing the root capability in `criticalSet`.
715
- capt.println(i " cannot box/unbox $cs $parent vs $expected" )
716
- actual
711
+ if needsAdaptation then
712
+ val criticalSet = // the set which is not allowed to have `*`
713
+ if covariant then cs1 // can't box with `*`
714
+ else expected.captureSet // can't unbox with `*`
715
+ if criticalSet.isUniversal then
716
+ // We can't box/unbox the universal capability. Leave `actual` as it is
717
+ // so we get an error in checkConforms. This tends to give better error
718
+ // messages than disallowing the root capability in `criticalSet`.
719
+ capt.println(i " cannot box/unbox $actual vs $expected" )
720
+ actual
721
+ else
722
+ // Disallow future addition of `*` to `criticalSet`.
723
+ criticalSet.disallowRootCapability { () =>
724
+ report.error(
725
+ em """ $actual cannot be box-converted to $expected
726
+ |since one of their capture sets contains the root capability `*` """ ,
727
+ pos)
728
+ }
729
+ if ! insertBox then // unboxing
730
+ markFree(criticalSet, pos)
731
+ recon(CapturingType (parent1, cs1, ! actualIsBoxed))
717
732
else
718
- // Disallow future addition of `*` to `criticalSet`.
719
- criticalSet.disallowRootCapability { () =>
720
- report.error(
721
- em """ $actualIsBoxed $cs $parent cannot be box-converted to $expected
722
- |since one of their capture sets contains the root capability `*` """ ,
723
- pos)
724
- }
725
- if ! insertBox then // unboxing
726
- markFree(cs1, pos)
727
- (parent1, cs1, ! actualIsBoxed)
728
- else
729
- (parent1, cs1, actualIsBoxed)
733
+ recon(CapturingType (parent1, cs1, actualIsBoxed))
734
+ }
730
735
731
736
732
737
var actualw = actual.widenDealias
0 commit comments