@@ -18,7 +18,7 @@ import util.{SimpleIdentitySet, EqHashMap, EqHashSet, SrcPos, Property}
18
18
import transform .{Recheck , PreRecheck , CapturedVars }
19
19
import Recheck .*
20
20
import scala .collection .mutable
21
- import CaptureSet .{withCaptureSetsExplained , IdempotentCaptRefMap , CompareResult }
21
+ import CaptureSet .{withCaptureSetsExplained , IdempotentCaptRefMap , CompareResult , ExistentialSubsumesFailure }
22
22
import CCState .*
23
23
import StdNames .nme
24
24
import NameKinds .{DefaultGetterName , WildcardParamName , UniqueNameKind }
@@ -354,7 +354,7 @@ class CheckCaptures extends Recheck, SymTransformer:
354
354
def checkOK (res : CompareResult , prefix : => String , added : CaptureRef | CaptureSet , pos : SrcPos , provenance : => String = " " )(using Context ): Unit =
355
355
if ! res.isOK then
356
356
inContext(root.printContext(added, res.blocking)):
357
- def toAdd : String = CaptureSet .levelErrors .toAdd.mkString
357
+ def toAdd : String = errorNotes(res.errorNotes) .toAdd.mkString
358
358
def descr : String =
359
359
val d = res.blocking.description
360
360
if d.isEmpty then provenance else " "
@@ -363,15 +363,15 @@ class CheckCaptures extends Recheck, SymTransformer:
363
363
/** Check subcapturing `{elem} <: cs`, report error on failure */
364
364
def checkElem (elem : CaptureRef , cs : CaptureSet , pos : SrcPos , provenance : => String = " " )(using Context ) =
365
365
checkOK(
366
- elem.singletonCaptureSet.subCaptures(cs),
366
+ ccState.test( elem.singletonCaptureSet.subCaptures(cs) ),
367
367
i " $elem cannot be referenced here; it is not " ,
368
368
elem, pos, provenance)
369
369
370
370
/** Check subcapturing `cs1 <: cs2`, report error on failure */
371
371
def checkSubset (cs1 : CaptureSet , cs2 : CaptureSet , pos : SrcPos ,
372
372
provenance : => String = " " , cs1description : String = " " )(using Context ) =
373
373
checkOK(
374
- cs1.subCaptures(cs2),
374
+ ccState.test( cs1.subCaptures(cs2) ),
375
375
if cs1.elems.size == 1 then i " reference ${cs1.elems.toList.head}$cs1description is not "
376
376
else i " references $cs1$cs1description are not all " ,
377
377
cs1, pos, provenance)
@@ -1210,27 +1210,29 @@ class CheckCaptures extends Recheck, SymTransformer:
1210
1210
1211
1211
type BoxErrors = mutable.ListBuffer [Message ] | Null
1212
1212
1213
- private def boxErrorAddenda ( boxErrors : BoxErrors ) =
1214
- if boxErrors == null then NothingToAdd
1213
+ private def errorNotes ( notes : List [ ErrorNote ])( using Context ) : Addenda =
1214
+ if notes.isEmpty then NothingToAdd
1215
1215
else new Addenda :
1216
- override def toAdd (using Context ): List [ String ] =
1217
- boxErrors.toList.map : msg =>
1218
- i """
1219
- |
1220
- |Note that ${msg.toString} "" "
1221
-
1222
- private def existentialSubsumesFailureAddenda ( using Context ) : Addenda =
1223
- ccState.existentialSubsumesFailure match
1224
- case Some ((ex @ root. Result (binder), other)) =>
1225
- new Addenda :
1226
- override def toAdd ( using Context ) : List [ String ] =
1227
- val ann = ex.rootAnnot
1228
- i """
1229
- |
1230
- |Note that the existential capture root in ${ex.rootAnnot.originalBinder.resType}
1216
+ override def toAdd (using Context ) = notes.map : note =>
1217
+ val msg = note match
1218
+ case CompareResult . LevelError (cs, ref) =>
1219
+ if ref.stripReadOnly.isCapOrFresh then
1220
+ def capStr = if ref.isReadOnly then " cap.rd " else " cap "
1221
+ i """ the universal capability ` $capStr `
1222
+ |cannot be included in capture set $cs """
1223
+ else
1224
+ val levelStr = ref match
1225
+ case ref : TermRef => i " , defined in ${ref.symbol.maybeOwner} "
1226
+ case _ => " "
1227
+ i """ reference ${ref}$levelStr
1228
+ |cannot be included in outer capture set $cs """
1229
+ case ExistentialSubsumesFailure (ex, other) =>
1230
+ i """ the existential capture root in ${ex.rootAnnot.originalBinder.resType}
1231
1231
|cannot subsume the capability $other"""
1232
- :: Nil
1233
- case _ => NothingToAdd
1232
+ i """
1233
+ |
1234
+ |Note that ${msg.toString}"""
1235
+
1234
1236
1235
1237
/** Addendas for error messages that show where we have under-approximated by
1236
1238
* mapping a a capture ref in contravariant position to the empty set because
@@ -1264,15 +1266,14 @@ class CheckCaptures extends Recheck, SymTransformer:
1264
1266
*/
1265
1267
override def checkConformsExpr (actual : Type , expected : Type , tree : Tree , addenda : Addenda )(using Context ): Type =
1266
1268
var expected1 = alignDependentFunction(expected, actual.stripCapturing)
1267
- val boxErrors = new mutable.ListBuffer [Message ]
1268
- val actualBoxed = adapt(actual, expected1, tree, boxErrors)
1269
+ val actualBoxed = adapt(actual, expected1, tree)
1269
1270
// println(i"check conforms $actualBoxed <<< $expected1")
1270
1271
1271
1272
if actualBoxed eq actual then
1272
1273
// Only `addOuterRefs` when there is no box adaptation
1273
1274
expected1 = addOuterRefs(expected1, actual, tree.srcPos)
1274
- ccState.existentialSubsumesFailure = None
1275
- if isCompatible(actualBoxed, expected1) then
1275
+ val result = ccState.testOK(isCompatible(actualBoxed, expected1))
1276
+ if result.isOK then
1276
1277
if debugSuccesses then tree match
1277
1278
case Ident (_) =>
1278
1279
println(i " SUCCESS $tree for $actual <:< $expected: \n ${TypeComparer .explained(_.isSubType(actualBoxed, expected1))}" )
@@ -1283,10 +1284,7 @@ class CheckCaptures extends Recheck, SymTransformer:
1283
1284
inContext(root.printContext(actualBoxed, expected1)):
1284
1285
err.typeMismatch(tree.withType(actualBoxed), expected1,
1285
1286
addApproxAddenda(
1286
- addenda
1287
- ++ CaptureSet .levelErrors
1288
- ++ boxErrorAddenda(boxErrors)
1289
- ++ existentialSubsumesFailureAddenda,
1287
+ addenda ++ errorNotes(result.errorNotes),
1290
1288
expected1))
1291
1289
actual
1292
1290
end checkConformsExpr
@@ -1397,7 +1395,7 @@ class CheckCaptures extends Recheck, SymTransformer:
1397
1395
*
1398
1396
* @param alwaysConst always make capture set variables constant after adaptation
1399
1397
*/
1400
- def adaptBoxed (actual : Type , expected : Type , tree : Tree , covariant : Boolean , alwaysConst : Boolean , boxErrors : BoxErrors )(using Context ): Type =
1398
+ def adaptBoxed (actual : Type , expected : Type , tree : Tree , covariant : Boolean , alwaysConst : Boolean )(using Context ): Type =
1401
1399
1402
1400
def recur (actual : Type , expected : Type , covariant : Boolean ): Type =
1403
1401
@@ -1551,15 +1549,15 @@ class CheckCaptures extends Recheck, SymTransformer:
1551
1549
* - narrow nested captures of `x`'s underlying type to `{x*}`
1552
1550
* - do box adaptation
1553
1551
*/
1554
- def adapt (actual : Type , expected : Type , tree : Tree , boxErrors : BoxErrors )(using Context ): Type =
1552
+ def adapt (actual : Type , expected : Type , tree : Tree )(using Context ): Type =
1555
1553
if noWiden(actual, expected) then
1556
1554
actual
1557
1555
else
1558
1556
val improvedVAR = improveCaptures(actual.widen.dealiasKeepAnnots, actual)
1559
1557
val improved = improveReadOnly(improvedVAR, expected)
1560
1558
val adapted = adaptBoxed(
1561
1559
improved.withReachCaptures(actual), expected, tree,
1562
- covariant = true , alwaysConst = false , boxErrors )
1560
+ covariant = true , alwaysConst = false )
1563
1561
if adapted eq improvedVAR // no .rd improvement, no box-adaptation
1564
1562
then actual // might as well use actual instead of improved widened
1565
1563
else adapted.showing(i " adapt $actual vs $expected = $adapted" , capt)
@@ -1585,7 +1583,7 @@ class CheckCaptures extends Recheck, SymTransformer:
1585
1583
try
1586
1584
curEnv = Env (clazz, EnvKind .NestedInOwner , capturedVars(clazz), outer0 = curEnv)
1587
1585
val adapted =
1588
- adaptBoxed(actual, expected1, tree, covariant = true , alwaysConst = true , null )
1586
+ adaptBoxed(actual, expected1, tree, covariant = true , alwaysConst = true )
1589
1587
actual match
1590
1588
case _ : MethodType =>
1591
1589
// We remove the capture set resulted from box adaptation for method types,
0 commit comments