@@ -16,6 +16,7 @@ import transform.Recheck
1616import Recheck .*
1717import scala .collection .mutable
1818import CaptureSet .withCaptureSetsExplained
19+ import reporting .trace
1920
2021object CheckCaptures :
2122 import ast .tpd .*
@@ -75,7 +76,15 @@ object CheckCaptures:
7576 if remaining.accountsFor(firstRef) then
7677 report.warning(em " redundant capture: $remaining already accounts for $firstRef" , ann.srcPos)
7778
78- private inline val disallowGlobal = true
79+ /** Does this function allow type arguments carrying the universal capability?
80+ * Currently this is true only for `erasedValue` since this function is magic in
81+ * that is allows to conjure global capabilies from nothing (aside: can we find a
82+ * more controlled way to achieve this?).
83+ * But it could be generalized to other functions that so that they can take capability
84+ * classes as arguments.
85+ */
86+ private def allowUniversalArguments (fn : Tree )(using Context ): Boolean =
87+ fn.symbol == defn.Compiletime_erasedValue
7988
8089class CheckCaptures extends Recheck :
8190 thisPhase =>
@@ -305,13 +314,13 @@ class CheckCaptures extends Recheck:
305314 .traverse(ctx.compilationUnit.tpdTree)
306315 withCaptureSetsExplained {
307316 super .checkUnit(unit)
308- PostRefinerCheck .traverse(unit.tpdTree)
317+ PostCheck .traverse(unit.tpdTree)
309318 if ctx.settings.YccDebug .value then
310319 show(unit.tpdTree) // this dows not print tree, but makes its variables visible for dependency printing
311320 }
312321
313- def checkNotGlobal (tree : Tree , tp : Type , allArgs : Tree * )(using Context ): Unit =
314- for ref <- tp.captureSet.elems do
322+ def checkNotGlobal (tree : Tree , tp : Type , isVar : Boolean , allArgs : Tree * )(using Context ): Unit =
323+ for ref <- tp.captureSet.elems do
315324 val isGlobal = ref match
316325 case ref : TermRef => ref.isRootCapability
317326 case _ => false
@@ -320,7 +329,7 @@ class CheckCaptures extends Recheck:
320329 val notAllowed = i " is not allowed to capture the $what capability $ref"
321330 def msg =
322331 if allArgs.isEmpty then
323- i " type of mutable variable ${tree.knownType}$notAllowed"
332+ i " ${ if isVar then " type of mutable variable" else " result type " } ${tree.knownType}$notAllowed"
324333 else tree match
325334 case tree : InferredTypeTree =>
326335 i """ inferred type argument ${tree.knownType}$notAllowed
@@ -330,12 +339,11 @@ class CheckCaptures extends Recheck:
330339 report.error(msg, tree.srcPos)
331340
332341 def checkNotGlobal (tree : Tree , allArgs : Tree * )(using Context ): Unit =
333- if disallowGlobal then
334- tree match
335- case LambdaTypeTree (_, restpt) =>
336- checkNotGlobal(restpt, allArgs* )
337- case _ =>
338- checkNotGlobal(tree, tree.knownType, allArgs* )
342+ tree match
343+ case LambdaTypeTree (_, restpt) =>
344+ checkNotGlobal(restpt, allArgs* )
345+ case _ =>
346+ checkNotGlobal(tree, tree.knownType, isVar = false , allArgs* )
339347
340348 def checkNotGlobalDeep (tree : Tree )(using Context ): Unit =
341349 val checker = new TypeTraverser :
@@ -346,12 +354,12 @@ class CheckCaptures extends Recheck:
346354 case _ =>
347355 case tp : TermRef =>
348356 case _ =>
349- checkNotGlobal(tree, tp)
357+ checkNotGlobal(tree, tp, isVar = true )
350358 traverseChildren(tp)
351359 checker.traverse(tree.knownType)
352360
353- object PostRefinerCheck extends TreeTraverser :
354- def traverse (tree : Tree )(using Context ) =
361+ object PostCheck extends TreeTraverser :
362+ def traverse (tree : Tree )(using Context ) = trace{ i " post check $tree " } {
355363 tree match
356364 case _ : InferredTypeTree =>
357365 case tree : TypeTree if ! tree.span.isZeroExtent =>
@@ -362,7 +370,7 @@ class CheckCaptures extends Recheck:
362370 checkWellformedPost(annot.tree)
363371 case _ =>
364372 }
365- case tree1 @ TypeApply (fn, args) if disallowGlobal =>
373+ case tree1 @ TypeApply (fn, args) if ! allowUniversalArguments(fn) =>
366374 for arg <- args do
367375 // println(i"checking $arg in $tree: ${tree.knownType.captureSet}")
368376 checkNotGlobal(arg, args* )
@@ -390,11 +398,14 @@ class CheckCaptures extends Recheck:
390398 inferred.foreachPart(checkPure, StopAt .Static )
391399 case t : ValDef if t.symbol.is(Mutable ) =>
392400 checkNotGlobalDeep(t.tpt)
401+ case t : Try =>
402+ checkNotGlobal(t)
393403 case _ =>
394404 traverseChildren(tree)
405+ }
395406
396- def postRefinerCheck (tree : tpd.Tree )(using Context ): Unit =
397- PostRefinerCheck .traverse(tree)
407+ def postCheck (tree : tpd.Tree )(using Context ): Unit =
408+ PostCheck .traverse(tree)
398409
399410 end CaptureChecker
400411end CheckCaptures
0 commit comments