Description
scala.annotation.retains
and retainsCap
are internally used by the capture checker as the representation of capturing types. While capture checking itself is still evolving, the annotations should be considered stable.
Generally, the annotations does not show up in programs that do not enable experimental.captureChecking
, even when interacting with modules that do. However, inlining will surface these annotations. While they do not affect the type checker, they cause the experimental
check to fail.
An example of this is the scala.util.boundary
package, which would greatly benefit from having its Label
tracked and capture-checked.
However, boundary.apply
requires its body to be inlined into the caller (so that locally-scoped boundary.break
calls turn into efficient jumps), which leaks the tracked label
with the retainsCap
annotation into the caller.
/** Run `body` with freshly generated label as implicit argument. Catch any
* breaks associated with that label and return their results instead of
* `body`'s result.
*/
inline def apply[T](inline body: Label[T]^ ?=> T): T =
val local: Label[T]^ = Label[T]() // Label[T] @retainsCap
try body(using local)
catch case ex: Break[T] @unchecked =>
if ex.label eq local.id then ex.value
else throw ex
This would prevent code not enabling capture-checking (which includes the Scala compiler itself) from using boundary
.