diff --git a/build.sbt b/build.sbt index eb222f5d9ffa..ddb2d0273300 100644 --- a/build.sbt +++ b/build.sbt @@ -8,7 +8,6 @@ val `dotty-compiler-bootstrapped` = Build.`dotty-compiler-bootstrapped` val `dotty-library` = Build.`dotty-library` val `dotty-library-bootstrapped` = Build.`dotty-library-bootstrapped` val `dotty-sbt-bridge` = Build.`dotty-sbt-bridge` -val `dotty-sbt-bridge-bootstrapped` = Build.`dotty-sbt-bridge-bootstrapped` val `dotty-language-server` = Build.`dotty-language-server` val `dotty-bench` = Build.`dotty-bench` val `dotty-bench-bootstrapped` = Build.`dotty-bench-bootstrapped` diff --git a/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala b/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala new file mode 100644 index 000000000000..630df31014f7 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala @@ -0,0 +1,8 @@ +package dotty.tools +package dotc +package reporting + +/** + * This class mixes in a few standard traits, so that it is easier to extend from Java. + */ +abstract class AbstractReporter extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 4d775eaa3bc5..8eb9dda8f7b1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -13,7 +13,7 @@ import diagnostic.messages.{ Error, ConditionalWarning } class ConsoleReporter( reader: BufferedReader = Console.in, writer: PrintWriter = new PrintWriter(Console.err, true) -) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering { +) extends AbstractReporter { import MessageContainer._ diff --git a/project/Build.scala b/project/Build.scala index 67882cb4f2b7..7bbc21f1f01c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -134,7 +134,7 @@ object Build { "-language:existentials,higherKinds,implicitConversions" ), - javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"), + javacOptions in (Compile, compile) ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"), // Change this to true if you want to bootstrap using a published non-bootstrapped compiler bootstrapFromPublishedJars := false, @@ -209,10 +209,14 @@ object Build { testOptions in Test += Tests.Argument(TestFrameworks.JUnit, "-a", "-v") ) - // Settings used for projects compiled only with Scala 2 - lazy val commonScala2Settings = commonSettings ++ Seq( + // Settings used for projects compiled only with Java + lazy val commonJavaSettings = commonSettings ++ Seq( version := dottyVersion, - scalaVersion := scalacVersion + scalaVersion := scalacVersion, + // Do not append Scala versions to the generated artifacts + crossPaths := false, + // Do not depend on the Scala library + autoScalaLibrary := false ) // Settings used when compiling dotty using Scala 2 @@ -226,17 +230,9 @@ object Build { version := dottyVersion, scalaVersion := dottyNonBootstrappedVersion, - // Avoid having to run `dotty-sbt-bridge/publishLocal` before compiling a bootstrapped project - scalaCompilerBridgeSource := - (dottyOrganization %% "dotty-sbt-bridge" % dottyVersion) - .artifacts(Artifact.sources("dotty-sbt-bridge").withUrl( - // We cannot use the `packageSrc` task because a setting cannot depend - // on a task. Instead, we make `compile` below depend on the bridge `packageSrc` - Some((artifactPath in (`dotty-sbt-bridge`, Compile, packageSrc)).value.toURI.toURL))), - compile in Compile := (compile in Compile) - .dependsOn(packageSrc in (`dotty-sbt-bridge`, Compile)) - .dependsOn(compile in (`dotty-sbt-bridge`, Compile)) - .value, + scalaCompilerBridgeBinaryJar := { + Some((packageBin in (`dotty-sbt-bridge`, Compile)).value) + }, // Use the same name as the non-bootstrapped projects for the artifacts moduleName ~= { _.stripSuffix("-bootstrapped") }, @@ -359,13 +355,6 @@ object Build { // currently refers to dotty in its scripted task and "aggregate" does not take by-name // parameters: https://github.com/sbt/sbt/issues/2200 lazy val dottySbtBridgeRef = LocalProject("dotty-sbt-bridge") - // Same thing for the bootstrapped version - lazy val dottySbtBridgeBootstrappedRef = LocalProject("dotty-sbt-bridge-bootstrapped") - - def dottySbtBridgeReference(implicit mode: Mode): LocalProject = mode match { - case NonBootstrapped => dottySbtBridgeRef - case _ => dottySbtBridgeBootstrappedRef - } // The root project: // - aggregates other projects so that "compile", "test", etc are run on all projects at once. @@ -375,15 +364,7 @@ object Build { lazy val `dotty-bootstrapped` = project.asDottyRoot(Bootstrapped) lazy val `dotty-interfaces` = project.in(file("interfaces")). - settings(commonScala2Settings). // Java-only project, so this is fine - settings( - // Do not append Scala versions to the generated artifacts - crossPaths := false, - // Do not depend on the Scala library - autoScalaLibrary := false, - //Remove javac invalid options in Compile doc - javacOptions in (Compile, doc) --= Seq("-Xlint:unchecked", "-Xlint:deprecation") - ) + settings(commonJavaSettings) private lazy val dottydocClasspath = Def.task { val jars = (packageAll in `dotty-compiler`).value @@ -798,67 +779,19 @@ object Build { case Bootstrapped => `dotty-library-bootstrapped` } - // until sbt/sbt#2402 is fixed (https://github.com/sbt/sbt/issues/2402) - lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") - - def cleanSbtBridgeImpl(): Unit = { - val home = System.getProperty("user.home") - val sbtOrg = "org.scala-sbt" - val bridgePattern = s"*dotty-sbt-bridge*$dottyVersion*" - - IO.delete((file(home) / ".sbt" / "1.0" / "zinc" / sbtOrg * bridgePattern).get) - IO.delete((file(home) / ".sbt" / "boot" * "scala-*" / sbtOrg / "sbt" * "*" * bridgePattern).get) - } - - lazy val dottySbtBridgeSettings = Seq( - cleanSbtBridge := { - cleanSbtBridgeImpl() - }, - compile in Compile := { - val log = streams.value.log - val prev = (previousCompile in Compile).value.analysis.orElse(null) - val cur = (compile in Compile).value - if (prev != cur) { - log.info("Cleaning the dotty-sbt-bridge cache because it was recompiled.") - cleanSbtBridgeImpl() - } - cur - }, - description := "sbt compiler bridge for Dotty", - resolvers += Resolver.typesafeIvyRepo("releases"), // For org.scala-sbt:api - libraryDependencies ++= Seq( - Dependencies.`compiler-interface` % Provided, - (Dependencies.`zinc-api-info` % Test).withDottyCompat(scalaVersion.value) - ), - // The sources should be published with crossPaths := false since they - // need to be compiled by the project using the bridge. - crossPaths := false, - - // Don't publish any binaries for the bridge because of the above - publishArtifact in (Compile, packageBin) := false, - - fork in Test := true, - parallelExecution in Test := false - ) + lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")). + dependsOn(dottyCompiler(NonBootstrapped) % Provided). + dependsOn(dottyDoc(NonBootstrapped) % Provided). + settings(commonJavaSettings). + settings( + description := "sbt compiler bridge for Dotty", + libraryDependencies ++= Seq( + Dependencies.`compiler-interface` % Provided, + (Dependencies.`zinc-api-info` % Test).withDottyCompat(scalaVersion.value) + ), - lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")).asDottySbtBridge(NonBootstrapped) - lazy val `dotty-sbt-bridge-bootstrapped` = project.in(file("sbt-bridge")).asDottySbtBridge(Bootstrapped) - .settings( - // Tweak -Yscala2-unpickler to allow some sbt dependencies used in tests - /* - scalacOptions in Test := { - val oldOptions = (scalacOptions in Test).value - val i = oldOptions.indexOf("-Yscala2-unpickler") - assert(i != -1) - val oldValue = oldOptions(i + 1) - - val attList = (dependencyClasspath in Test).value - val sbtIo = findLib(attList, "org.scala-sbt/io") - val zincApiInfo = findLib(attList, "zinc-apiinfo") - - oldOptions.updated(i + 1, s"$sbtIo:$zincApiInfo:$oldValue") - } - */ + fork in Test := true, + parallelExecution in Test := false ) lazy val `dotty-language-server` = project.in(file("language-server")). @@ -1017,7 +950,7 @@ object Build { scriptedLaunchOpts ++= ivyPaths.value.ivyHome.map("-Dsbt.ivy.home=" + _.getAbsolutePath).toList, scriptedBufferLog := true, scripted := scripted.dependsOn( - publishLocal in `dotty-sbt-bridge-bootstrapped`, + publishLocal in `dotty-sbt-bridge`, publishLocal in `dotty-interfaces`, publishLocal in `dotty-compiler-bootstrapped`, publishLocal in `dotty-library-bootstrapped`, @@ -1285,7 +1218,7 @@ object Build { // FIXME: we do not aggregate `bin` because its tests delete jars, thus breaking other tests def asDottyRoot(implicit mode: Mode): Project = project.withCommonSettings. - aggregate(`dotty-interfaces`, dottyLibrary, dottyCompiler, dottyDoc, dottySbtBridgeReference). + aggregate(`dotty-interfaces`, dottyLibrary, dottyCompiler, dottyDoc, `dotty-sbt-bridge`). bootstrappedAggregate(`scala-library`, `scala-compiler`, `scala-reflect`, scalap, `dotty-language-server`). dependsOn(dottyCompiler). dependsOn(dottyLibrary). @@ -1309,11 +1242,6 @@ object Build { dependsOn(dottyCompiler, dottyCompiler % "test->test"). settings(dottyDocSettings) - def asDottySbtBridge(implicit mode: Mode): Project = project.withCommonSettings. - dependsOn(dottyCompiler % Provided). - dependsOn(dottyDoc % Provided). - settings(dottySbtBridgeSettings) - def asDottyBench(implicit mode: Mode): Project = project.withCommonSettings. dependsOn(dottyCompiler). settings(commonBenchmarkSettings). diff --git a/sbt-bridge/src/xsbt/CachedCompilerImpl.java b/sbt-bridge/src/xsbt/CachedCompilerImpl.java new file mode 100644 index 000000000000..caaecf8ca732 --- /dev/null +++ b/sbt-bridge/src/xsbt/CachedCompilerImpl.java @@ -0,0 +1,74 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.AnalysisCallback; +import xsbti.Logger; +import xsbti.Reporter; +import xsbti.Severity; +import xsbti.compile.*; + +import java.io.File; + +import dotty.tools.dotc.core.Contexts.Context; +import dotty.tools.dotc.core.Contexts.ContextBase; +import dotty.tools.dotc.Main; +import dotty.tools.dotc.interfaces.*; + +import java.net.URLClassLoader; + +public class CachedCompilerImpl implements CachedCompiler { + private final String[] args; + private final Output output; + private final String[] outputArgs; + + public CachedCompilerImpl(String[] args, Output output) { + super(); + this.args = args; + this.output = output; + + if (!(output instanceof SingleOutput)) + throw new IllegalArgumentException("output should be a SingleOutput, was a " + output.getClass().getName()); + + this.outputArgs = + new String[] { "-d", ((SingleOutput) output).getOutputDirectory().getAbsolutePath().toString() }; + } + + public String[] commandArguments(File[] sources) { + String[] sortedSourcesAbsolute = new String[sources.length]; + for (int i = 0; i < sources.length; i++) + sortedSourcesAbsolute[i] = sources[i].getAbsolutePath(); + java.util.Arrays.sort(sortedSourcesAbsolute); + + // Concatenate outputArgs, args and sortedSourcesAbsolute + String[] result = new String[outputArgs.length + args.length + sortedSourcesAbsolute.length]; + int j = 0; + for (int i = 0; i < outputArgs.length; i++, j++) + result[j] = outputArgs[i]; + for (int i = 0; i < args.length; i++, j++) + result[j] = args[i]; + for (int i = 0; i < sortedSourcesAbsolute.length; i++, j++) + result[j] = sortedSourcesAbsolute[i]; + + return result; + } + + synchronized public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log, Reporter delegate, CompileProgress progress) { + log.debug(() -> { + String msg = "Calling Dotty compiler with arguments (CompilerInterface):"; + for (String arg : args) + msg = msg + "\n\t" + arg; + return msg; + }); + + Context ctx = new ContextBase().initialCtx().fresh() + .setSbtCallback(callback) + .setReporter(new DelegatingReporter(delegate)); + + dotty.tools.dotc.reporting.Reporter reporter = Main.process(commandArguments(sources), ctx); + if (reporter.hasErrors()) { + throw new InterfaceCompileFailed(args, new Problem[0]); + } + } +} diff --git a/sbt-bridge/src/xsbt/CompilerClassLoader.java b/sbt-bridge/src/xsbt/CompilerClassLoader.java new file mode 100644 index 000000000000..ec0e32049f97 --- /dev/null +++ b/sbt-bridge/src/xsbt/CompilerClassLoader.java @@ -0,0 +1,122 @@ +package xsbt; + +import java.lang.reflect.Field; + +import java.net.URL; +import java.net.URLClassLoader; + +import java.util.WeakHashMap; + +/** + * A classloader to run the compiler + *
+ * A CompilerClassLoader is constructed from a list of `urls` that need to be on + * the classpath to run the compiler and the classloader used by sbt. + *
+ * To understand why a custom classloader is needed for the compiler, let us + * describe some alternatives that wouldn't work. + *
+ * Our solution is to implement a subclass of URLClassLoader with no parent, instead + * we override `loadClass` to load the `xsbti.*` interfaces from `sbtLoader`. + */ +public class CompilerClassLoader extends URLClassLoader { + private final ClassLoader sbtLoader; + + public CompilerClassLoader(URL[] urls, ClassLoader sbtLoader) { + super(urls, null); + this.sbtLoader = sbtLoader; + } + + @Override + public Class> loadClass(String className, boolean resolve) throws ClassNotFoundException { + if (className.startsWith("xsbti.")) { + // We can't use the loadClass overload with two arguments because it's + // protected, but we can do the same by hand (the classloader instance + // from which we call resolveClass does not matter). + Class> c = sbtLoader.loadClass(className); + if (resolve) + resolveClass(c); + return c; + } else { + return super.loadClass(className, resolve); + } + } + + /** + * Cache the result of `fixBridgeLoader`. + *
+ * Reusing ClassLoaders is important for warm performance since otherwise the
+ * JIT code cache for the compiler will be discarded between every call to
+ * the sbt `compile` task.
+ */
+ private static WeakHashMap
+ * Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs
+ *
+ * The classloader that we get from sbt looks like:
+ *
+ * URLClassLoader(bridgeURLs,
+ * DualLoader(scalaLoader, notXsbtiFilter, sbtLoader, xsbtiFilter))
+ *
+ * DualLoader will load the `xsbti.*` interfaces using `sbtLoader` and
+ * everything else with `scalaLoader`. Once we have loaded the dotty Main
+ * class using `scalaLoader`, subsequent classes in the dotty compiler will
+ * also be loaded by `scalaLoader` and _not_ by the DualLoader. But the sbt
+ * compiler phases are part of dotty and still need access to the `xsbti.*`
+ * interfaces in `sbtLoader`, therefore DualLoader does not work for us
+ * (this issue is not present with scalac because the sbt phases are
+ * currently defined in the compiler bridge itself, not in scalac).
+ *
+ * CompilerClassLoader is a replacement for DualLoader. Until we can fix
+ * this in sbt proper, we need to use reflection to construct our own
+ * fixed classloader:
+ *
+ * URLClassLoader(bridgeURLs,
+ * CompilerClassLoader(scalaLoader.getURLs, sbtLoader))
+ *
+ * @param bridgeLoader The classloader that sbt uses to load the compiler bridge
+ * @return A fixed classloader that works with dotty
+ */
+ synchronized public static ClassLoader fixBridgeLoader(ClassLoader bridgeLoader) {
+ return fixedLoaderCache.computeIfAbsent(bridgeLoader, k -> computeFixedLoader(k));
+ }
+
+ private static ClassLoader computeFixedLoader(ClassLoader bridgeLoader) {
+ URLClassLoader urlBridgeLoader = (URLClassLoader) bridgeLoader;
+ ClassLoader dualLoader = urlBridgeLoader.getParent();
+ Class> dualLoaderClass = dualLoader.getClass();
+
+ try {
+ // DualLoader.parentA and DualLoader.parentB are private
+ Field parentAField = dualLoaderClass.getDeclaredField("parentA");
+ parentAField.setAccessible(true);
+ Field parentBField = dualLoaderClass.getDeclaredField("parentB");
+ parentBField.setAccessible(true);
+ URLClassLoader scalaLoader = (URLClassLoader) parentAField.get(dualLoader);
+ URLClassLoader sbtLoader = (URLClassLoader) parentBField.get(dualLoader);
+
+ URL[] bridgeURLs = urlBridgeLoader.getURLs();
+ return new URLClassLoader(bridgeURLs,
+ new CompilerClassLoader(scalaLoader.getURLs(), sbtLoader));
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/sbt-bridge/src/xsbt/CompilerClassLoader.scala b/sbt-bridge/src/xsbt/CompilerClassLoader.scala
deleted file mode 100644
index 071141dcfac3..000000000000
--- a/sbt-bridge/src/xsbt/CompilerClassLoader.scala
+++ /dev/null
@@ -1,104 +0,0 @@
-package xsbt
-
-import java.net.{URL, URLClassLoader}
-
-import scala.collection.mutable
-
-/** A classloader to run the compiler
- *
- * A CompilerClassLoader is constructed from a list of `urls` that need to be on
- * the classpath to run the compiler and the classloader used by sbt.
- *
- * To understand why a custom classloader is needed for the compiler, let us
- * describe some alternatives that wouldn't work.
- * - `new URLClassLoader(urls)`:
- * The compiler contains sbt phases that callback to sbt using the `xsbti.*`
- * interfaces. If `urls` does not contain the sbt interfaces we'll get a
- * `ClassNotFoundException` in the compiler when we try to use them, if
- * `urls` does contain the interfaces we'll get a `ClassCastException` or a
- * `LinkageError` because if the same class is loaded by two different
- * classloaders, they are considered distinct by the JVM.
- * - `new URLClassLoader(urls, sbtLoader)`:
- * Because of the JVM delegation model, this means that we will only load
- * a class from `urls` if it's not present in the parent `sbtLoader`, but
- * sbt uses its own version of the scala compiler and scala library which
- * is not the one we need to run the compiler.
- *
- * Our solution is to implement a subclass of URLClassLoader with no parent, instead
- * we override `loadClass` to load the `xsbti.*` interfaces from `sbtLoader`.
- */
-class CompilerClassLoader(urls: Array[URL], sbtLoader: ClassLoader)
- extends URLClassLoader(urls, null) {
- override def loadClass(className: String, resolve: Boolean): Class[_] =
- if (className.startsWith("xsbti.")) {
- // We can't use the loadClass overload with two arguments because it's
- // protected, but we can do the same by hand (the classloader instance
- // from which we call resolveClass does not matter).
- val c = sbtLoader.loadClass(className)
- if (resolve)
- resolveClass(c)
- c
- } else {
- super.loadClass(className, resolve)
- }
-}
-
-object CompilerClassLoader {
- /** Cache the result of `fixBridgeLoader`.
- *
- * Reusing ClassLoaders is important for warm performance since otherwise the
- * JIT code cache for the compiler will be discarded between every call to
- * the sbt `compile` task.
- */
- private[this] val fixedLoaderCache = new mutable.WeakHashMap[ClassLoader, ClassLoader]
-
- /** Fix the compiler bridge ClassLoader
- *
- * Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs
- *
- * The classloader that we get from sbt looks like:
- *
- * URLClassLoader(bridgeURLs,
- * DualLoader(scalaLoader, notXsbtiFilter, sbtLoader, xsbtiFilter))
- *
- * DualLoader will load the `xsbti.*` interfaces using `sbtLoader` and
- * everything else with `scalaLoader`. Once we have loaded the dotty Main
- * class using `scalaLoader`, subsequent classes in the dotty compiler will
- * also be loaded by `scalaLoader` and _not_ by the DualLoader. But the sbt
- * compiler phases are part of dotty and still need access to the `xsbti.*`
- * interfaces in `sbtLoader`, therefore DualLoader does not work for us
- * (this issue is not present with scalac because the sbt phases are
- * currently defined in the compiler bridge itself, not in scalac).
- *
- * CompilerClassLoader is a replacement for DualLoader. Until we can fix
- * this in sbt proper, we need to use reflection to construct our own
- * fixed classloader:
- *
- * URLClassLoader(bridgeURLs,
- * CompilerClassLoader(scalaLoader.getURLs, sbtLoader))
- *
- * @param bridgeLoader The classloader that sbt uses to load the compiler bridge
- * @return A fixed classloader that works with dotty
- */
- def fixBridgeLoader(bridgeLoader: ClassLoader): ClassLoader = synchronized {
- fixedLoaderCache.getOrElseUpdate(bridgeLoader, computeFixedLoader(bridgeLoader))
- }
-
- private[this] def computeFixedLoader(bridgeLoader: ClassLoader) = bridgeLoader match {
- case bridgeLoader: URLClassLoader =>
- val dualLoader = bridgeLoader.getParent
- val dualLoaderClass = dualLoader.getClass
-
- // DualLoader#parentA and DualLoader#parentB are private
- val parentAField = dualLoaderClass.getDeclaredField("parentA")
- parentAField.setAccessible(true)
- val parentBField = dualLoaderClass.getDeclaredField("parentB")
- parentBField.setAccessible(true)
- val scalaLoader = parentAField.get(dualLoader).asInstanceOf[URLClassLoader]
- val sbtLoader = parentBField.get(dualLoader).asInstanceOf[URLClassLoader]
-
- val bridgeURLs = bridgeLoader.getURLs
- new URLClassLoader(bridgeURLs,
- new CompilerClassLoader(scalaLoader.getURLs, sbtLoader))
- }
-}
diff --git a/sbt-bridge/src/xsbt/CompilerInterface.java b/sbt-bridge/src/xsbt/CompilerInterface.java
new file mode 100644
index 000000000000..10b90adbb0e3
--- /dev/null
+++ b/sbt-bridge/src/xsbt/CompilerInterface.java
@@ -0,0 +1,43 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+package xsbt;
+
+import xsbti.AnalysisCallback;
+import xsbti.Logger;
+import xsbti.Reporter;
+import xsbti.Severity;
+import xsbti.compile.*;
+
+import java.io.File;
+
+import dotty.tools.dotc.core.Contexts.ContextBase;
+import dotty.tools.dotc.Main;
+import dotty.tools.dotc.interfaces.*;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URLClassLoader;
+
+public final class CompilerInterface {
+ public CachedCompiler newCompiler(String[] options, Output output, Logger initialLog, Reporter initialDelegate) {
+ // The classloader that sbt uses to load the compiler bridge is broken
+ // (see CompilerClassLoader#fixBridgeLoader for details). To workaround
+ // this we construct our own ClassLoader and then run the following code
+ // with it:
+ // new CachedCompilerImpl(options, output)
+
+ try {
+ ClassLoader bridgeLoader = this.getClass().getClassLoader();
+ ClassLoader fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader);
+ Class> cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl");
+ return (CachedCompiler) cciClass.getConstructors()[0].newInstance(options, output);
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log,
+ Reporter delegate, CompileProgress progress, CachedCompiler cached) {
+ cached.run(sources, changes, callback, log, delegate, progress);
+ }
+}
diff --git a/sbt-bridge/src/xsbt/CompilerInterface.scala b/sbt-bridge/src/xsbt/CompilerInterface.scala
deleted file mode 100644
index ac828b996957..000000000000
--- a/sbt-bridge/src/xsbt/CompilerInterface.scala
+++ /dev/null
@@ -1,70 +0,0 @@
-/* sbt -- Simple Build Tool
- * Copyright 2008, 2009 Mark Harrah
- */
-package xsbt
-
-import xsbti.{ AnalysisCallback, Logger, Reporter, Severity }
-import xsbti.compile._
-import java.io.File
-
-import dotty.tools.dotc.core.Contexts.ContextBase
-import dotty.tools.dotc.{ Main => DottyMain }
-import dotty.tools.dotc.interfaces._
-
-import java.net.URLClassLoader
-
-final class CompilerInterface {
- def newCompiler(options: Array[String], output: Output, initialLog: xsbti.Logger,
- initialDelegate: xsbti.Reporter): CachedCompiler = {
- // The classloader that sbt uses to load the compiler bridge is broken
- // (see CompilerClassLoader#fixBridgeLoader for details). To workaround
- // this we construct our own ClassLoader and then run the following code
- // with it:
- // new CachedCompilerImpl(options, output)
-
- val bridgeLoader = getClass.getClassLoader
- val fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader)
- val cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl")
- cciClass.getConstructors.head
- .newInstance(options, output)
- .asInstanceOf[CachedCompiler]
- }
-
- def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger,
- delegate: Reporter, progress: CompileProgress, cached: CachedCompiler): Unit =
- cached.run(sources, changes, callback, log, delegate, progress)
-}
-
-class CachedCompilerImpl(args: Array[String], output: Output) extends CachedCompiler {
- val outputArgs =
- output match {
- case multi: MultipleOutput =>
- ???
- case single: SingleOutput =>
- List("-d", single.getOutputDirectory.getAbsolutePath.toString)
- }
-
- def commandArguments(sources: Array[File]): Array[String] =
- (outputArgs ++ args.toList ++ sources.map(_.getAbsolutePath).sortWith(_ < _)).toArray[String]
-
- def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized {
- run(sources.toList, changes, callback, log, delegate, progress)
- }
- private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, compileProgress: CompileProgress): Unit = {
- log.debug(() => args.mkString("Calling Dotty compiler with arguments (CompilerInterface):\n\t", "\n\t", ""))
- val ctx = (new ContextBase).initialCtx.fresh
- .setSbtCallback(callback)
- .setReporter(new DelegatingReporter(delegate))
-
- val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader]
-
- val reporter = DottyMain.process(commandArguments(sources.toArray), ctx)
- if (reporter.hasErrors) {
- throw new InterfaceCompileFailed(args, Array())
- }
- }
-}
-
-class InterfaceCompileFailed(override val arguments: Array[String], override val problems: Array[xsbti.Problem]) extends xsbti.CompileFailed {
- override val toString = "Compilation failed"
-}
diff --git a/sbt-bridge/src/xsbt/ConsoleInterface.java b/sbt-bridge/src/xsbt/ConsoleInterface.java
new file mode 100644
index 000000000000..3467e6abc226
--- /dev/null
+++ b/sbt-bridge/src/xsbt/ConsoleInterface.java
@@ -0,0 +1,55 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+package xsbt;
+
+import java.util.ArrayList;
+
+import scala.Some;
+
+import xsbti.Logger;
+
+import dotty.tools.dotc.core.Contexts.Context;
+import dotty.tools.repl.ReplDriver;
+import dotty.tools.repl.State;
+
+public class ConsoleInterface {
+ public String[] commandArguments(String[] args, String bootClasspathString, String classpathString, Logger log) {
+ return args;
+ }
+
+ public void run(
+ String[] args,
+ String bootClasspathString,
+ String classpathString,
+ String initialCommands,
+ String cleanupCommands,
+ ClassLoader loader,
+ String[] bindNames,
+ Object[] bindValues,
+ Logger log
+ ) {
+ ArrayList