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 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 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" + ) + } } 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, )