@@ -730,7 +730,7 @@ class CheckCaptures extends Recheck, SymTransformer:
730
730
case _ =>
731
731
val res =
732
732
try super .recheck(tree, pt)
733
- catch case ex : CaptureRoot . NoCommonRoot =>
733
+ catch case ex : NoCommonRoot =>
734
734
report.error(ex.getMessage.nn)
735
735
tree.tpe
736
736
finally curEnv = saved
@@ -760,9 +760,13 @@ class CheckCaptures extends Recheck, SymTransformer:
760
760
}
761
761
checkNotUniversal(parent)
762
762
case _ =>
763
- if ! allowUniversalInBoxed && needsUniversalCheck then
764
- checkNotUniversal(tpe)
765
- super .recheckFinish(tpe, tree, pt)
763
+ val adapted =
764
+ if allowUniversalInBoxed then
765
+ adaptUniversal(tpe, pt, tree)
766
+ else
767
+ if needsUniversalCheck then checkNotUniversal(tpe)
768
+ tpe
769
+ super .recheckFinish(adapted, tree, pt)
766
770
end recheckFinish
767
771
768
772
// ------------------ Adaptation -------------------------------------
@@ -776,6 +780,32 @@ class CheckCaptures extends Recheck, SymTransformer:
776
780
// - Adapt box status and environment capture sets by simulating box/unbox operations.
777
781
// - Instantiate `cap` in actual as needed to a local root.
778
782
783
+ def impliedRoot (tree : Tree )(using Context ) =
784
+ val acc = new TreeAccumulator [Symbol ]:
785
+ val locals = mutable.Set [Symbol ]()
786
+ private def max (sym1 : Symbol , sym2 : Symbol )(using Context ) =
787
+ sym1.maxNested(sym2, onConflict = (_, _) => throw NoCommonRoot (sym1, sym2))
788
+ def apply (s : Symbol , t : Tree )(using Context ) = t match
789
+ case t : (Ident | This )
790
+ if ! locals.contains(t.symbol) && t.symbol.isTrackedSomewhere =>
791
+ max(s, t.symbol.levelOwner)
792
+ case t : DefTree =>
793
+ locals += t.symbol
794
+ foldOver(s, t)
795
+ case _ =>
796
+ foldOver(s, t)
797
+ acc(defn.RootClass , tree).localRoot
798
+
799
+ def adaptUniversal (actual : Type , expected : Type , tree : Tree )(using Context ): Type =
800
+ if expected.captureSet.disallowsUniversal && actual.captureSet.isUniversal then
801
+ val localRoot = impliedRoot(tree)
802
+ CapturingType (
803
+ actual.stripCapturing,
804
+ localRoot.termRef.singletonCaptureSet,
805
+ actual.isBoxedCapturing)
806
+ .showing(i " adapt universal $actual vs $expected = $result" )
807
+ else actual
808
+
779
809
/** Massage `actual` and `expected` types before checking conformance.
780
810
* Massaging is done by the methods following this one:
781
811
* - align dependent function types and add outer references in the expected type
@@ -865,6 +895,7 @@ class CheckCaptures extends Recheck, SymTransformer:
865
895
expected
866
896
end addOuterRefs
867
897
898
+
868
899
/** Adapt `actual` type to `expected` type by inserting boxing and unboxing conversions
869
900
*
870
901
* @param alwaysConst always make capture set variables constant after adaptation
0 commit comments