1
1
package scala .util
2
+
3
+ import language .experimental .captureChecking
2
4
import scala .annotation .implicitNotFound
3
5
4
6
/** A boundary that can be exited by `break` calls.
@@ -27,18 +29,27 @@ import scala.annotation.implicitNotFound
27
29
* ```
28
30
*/
29
31
object boundary :
32
+ import caps .unsafe .unsafeAssumePure
30
33
31
34
/** User code should call `break.apply` instead of throwing this exception
32
35
* directly.
33
36
*/
34
- final class Break [T ] private [boundary]( val label : Label [T ], val value : T )
37
+ final class Break [T ] private [boundary] ( private [boundary] val label : Label [T ]^ {} , val value : T )
35
38
extends RuntimeException (
36
- /* message*/ null , /* cause*/ null , /* enableSuppression=*/ false , /* writableStackTrace*/ false )
39
+ /* message*/ null , /* cause*/ null , /* enableSuppression=*/ false , /* writableStackTrace*/ false ):
40
+
41
+ /** Compare the given [[Label ]] to the one this [[Break ]] was constructed with. */
42
+ inline def isSameLabelAs (other : Label [T ]) = label eq other
43
+
44
+ object Break :
45
+ def apply [T ](label : Label [T ], value : T ) =
46
+ // SAFETY: labels cannot leak from [[Break]], and is only used for equality comparison.
47
+ new Break (label.unsafeAssumePure, value)
37
48
38
49
/** Labels are targets indicating which boundary will be exited by a `break`.
39
50
*/
40
51
@ implicitNotFound(" explain=A Label is generated from an enclosing `scala.util.boundary` call.\n Maybe that boundary is missing?" )
41
- final class Label [- T ]
52
+ final class Label [- T ] extends caps. Capability
42
53
43
54
/** Abort current computation and instead return `value` as the value of
44
55
* the enclosing `boundary` call that created `label`.
@@ -60,7 +71,7 @@ object boundary:
60
71
val local = Label [T ]()
61
72
try body(using local)
62
73
catch case ex : Break [T ] @ unchecked =>
63
- if ex.label eq local then ex.value
74
+ if ex.isSameLabelAs( local) then ex.value
64
75
else throw ex
65
76
66
77
end boundary
0 commit comments