The error messages do give you a bit of a run-around. They are both correct, but not helpful since the obvious fix to the type mismatch causes the leakage error for the reach capability. I tried in Warn if reach capability in result will likely cause leakage by odersky · Pull Request #24860 · scala/scala3 · GitHub to give you a warning at the point where you try toi add the reach capability to the result. That now produces the following for your example:
-- Warning: tests/neg-custom-args/captures/nicolas2.scala:9:53 ---------------------------------------------------------
9 |def oneOf[A](head: Rand ?=> A, tail: (Rand ?=> A)*): Rand ?->{head, tail*} A =
| ^^^^^^^^^^^^^^^^^^^^^^^
| Reach capability tail* in function result refers to parameter tail.
| To avoid errors of the form "Local reach capability tail* leaks into capture scope ..."
| you should replace the reach capability with a new capset variable in method oneOf.
-- Error: tests/neg-custom-args/captures/nicolas2.scala:11:5 -----------------------------------------------------------
11 | all(nextInt(all.length)) // error
| ^^^^^^^^^^^^^^^^^^^^^^^^
| Local reach capability tail* leaks into capture scope of method oneOf.
| You could try to abstract the capabilities referred to by tail* in a capset variable.
The correct way to fix the example is:
import caps.*
trait Rand extends SharedCapability:
def range(min: Int, max: Int): Int
def nextInt(max: Int): Rand ?-> Int =
r ?=> r.range(0, max)
def oneOf[A, B^](head: Rand ?=> A, tail: (Rand ?->{B} A)*): Rand ?->{head, B} A =
val all: Seq[Rand ?->{head, B} A] = head +: tail // error
all(nextInt(all.length))