From 557efdd882f8e7d4a1e4f8d4e807ab838e21d447 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Fri, 14 Aug 2026 11:32:47 +0200 Subject: [PATCH] Make `bin/replQ` work work with non-bootstrapped compilation --- bin/scalaQ | 20 +++++++++++ build.sbt | 1 + project/Build.scala | 85 ++++++++++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 32 deletions(-) create mode 100755 bin/scalaQ diff --git a/bin/scalaQ b/bin/scalaQ new file mode 100755 index 000000000000..7825a055eb8c --- /dev/null +++ b/bin/scalaQ @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >& /dev/null && pwd)/.." +. $ROOT/bin/commonQ + +# Runs a class compiled with bin/scalacQ on the classpath written by `sbt buildQuick` +# (compiler + freshly built stdlib). +# +# bin/scalacQ -d out MyFile.scala +# bin/scalaQ -cp out MyMain arg1 +# +# Without -cp, classes are looked up in the current directory. + +extraCp="." +if [ "$1" = "-cp" ] || [ "$1" = "-classpath" ]; then + extraCp="$2" + shift 2 +fi + +java -cp "$extraCp:$cp" "$@" diff --git a/build.sbt b/build.sbt index f34c3ddb5c5a..a143a951144f 100644 --- a/build.sbt +++ b/build.sbt @@ -9,6 +9,7 @@ val `scala3-compiler-nonbootstrapped` = Build.`scala3-compiler-nonbootstrapped` val `scala3-compiler-bootstrapped` = Build.`scala3-compiler-bootstrapped` val `scala3-repl` = Build.`scala3-repl` +val `scala3-repl-nonbootstrapped` = Build.`scala3-repl-nonbootstrapped` // The Standard Library val `scala2-library` = Build.`scala2-library` diff --git a/project/Build.scala b/project/Build.scala index c58ce08e7473..6ac7c02f19b1 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -51,7 +51,7 @@ object Build { // Used to run binaries similar to ./bin/scala script val scala = inputKey[Unit]("run compiled binary using the correct classpath, or the user supplied classpath") - val buildQuick = taskKey[Unit]("compile the compiler and REPL, write classpath to bin/.cp for use by bin/scalacQ and bin/replQ") + val buildQuick = taskKey[Unit]("compile the compiler and REPL, write classpath to bin/.cp for use by bin/scalacQ, bin/scalaQ and bin/replQ") // Settings used to configure the test language server val ideTestsCompilerVersion = taskKey[String]("Compiler version to use in IDE tests") @@ -609,6 +609,7 @@ object Build { `scala3-staging`, `scala3-tasty-inspector`, `scala3-repl`, + `scala3-repl-nonbootstrapped`, `scala2-library`, scaladoc, `scaladoc-testcases`, @@ -636,7 +637,8 @@ object Build { lazy val `scala3-nonbootstrapped` = project.in(file(".")) .aggregate(`scala3-interfaces`, `scala3-library-nonbootstrapped` , `scala-library-nonbootstrapped`, - `tasty-core-nonbootstrapped`, `scala3-directives-parser-nonbootstrapped`, `scala3-compiler-nonbootstrapped`, `scala3-sbt-bridge-nonbootstrapped`) + `tasty-core-nonbootstrapped`, `scala3-directives-parser-nonbootstrapped`, `scala3-compiler-nonbootstrapped`, + `scala3-sbt-bridge-nonbootstrapped`, `scala3-repl-nonbootstrapped`) .settings( name := "scala3-nonbootstrapped", moduleName := "scala3-nonbootstrapped", @@ -666,13 +668,11 @@ object Build { libraryProject = `scala-library-nonbootstrapped`, withCompilerDeps = withCompilerClasspath(`scala3-compiler-nonbootstrapped`) ).evaluated, - // TODO: scala3-repl depends on the bootstrapped compiler, making this slower - // than it needs to be. A non-bootstrapped REPL project would speed this up. buildQuick := { - val _ = (`scala3-repl` / Compile / compile).value - val cp = (`scala3-repl` / Compile / fullClasspath).value.map(_.data.getAbsolutePath).mkString(File.pathSeparator) + val _ = (`scala3-repl-nonbootstrapped` / Compile / compile).value + val cp = (`scala3-repl-nonbootstrapped` / Compile / fullClasspath).value.map(_.data.getAbsolutePath).mkString(File.pathSeparator) IO.write(baseDirectory.value / "bin" / ".cp", cp) - streams.value.log.info(s"Wrote classpath to bin/.cp — use bin/scalacQ and bin/replQ") + streams.value.log.info(s"Wrote classpath to bin/.cp — use bin/scalacQ, bin/scalaQ and bin/replQ") }, testCompilation := testCompilationTask( compilerProject = `scala3-compiler-nonbootstrapped`, @@ -852,7 +852,6 @@ object Build { bspEnabled := false, ) - /* Configuration of the org.scala-lang:scala3-tasty-inspector:*.**.**-bootstrapped project */ lazy val `scala3-tasty-inspector` = project.in(file("tasty-inspector")) // We want the compiler to be present in the compiler classpath when compiling this project but not // when compiling a project that depends on scala3-tasty-inspector (see sbt-test/sbt-dotty/tasty-inspector-example-project), @@ -883,52 +882,74 @@ object Build { bspEnabled := false, ) + /* Settings shared between the `scala3-repl` and `scala3-repl-nonbootstrapped` projects */ + lazy val replSettings = Def.settings( + moduleName := "scala3-repl", + versionScheme := Some("semver-spec"), + crossPaths := true, + // sbt shouldn't add the stdlib automatically, we depend on it transitively via the compiler project + autoScalaLibrary := false, + // Add the source directories of the REPL + Compile / unmanagedSourceDirectories := Seq(baseDirectory.value / "src"), + Compile / unmanagedResourceDirectories := Seq(baseDirectory.value / "resources"), + Test / unmanagedSourceDirectories := Seq(baseDirectory.value / "test"), + Test / unmanagedResourceDirectories := Seq(baseDirectory.value / "test-resources"), + // All the dependencies needed by the REPL + libraryDependencies ++= Seq( + Dependencies.jlineReader, + Dependencies.jlineTerminal, + Dependencies.jlineTerminalJni, + Dependencies.sbtJunitInterface % Test, + Dependencies.coursierInterface, // used by the REPL for dependency resolution + ), + run / fork := true, + Compile / run := { + //val classpath = s"-classpath ${(`scala-library-bootstrapped` / Compile / packageBin).value}" + // TODO: We should use the val above instead of `-usejavacp` below. SBT crashes we we have a val and we call toTask + // with it as a parameter. THIS IS NOT A LEGIT USE CASE OF THE `-usejavacp` FLAG. + (Compile / run).partialInput(" -usejavacp").evaluated + }, + ) + lazy val `scala3-repl` = project.in(file("repl")) .dependsOn(`scala3-compiler-bootstrapped` % "compile->compile;test->test", `scala3-directives-parser-bootstrapped`) .settings(publishSettings) + .settings(replSettings) .settings( name := "scala3-repl", - moduleName := "scala3-repl", version := dottyVersion, - versionScheme := Some("semver-spec"), scalaVersion := dottyNonBootstrappedVersion, - crossPaths := true, - autoScalaLibrary := false, - // Add the source directories for the sbt-bridge (bootstrapped) - Compile / unmanagedSourceDirectories := Seq(baseDirectory.value / "src"), - Compile / unmanagedResourceDirectories := Seq(baseDirectory.value / "resources"), - Test / unmanagedSourceDirectories := Seq(baseDirectory.value / "test"), - Test / unmanagedResourceDirectories := Seq(baseDirectory.value / "test-resources"), - // Packaging configuration of `scala3-staging` + // Packaging configuration of `scala3-repl` Compile / packageBin / publishArtifact := true, Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, publish / skip := false, - libraryDependencies ++= Seq( - Dependencies.jlineReader, - Dependencies.jlineTerminal, - Dependencies.jlineTerminalJni, - Dependencies.sbtJunitInterface % Test, - Dependencies.coursierInterface, // used by the REPL for dependency resolution - ), // Configure to use the non-bootstrapped compiler bootstrappedScalaInstanceSettings, // Needed for the JSR223 tests which are "run" tests Test / javaOptions += s"-Ddotty.tests.classes.scalaLibrary=${(`scala-library-bootstrapped` / Compile / packageBin).value}", - run / fork := true, excludeDependencies += "org.scala-lang" %% "scala3-library", excludeDependencies += "org.scala-lang" % "scala-library", - Compile / run := { - //val classpath = s"-classpath ${(`scala-library-bootstrapped` / Compile / packageBin).value}" - // TODO: We should use the val above instead of `-usejavacp` below. SBT crashes we we have a val and we call toTask - // with it as a parameter. THIS IS NOT A LEGIT USE CASE OF THE `-usejavacp` FLAG. - (Compile / run).partialInput(" -usejavacp").evaluated - }, bspEnabled := enableBspAllProjects, ) + lazy val `scala3-repl-nonbootstrapped` = project.in(file("repl")) + .dependsOn(`scala3-compiler-nonbootstrapped` % "compile->compile;test->test", `scala3-directives-parser-nonbootstrapped`) + .settings(replSettings) + .settings( + name := "scala3-repl-nonbootstrapped", + version := dottyNonBootstrappedVersion, + scalaVersion := referenceVersion, + Compile / mainClass := Some("dotty.tools.repl.Main"), + publish / skip := true, + target := target.value / "scala3-repl-nonbootstrapped", + fetchedScalaInstanceSettings, + Test / javaOptions += s"-Ddotty.tests.classes.scalaLibrary=${(`scala-library-nonbootstrapped` / Compile / packageBin).value}", + bspEnabled := true, + ) + // ============================================================================================== // =================================== SCALA STANDARD LIBRARY =================================== // ==============================================================================================