@@ -262,30 +262,36 @@ class CheckCaptures extends Recheck, SymTransformer:
262
262
def assertSub (cs1 : CaptureSet , cs2 : CaptureSet )(using Context ) =
263
263
assert(cs1.subCaptures(cs2, frozen = false ).isOK, i " $cs1 is not a subset of $cs2" )
264
264
265
- def checkOK (res : CompareResult , prefix : => String , pos : SrcPos )(using Context ): Unit =
265
+ def checkOK (res : CompareResult , prefix : => String , pos : SrcPos , provenance : => String = " " )(using Context ): Unit =
266
266
if ! res.isOK then
267
267
def toAdd : String = CaptureSet .levelErrors.toAdd.mkString
268
- report.error(em " $prefix included in the allowed capture set ${res.blocking}$toAdd" , pos)
268
+ def descr : String =
269
+ val d = res.blocking.description
270
+ if d.isEmpty then provenance else " "
271
+ report.error(em " $prefix included in the allowed capture set ${res.blocking}$descr$toAdd" , pos)
269
272
270
273
/** Check subcapturing `{elem} <: cs`, report error on failure */
271
- def checkElem (elem : CaptureRef , cs : CaptureSet , pos : SrcPos )(using Context ) =
274
+ def checkElem (elem : CaptureRef , cs : CaptureSet , pos : SrcPos , provenance : => String = " " )(using Context ) =
272
275
checkOK(
273
276
elem.singletonCaptureSet.subCaptures(cs, frozen = false ),
274
277
i " $elem cannot be referenced here; it is not " ,
275
- pos)
278
+ pos, provenance )
276
279
277
280
/** Check subcapturing `cs1 <: cs2`, report error on failure */
278
- def checkSubset (cs1 : CaptureSet , cs2 : CaptureSet , pos : SrcPos )(using Context ) =
281
+ def checkSubset (cs1 : CaptureSet , cs2 : CaptureSet , pos : SrcPos , provenance : => String = " " )(using Context ) =
279
282
checkOK(
280
283
cs1.subCaptures(cs2, frozen = false ),
281
- if cs1.elems.size == 1 then i " reference ${cs1.elems.toList} %, % is not"
284
+ if cs1.elems.size == 1 then i " reference ${cs1.elems.toList.head} is not "
282
285
else i " references $cs1 are not all " ,
283
- pos)
286
+ pos, provenance )
284
287
285
288
/** The current environment */
286
289
private var curEnv : Env = inContext(ictx):
287
290
Env (defn.RootClass , EnvKind .Regular , CaptureSet .empty, null )
288
291
292
+ /** Currently checked closures and their expected types, used for error reporting */
293
+ private var openClosures : List [(Symbol , Type )] = Nil
294
+
289
295
private val myCapturedVars : util.EqHashMap [Symbol , CaptureSet ] = EqHashMap ()
290
296
291
297
/** If `sym` is a class or method nested inside a term, a capture set variable representing
@@ -312,6 +318,19 @@ class CheckCaptures extends Recheck, SymTransformer:
312
318
recur(nextEnv, skip = env.kind == EnvKind .ClosureResult )
313
319
recur(curEnv, skip = false )
314
320
321
+ /** A description where this environment comes from */
322
+ private def provenance (env : Env )(using Context ): String =
323
+ val owner = env.owner
324
+ if owner.isAnonymousFunction then
325
+ val expected = openClosures
326
+ .find(_._1 == owner)
327
+ .map(_._2)
328
+ .getOrElse(owner.info.toFunctionType(isJava = false ))
329
+ i " \n of an enclosing function literal with expected type $expected"
330
+ else
331
+ i " \n of the enclosing ${owner.showLocated}"
332
+
333
+
315
334
/** Include `sym` in the capture sets of all enclosing environments nested in the
316
335
* the environment in which `sym` is defined.
317
336
*/
@@ -321,7 +340,7 @@ class CheckCaptures extends Recheck, SymTransformer:
321
340
if ref.isTracked then
322
341
forallOuterEnvsUpTo(sym.enclosure): env =>
323
342
capt.println(i " Mark $sym with cs ${ref.captureSet} free in ${env.owner}" )
324
- checkElem(ref, env.captured, pos)
343
+ checkElem(ref, env.captured, pos, provenance(env) )
325
344
326
345
/** Make sure (projected) `cs` is a subset of the capture sets of all enclosing
327
346
* environments. At each stage, only include references from `cs` that are outside
@@ -338,7 +357,7 @@ class CheckCaptures extends Recheck, SymTransformer:
338
357
case ref : ThisType => isVisibleFromEnv(ref.cls)
339
358
case _ => false
340
359
capt.println(i " Include call capture $included in ${env.owner}" )
341
- checkSubset(included, env.captured, pos)
360
+ checkSubset(included, env.captured, pos, provenance(env) )
342
361
343
362
/** Include references captured by the called method in the current environment stack */
344
363
def includeCallCaptures (sym : Symbol , pos : SrcPos )(using Context ): Unit =
@@ -585,11 +604,15 @@ class CheckCaptures extends Recheck, SymTransformer:
585
604
586
605
// Constrain closure's parameters and result from the expected type before
587
606
// rechecking the body.
588
- val res = recheckClosure(expr, pt, forceDependent = true )
589
- checkConformsExpr(res, pt, expr)
590
- recheckDef(mdef, mdef.symbol)
591
- // println(i"RECHECK CLOSURE ${mdef.symbol.info}")
592
- res
607
+ openClosures = (mdef.symbol, pt) :: openClosures
608
+ try
609
+ val res = recheckClosure(expr, pt, forceDependent = true )
610
+ checkConformsExpr(res, pt, expr)
611
+ recheckDef(mdef, mdef.symbol)
612
+ // println(i"RECHECK CLOSURE ${mdef.symbol.info}")
613
+ res
614
+ finally
615
+ openClosures = openClosures.tail
593
616
end recheckClosureBlock
594
617
595
618
override def recheckValDef (tree : ValDef , sym : Symbol )(using Context ): Unit =
@@ -608,7 +631,8 @@ class CheckCaptures extends Recheck, SymTransformer:
608
631
if ! Synthetics .isExcluded(sym) then
609
632
val saved = curEnv
610
633
val localSet = capturedVars(sym)
611
- if ! localSet.isAlwaysEmpty then curEnv = Env (sym, EnvKind .Regular , localSet, curEnv)
634
+ if ! localSet.isAlwaysEmpty then
635
+ curEnv = Env (sym, EnvKind .Regular , localSet, curEnv)
612
636
try super .recheckDefDef(tree, sym)
613
637
finally
614
638
interpolateVarsIn(tree.tpt)
@@ -625,7 +649,8 @@ class CheckCaptures extends Recheck, SymTransformer:
625
649
val saved = curEnv
626
650
val localSet = capturedVars(cls)
627
651
for parent <- impl.parents do // (1)
628
- checkSubset(capturedVars(parent.tpe.classSymbol), localSet, parent.srcPos)
652
+ checkSubset(capturedVars(parent.tpe.classSymbol), localSet, parent.srcPos,
653
+ i " \n of the references allowed to be captured by $cls" )
629
654
if ! localSet.isAlwaysEmpty then curEnv = Env (cls, EnvKind .Regular , localSet, curEnv)
630
655
try
631
656
val thisSet = cls.classInfo.selfType.captureSet.withDescription(i " of the self type of $cls" )
0 commit comments