Skip to content

Commit b20db6e

Browse files
committed
Patch DropBreaks to correctly detect boundary blocks
We previously had the `ex.label eq label` comparision, which is no longer the case, with the (package) private label field.
1 parent 0ca72bc commit b20db6e

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ object StdNames {
530530
val isEmpty: N = "isEmpty"
531531
val isInstanceOf_ : N = "isInstanceOf"
532532
val isInstanceOfPM: N = "$isInstanceOf$"
533+
val isSameLabelAs : N = "isSameLabelAs"
533534
val java: N = "java"
534535
val key: N = "key"
535536
val label: N = "label"

compiler/src/dotty/tools/dotc/transform/DropBreaks.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ class DropBreaks extends MiniPhase:
6363
*/
6464
def unapply(expr: Tree)(using Context): Option[(Symbol, Symbol)] = stripTyped(expr) match
6565
case If(
66-
Apply(Select(Select(ex: Ident, label), eq), (lbl @ Ident(local)) :: Nil),
66+
Apply(Select(ex: Ident, isSameLabelAs), (lbl @ Ident(local)) :: Nil),
6767
Select(ex2: Ident, value),
6868
Apply(throww, (ex3: Ident) :: Nil))
69-
if label == nme.label && eq == nme.eq && local == nme.local && value == nme.value
69+
if isSameLabelAs == nme.isSameLabelAs && local == nme.local && value == nme.value
7070
&& throww.symbol == defn.throwMethod
7171
&& ex.symbol == ex2.symbol && ex.symbol == ex3.symbol =>
7272
Some((ex.symbol, lbl.symbol))

library/src/scala/util/boundary.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
package scala.util
2+
3+
import language.experimental.captureChecking
24
import scala.annotation.implicitNotFound
35

46
/** A boundary that can be exited by `break` calls.
@@ -31,9 +33,17 @@ object boundary:
3133
/** User code should call `break.apply` instead of throwing this exception
3234
* directly.
3335
*/
34-
final class Break[T] private[boundary](val label: Label[T], val value: T)
36+
final class Break[T] private[boundary](private[boundary] val label: Label[T]^{}, val value: T)
3537
extends RuntimeException(
36-
/*message*/ null, /*cause*/ null, /*enableSuppression=*/ false, /*writableStackTrace*/ false)
38+
/*message*/ null, /*cause*/ null, /*enableSuppression=*/ false, /*writableStackTrace*/ false):
39+
/** Compare the given [[Label]] to the one this [[Break]] was constructed with. */
40+
def isSameLabelAs(other: Label[T]) = label eq other
41+
42+
object Break:
43+
import caps.unsafe.unsafeAssumePure
44+
def apply[T](label: Label[T], value: T) =
45+
// SAFETY: labels cannot leak from [[Break]], and is only used for equality comparison.
46+
new Break(label.unsafeAssumePure, value)
3747

3848
/** Labels are targets indicating which boundary will be exited by a `break`.
3949
*/

0 commit comments

Comments
 (0)