From 11409fc23c52d3ed79440dbc2aef49db21624045 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 21 Dec 2025 21:47:58 +0100 Subject: [PATCH 1/4] Make test.dotty.Properties more verbose when classpath entry is not set --- compiler/test/dotty/Properties.scala | 37 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/test/dotty/Properties.scala b/compiler/test/dotty/Properties.scala index 6b529704b832..973936681841 100644 --- a/compiler/test/dotty/Properties.scala +++ b/compiler/test/dotty/Properties.scala @@ -52,31 +52,31 @@ object Properties { val testsSafeMode: Boolean = sys.props.isDefinedAt("dotty.tests.safemode") /** Extra directory containing sources for the compiler */ - def dottyCompilerManagedSources: Path = Paths.get(sys.props("dotty.tests.dottyCompilerManagedSources")) + def dottyCompilerManagedSources: Path = Paths.get(requireNonEmptyProperty("dotty.tests.dottyCompilerManagedSources")) /** dotty-interfaces jar */ - def dottyInterfaces: String = sys.props("dotty.tests.classes.dottyInterfaces") + def dottyInterfaces: String = requireNonEmptyProperty("dotty.tests.classes.dottyInterfaces") /** dotty-compiler jar */ - def dottyCompiler: String = sys.props("dotty.tests.classes.dottyCompiler") + def dottyCompiler: String = requireNonEmptyProperty("dotty.tests.classes.dottyCompiler") /** dotty-repl jar */ - def dottyRepl: String = sys.props("dotty.tests.classes.dottyRepl") + def dottyRepl: String = requireNonEmptyProperty("dotty.tests.classes.dottyRepl") /** dotty-staging jar */ - def dottyStaging: String = sys.props("dotty.tests.classes.dottyStaging") + def dottyStaging: String = requireNonEmptyProperty("dotty.tests.classes.dottyStaging") /** dotty-tasty-inspector jar */ - def dottyTastyInspector: String = sys.props("dotty.tests.classes.dottyTastyInspector") + def dottyTastyInspector: String = requireNonEmptyProperty("dotty.tests.classes.dottyTastyInspector") /** tasty-core jar */ - def tastyCore: String = sys.props("dotty.tests.classes.tastyCore") + def tastyCore: String = requireNonEmptyProperty("dotty.tests.classes.tastyCore") /** compiler-interface jar */ - def compilerInterface: String = sys.props("dotty.tests.classes.compilerInterface") + def compilerInterface: String = requireNonEmptyProperty("dotty.tests.classes.compilerInterface") /** scala-library jar */ - def scalaLibrary: String = sys.props("dotty.tests.classes.scalaLibrary") + def scalaLibrary: String = requireNonEmptyProperty("dotty.tests.classes.scalaLibrary") // TODO: Remove this once we migrate the test suite def usingScalaLibraryCCTasty: Boolean = true @@ -85,20 +85,27 @@ object Properties { def usingScalaLibraryTasty: Boolean = true /** scala-asm jar */ - def scalaAsm: String = sys.props("dotty.tests.classes.scalaAsm") + def scalaAsm: String = requireNonEmptyProperty("dotty.tests.classes.scalaAsm") /** jline-terminal jar */ - def jlineTerminal: String = sys.props("dotty.tests.classes.jlineTerminal") + def jlineTerminal: String = requireNonEmptyProperty("dotty.tests.classes.jlineTerminal") /** jline-reader jar */ - def jlineReader: String = sys.props("dotty.tests.classes.jlineReader") + def jlineReader: String = requireNonEmptyProperty("dotty.tests.classes.jlineReader") /** scalajs-javalib jar */ - def scalaJSJavalib: String = sys.props("dotty.tests.classes.scalaJSJavalib") + def scalaJSJavalib: String = requireNonEmptyProperty("dotty.tests.classes.scalaJSJavalib") /** scalajs-scalalib jar */ - def scalaJSScalalib: String = sys.props("dotty.tests.classes.scalaJSScalalib") + def scalaJSScalalib: String = requireNonEmptyProperty("dotty.tests.classes.scalaJSScalalib") /** scalajs-library jar */ - def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary") + def scalaJSLibrary: String = requireNonEmptyProperty("dotty.tests.classes.scalaJSLibrary") + + private def requireNonEmptyProperty(name: String): String = { + sys.props(name).ensuring( + value => value != null && value.nonEmpty, + s"Property $name is not set" + ) + } } From a639555d9fbf9633b7e0c3befce83ef2d3f3834d Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 21 Dec 2025 21:48:25 +0100 Subject: [PATCH 2/4] Setup required dependencies for scala3-staging project and sys properties --- project/Build.scala | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/project/Build.scala b/project/Build.scala index a978747d8d55..92661bf7df34 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1009,6 +1009,7 @@ object Build { // when compiling a project that depends on scala3-staging (see sbt-test/sbt-dotty/quoted-example-project), // but we always need it to be present on the JVM classpath at runtime. .dependsOn(`scala3-compiler-bootstrapped-new` % "provided; compile->runtime; test->test") + .dependsOn(`scala3-repl` % "provided; compile->runtime; test->test") .settings(publishSettings) .settings( name := "scala3-staging", @@ -1021,6 +1022,7 @@ object Build { // Add the source directories for the sbt-bridge (boostrapped) Compile / unmanagedSourceDirectories := Seq(baseDirectory.value / "src"), Test / unmanagedSourceDirectories := Seq(baseDirectory.value / "test"), + Test / unmanagedResourceDirectories := Seq(baseDirectory.value / "test-resources"), // Packaging configuration of `scala3-staging` Compile / packageBin / publishArtifact := true, Compile / packageDoc / publishArtifact := true, @@ -1056,6 +1058,21 @@ object Build { scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, + Test / javaOptions ++= { + val externalDeps = (ThisProject / Runtime / externalDependencyClasspath).value + Seq( + s"-Ddotty.tests.classes.compilerInterface=${findArtifactPath(externalDeps, "compiler-interface")}", + s"-Ddotty.tests.classes.dottyCompiler=${(`scala3-compiler-bootstrapped-new` / Compile / packageBin).value}", + s"-Ddotty.tests.classes.dottyInterfaces=${(`scala3-interfaces` / Compile / packageBin).value}", + s"-Ddotty.tests.classes.dottyRepl=${(`scala3-repl` / Compile / packageBin).value}", + s"-Ddotty.tests.classes.dottyStaging=${(ThisProject / Compile / packageBin).value}", + s"-Ddotty.tests.classes.jlineReader=${findArtifactPath(externalDeps, "jline-reader")}", + s"-Ddotty.tests.classes.jlineTerminal=${findArtifactPath(externalDeps, "jline-terminal")}", + s"-Ddotty.tests.classes.scalaAsm=${findArtifactPath(externalDeps, "scala-asm")}", + s"-Ddotty.tests.classes.scalaLibrary=${(`scala-library-bootstrapped` / Compile / packageBin).value}", + s"-Ddotty.tests.classes.tastyCore=${(`tasty-core-bootstrapped-new` / Compile / packageBin).value}", + ) + }, bspEnabled := false, ) From a81c179f27bd6df79801f224059056dc3c25f070 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 21 Dec 2025 21:48:51 +0100 Subject: [PATCH 3/4] Adjust dotc.util.ClasspathFromClassloader to scala3-repl seperation --- .../tools/dotc/util/ClasspathFromClassloader.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/util/ClasspathFromClassloader.scala b/compiler/src/dotty/tools/dotc/util/ClasspathFromClassloader.scala index 198499f2593e..df304f5d756b 100644 --- a/compiler/src/dotty/tools/dotc/util/ClasspathFromClassloader.scala +++ b/compiler/src/dotty/tools/dotc/util/ClasspathFromClassloader.scala @@ -9,6 +9,13 @@ import dotty.tools.io.AbstractFileClassLoader object ClasspathFromClassloader { + // Class name of the REPL classloader. + // We can't import AbstractFileClassLoader directly because the REPL module + // depends on compiler, not vice-versa. The class name comparison is required + // anyway because the REPL classloader class is normally loaded with a different + // classloader (see the comment below at the usage site). + private final val ReplAbstractFileClassLoaderName = "dotty.tools.repl.AbstractFileClassLoader" + /** Attempt to recreate a classpath from a classloader. * * BEWARE: with exotic enough classloaders, this may not work at all or do @@ -29,7 +36,8 @@ object ClasspathFromClassloader { classpathBuff ++= cl.getURLs.iterator.map(url => Paths.get(url.toURI).toAbsolutePath.toString) case _ => - if cl.getClass.getName == classOf[AbstractFileClassLoader].getName then + if cl.getClass.getName == ReplAbstractFileClassLoaderName || + cl.getClass.getName == classOf[AbstractFileClassLoader].getName then // HACK: We can't just collect the classpath from arbitrary parent // classloaders since the current classloader might intentionally // filter loading classes from its parent (for example From f585c5577b27c7858d9630bf1da4330c3bb3e26f Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 21 Dec 2025 21:49:53 +0100 Subject: [PATCH 4/4] Run scala3-staging tests in the CI --- .github/workflows/stdlib.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/stdlib.yaml b/.github/workflows/stdlib.yaml index ec1e4a65ff83..cfce19a5523b 100644 --- a/.github/workflows/stdlib.yaml +++ b/.github/workflows/stdlib.yaml @@ -221,6 +221,8 @@ jobs: - uses: sbt/setup-sbt@v1 - name: Compile `scala3-staging` run: ./project/scripts/sbt scala3-staging-new/compile + - name: Test `scala3-staging` + run: ./project/scripts/sbt scala3-staging-new/test scala3-tasty-inspector: runs-on: ubuntu-latest