From c5038b7d18d316c7e30e112a74c6054255f37336 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 20 Feb 2023 14:25:28 +0100 Subject: [PATCH 1/5] Fix race condition in new LazyVals --- library/src/scala/runtime/LazyVals.scala | 2 +- tests/run/i16806.check | 2 ++ tests/run/i16806.scala | 42 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/run/i16806.check create mode 100644 tests/run/i16806.scala diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 5d1e8e74b89d..416ffc91d34a 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -45,7 +45,7 @@ object LazyVals { /* ------------- Start of public API ------------- */ - sealed trait LazyValControlState + sealed trait LazyValControlState extends Serializable /** * Used to indicate the state of a lazy val that is being diff --git a/tests/run/i16806.check b/tests/run/i16806.check new file mode 100644 index 000000000000..af917347162a --- /dev/null +++ b/tests/run/i16806.check @@ -0,0 +1,2 @@ +Success +Success \ No newline at end of file diff --git a/tests/run/i16806.scala b/tests/run/i16806.scala new file mode 100644 index 000000000000..f45652080458 --- /dev/null +++ b/tests/run/i16806.scala @@ -0,0 +1,42 @@ +import java.util.concurrent.Semaphore +import scala.runtime.LazyVals.Evaluating + +object Repro { + + case object DFBit + final class DFError extends Exception("") + final class DFType[+T](val value: T | DFError) extends AnyVal + + def asIR(dfType: DFType[DFBit.type]): DFBit.type = dfType.value match + case dfTypeIR: DFBit.type => dfTypeIR + case err: DFError => throw new DFError + + object Holder { + val s = new Semaphore(1, false) + final lazy val Bit = { + s.release() + new DFType[DFBit.type](DFBit) + } + } + + @main + def Test = + val a = new Thread() { + override def run(): Unit = + Holder.s.acquire() + val x = Holder.Bit.value + assert(!x.isInstanceOf[Evaluating.type]) + println("Success") + } + val b = new Thread() { + override def run(): Unit = + Holder.s.acquire() + val x = Holder.Bit.value + assert(!x.isInstanceOf[Evaluating.type]) + println("Success") + } + a.start() + b.start() + a.join(300) + b.join(300) +} \ No newline at end of file From fd3d0e69f3176167ceab1e7afc79ddacf887fe74 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 20 Feb 2023 14:54:23 +0100 Subject: [PATCH 2/5] Add MiMA exceptions --- project/MiMaFilters.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 8af2de7058ee..49e18db3fccb 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -26,6 +26,11 @@ object MiMaFilters { ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language#experimental.into"), ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$experimental$into$"), // end of New experimental features in 3.3.X + + // Added java.io.Serializable as LazyValControlState supertype + ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyVals$LazyValControlState"), + ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyVals$Waiting"), + ) val TastyCore: Seq[ProblemFilter] = Seq( ProblemFilters.exclude[DirectMissingMethodProblem]("dotty.tools.tasty.TastyBuffer.reset"), From 4ee457469b30b39f1e650b4a382a585033f4f385 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 20 Feb 2023 16:51:05 +0100 Subject: [PATCH 3/5] Do not depend on runtime lib in tests --- tests/run/i16806.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/run/i16806.scala b/tests/run/i16806.scala index f45652080458..0b0dfe1f6b35 100644 --- a/tests/run/i16806.scala +++ b/tests/run/i16806.scala @@ -1,5 +1,4 @@ import java.util.concurrent.Semaphore -import scala.runtime.LazyVals.Evaluating object Repro { @@ -25,14 +24,14 @@ object Repro { override def run(): Unit = Holder.s.acquire() val x = Holder.Bit.value - assert(!x.isInstanceOf[Evaluating.type]) + assert(x.isInstanceOf[DFBit.type]) println("Success") } val b = new Thread() { override def run(): Unit = Holder.s.acquire() val x = Holder.Bit.value - assert(!x.isInstanceOf[Evaluating.type]) + assert(x.isInstanceOf[DFBit.type]) println("Success") } a.start() From 6f75016212a9bed2e85a834c59fd23ba45a602b1 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 27 Feb 2023 12:11:24 +0100 Subject: [PATCH 4/5] Disable test for Scalajs --- tests/run/i16806.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run/i16806.scala b/tests/run/i16806.scala index 0b0dfe1f6b35..16c0fb0d3ef5 100644 --- a/tests/run/i16806.scala +++ b/tests/run/i16806.scala @@ -1,3 +1,4 @@ +//scalajs: --skip import java.util.concurrent.Semaphore object Repro { From a43787af3eba1d155f1b107972658daedf6e68d8 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 27 Feb 2023 12:40:41 +0100 Subject: [PATCH 5/5] Add comment describing why LazyValControlState extends Serializable --- library/src/scala/runtime/LazyVals.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 416ffc91d34a..d8c89c7abf28 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -45,6 +45,7 @@ object LazyVals { /* ------------- Start of public API ------------- */ + // This trait extends Serializable to fix #16806 that caused a race condition sealed trait LazyValControlState extends Serializable /**