aboutsummaryrefslogtreecommitdiff
path: root/bridge/src/main/scala/xsbt/CompilerClassLoader.scala
diff options
context:
space:
mode:
Diffstat (limited to 'bridge/src/main/scala/xsbt/CompilerClassLoader.scala')
-rw-r--r--bridge/src/main/scala/xsbt/CompilerClassLoader.scala90
1 files changed, 0 insertions, 90 deletions
diff --git a/bridge/src/main/scala/xsbt/CompilerClassLoader.scala b/bridge/src/main/scala/xsbt/CompilerClassLoader.scala
deleted file mode 100644
index 3cb3f344f..000000000
--- a/bridge/src/main/scala/xsbt/CompilerClassLoader.scala
+++ /dev/null
@@ -1,90 +0,0 @@
-package xsbt
-
-import java.net.{URL, URLClassLoader}
-
-/** 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 {
- /** 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) = 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))
- }
-}