@@ -12,7 +12,7 @@ import ast.{tpd, untpd, Trees}
12
12
import Trees .*
13
13
import typer .RefChecks .{checkAllOverrides , checkSelfAgainstParents , OverridingPairsChecker }
14
14
import typer .Checking .{checkBounds , checkAppliedTypesIn }
15
- import typer .ErrorReporting .{Addenda , err }
15
+ import typer .ErrorReporting .{Addenda , NothingToAdd , err }
16
16
import typer .ProtoTypes .{AnySelectionProto , LhsProto }
17
17
import util .{SimpleIdentitySet , EqHashMap , EqHashSet , SrcPos , Property }
18
18
import transform .{Recheck , PreRecheck , CapturedVars }
@@ -22,7 +22,7 @@ import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap, CompareResult
22
22
import CCState .*
23
23
import StdNames .nme
24
24
import NameKinds .{DefaultGetterName , WildcardParamName , UniqueNameKind }
25
- import reporting .trace
25
+ import reporting .{ trace , Message }
26
26
27
27
/** The capture checker */
28
28
object CheckCaptures :
@@ -866,7 +866,10 @@ class CheckCaptures extends Recheck, SymTransformer:
866
866
}
867
867
checkNotUniversal(parent)
868
868
case _ =>
869
- if ! ccConfig.allowUniversalInBoxed && needsUniversalCheck then
869
+ if ! ccConfig.allowUniversalInBoxed
870
+ && ! tpe.hasAnnotation(defn.UncheckedCapturesAnnot )
871
+ && needsUniversalCheck
872
+ then
870
873
checkNotUniversal(tpe)
871
874
super .recheckFinish(tpe, tree, pt)
872
875
end recheckFinish
@@ -884,6 +887,17 @@ class CheckCaptures extends Recheck, SymTransformer:
884
887
885
888
private inline val debugSuccesses = false
886
889
890
+ type BoxErrors = mutable.ListBuffer [Message ] | Null
891
+
892
+ private def boxErrorAddenda (boxErrors : BoxErrors ) =
893
+ if boxErrors == null then NothingToAdd
894
+ else new Addenda :
895
+ override def toAdd (using Context ): List [String ] =
896
+ boxErrors.toList.map: msg =>
897
+ i """
898
+ |
899
+ |Note that ${msg.toString}"""
900
+
887
901
/** Massage `actual` and `expected` types before checking conformance.
888
902
* Massaging is done by the methods following this one:
889
903
* - align dependent function types and add outer references in the expected type
@@ -893,7 +907,8 @@ class CheckCaptures extends Recheck, SymTransformer:
893
907
*/
894
908
override def checkConformsExpr (actual : Type , expected : Type , tree : Tree , addenda : Addenda )(using Context ): Type =
895
909
var expected1 = alignDependentFunction(expected, actual.stripCapturing)
896
- val actualBoxed = adapt(actual, expected1, tree.srcPos)
910
+ val boxErrors = new mutable.ListBuffer [Message ]
911
+ val actualBoxed = adapt(actual, expected1, tree.srcPos, boxErrors)
897
912
// println(i"check conforms $actualBoxed <<< $expected1")
898
913
899
914
if actualBoxed eq actual then
@@ -907,7 +922,8 @@ class CheckCaptures extends Recheck, SymTransformer:
907
922
actualBoxed
908
923
else
909
924
capt.println(i " conforms failed for ${tree}: $actual vs $expected" )
910
- err.typeMismatch(tree.withType(actualBoxed), expected1, addenda ++ CaptureSet .levelErrors)
925
+ err.typeMismatch(tree.withType(actualBoxed), expected1,
926
+ addenda ++ CaptureSet .levelErrors ++ boxErrorAddenda(boxErrors))
911
927
actual
912
928
end checkConformsExpr
913
929
@@ -991,7 +1007,7 @@ class CheckCaptures extends Recheck, SymTransformer:
991
1007
*
992
1008
* @param alwaysConst always make capture set variables constant after adaptation
993
1009
*/
994
- def adaptBoxed (actual : Type , expected : Type , pos : SrcPos , covariant : Boolean , alwaysConst : Boolean )(using Context ): Type =
1010
+ def adaptBoxed (actual : Type , expected : Type , pos : SrcPos , covariant : Boolean , alwaysConst : Boolean , boxErrors : BoxErrors )(using Context ): Type =
995
1011
996
1012
/** Adapt the inner shape type: get the adapted shape type, and the capture set leaked during adaptation
997
1013
* @param boxed if true we adapt to a boxed expected type
@@ -1008,8 +1024,8 @@ class CheckCaptures extends Recheck, SymTransformer:
1008
1024
case FunctionOrMethod (eargs, eres) => (eargs, eres)
1009
1025
case _ => (aargs.map(_ => WildcardType ), WildcardType )
1010
1026
val aargs1 = aargs.zipWithConserve(eargs):
1011
- adaptBoxed(_, _, pos, ! covariant, alwaysConst)
1012
- val ares1 = adaptBoxed(ares, eres, pos, covariant, alwaysConst)
1027
+ adaptBoxed(_, _, pos, ! covariant, alwaysConst, boxErrors )
1028
+ val ares1 = adaptBoxed(ares, eres, pos, covariant, alwaysConst, boxErrors )
1013
1029
val resTp =
1014
1030
if (aargs1 eq aargs) && (ares1 eq ares) then actualShape // optimize to avoid redundant matches
1015
1031
else actualShape.derivedFunctionOrMethod(aargs1, ares1)
@@ -1057,22 +1073,26 @@ class CheckCaptures extends Recheck, SymTransformer:
1057
1073
val criticalSet = // the set which is not allowed to have `cap`
1058
1074
if covariant then captures // can't box with `cap`
1059
1075
else expected.captureSet // can't unbox with `cap`
1060
- if criticalSet.isUniversal && expected.isValueType && ! ccConfig.allowUniversalInBoxed then
1076
+ def msg = em """ $actual cannot be box-converted to $expected
1077
+ |since at least one of their capture sets contains the root capability `cap` """
1078
+ def allowUniversalInBoxed =
1079
+ ccConfig.allowUniversalInBoxed
1080
+ || expected.hasAnnotation(defn.UncheckedCapturesAnnot )
1081
+ || actual.widen.hasAnnotation(defn.UncheckedCapturesAnnot )
1082
+ if criticalSet.isUniversal && expected.isValueType && ! allowUniversalInBoxed then
1061
1083
// We can't box/unbox the universal capability. Leave `actual` as it is
1062
- // so we get an error in checkConforms. This tends to give better error
1084
+ // so we get an error in checkConforms. Add the error message generated
1085
+ // from boxing as an addendum. This tends to give better error
1063
1086
// messages than disallowing the root capability in `criticalSet`.
1087
+ if boxErrors != null then boxErrors += msg
1064
1088
if ctx.settings.YccDebug .value then
1065
1089
println(i " cannot box/unbox $actual vs $expected" )
1066
1090
actual
1067
1091
else
1068
- if ! ccConfig. allowUniversalInBoxed then
1092
+ if ! allowUniversalInBoxed then
1069
1093
// Disallow future addition of `cap` to `criticalSet`.
1070
- criticalSet.disallowRootCapability { () =>
1071
- report.error(
1072
- em """ $actual cannot be box-converted to $expected
1073
- |since one of their capture sets contains the root capability `cap` """ ,
1074
- pos)
1075
- }
1094
+ criticalSet.disallowRootCapability: () =>
1095
+ report.error(msg, pos)
1076
1096
if ! insertBox then // unboxing
1077
1097
// debugShowEnvs()
1078
1098
markFree(criticalSet, pos)
@@ -1109,13 +1129,15 @@ class CheckCaptures extends Recheck, SymTransformer:
1109
1129
*
1110
1130
* @param alwaysConst always make capture set variables constant after adaptation
1111
1131
*/
1112
- def adapt (actual : Type , expected : Type , pos : SrcPos )(using Context ): Type =
1132
+ def adapt (actual : Type , expected : Type , pos : SrcPos , boxErrors : BoxErrors )(using Context ): Type =
1113
1133
if expected == LhsProto || expected.isSingleton && actual.isSingleton then
1114
1134
actual
1115
1135
else
1116
1136
val normalized = makeCaptureSetExplicit(actual)
1117
- val widened = improveCaptures(normalized.widenDealias, actual)
1118
- val adapted = adaptBoxed(widened.withReachCaptures(actual), expected, pos, covariant = true , alwaysConst = false )
1137
+ val widened = improveCaptures(normalized.widen.dealiasKeepAnnots, actual)
1138
+ val adapted = adaptBoxed(
1139
+ widened.withReachCaptures(actual), expected, pos,
1140
+ covariant = true , alwaysConst = false , boxErrors)
1119
1141
if adapted eq widened then normalized
1120
1142
else adapted.showing(i " adapt boxed $actual vs $expected ===> $adapted" , capt)
1121
1143
end adapt
@@ -1137,7 +1159,8 @@ class CheckCaptures extends Recheck, SymTransformer:
1137
1159
val saved = curEnv
1138
1160
try
1139
1161
curEnv = Env (clazz, EnvKind .NestedInOwner , capturedVars(clazz), outer0 = curEnv)
1140
- val adapted = adaptBoxed(/* Existential.strip*/ (actual), expected1, srcPos, covariant = true , alwaysConst = true )
1162
+ val adapted =
1163
+ adaptBoxed(/* Existential.strip*/ (actual), expected1, srcPos, covariant = true , alwaysConst = true , null )
1141
1164
actual match
1142
1165
case _ : MethodType =>
1143
1166
// We remove the capture set resulted from box adaptation for method types,
0 commit comments