Skip to content

Commit 101ebf8

Browse files
committed
[sbt-dotty] use sbt loader as parent of scala instance loader
1 parent 928e01a commit 101ebf8

File tree

4 files changed

+54
-135
lines changed

4 files changed

+54
-135
lines changed

project/Build.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ object Build {
337337
scalaLibrary,
338338
dottyLibrary,
339339
dottyCompiler,
340-
allJars
340+
allJars,
341+
appConfiguration.value
341342
)
342343
},
343344
// sbt-dotty defines `scalaInstance in doc` so we need to override it manually

sbt-bridge/src/xsbt/CompilerClassLoader.java

-122
This file was deleted.

sbt-bridge/src/xsbt/CompilerInterface.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,9 @@
2020

2121
public final class CompilerInterface {
2222
public CachedCompiler newCompiler(String[] options, Output output, Logger initialLog, Reporter initialDelegate) {
23-
// The classloader that sbt uses to load the compiler bridge is broken
24-
// (see CompilerClassLoader#fixBridgeLoader for details). To workaround
25-
// this we construct our own ClassLoader and then run the following code
26-
// with it:
27-
// new CachedCompilerImpl(options, output)
28-
2923
try {
3024
ClassLoader bridgeLoader = this.getClass().getClassLoader();
31-
ClassLoader fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader);
32-
Class<?> cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl");
25+
Class<?> cciClass = bridgeLoader.loadClass("xsbt.CachedCompilerImpl");
3326
return (CachedCompiler) cciClass.getConstructors()[0].newInstance(options, output);
3427
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
3528
throw new RuntimeException(e);

sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala

+51-4
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ import sbt.librarymanagement.{
88
VersionNumber
99
}
1010
import sbt.internal.inc.ScalaInstance
11+
import sbt.internal.inc.classpath.ClassLoaderCache
1112
import xsbti.compile._
13+
import xsbti.AppConfiguration
1214
import java.net.URLClassLoader
1315
import java.util.Optional
16+
import java.util.{Enumeration, Collections}
17+
import java.net.URL
1418
import scala.util.Properties.isJavaAtLeast
1519

20+
1621
object DottyPlugin extends AutoPlugin {
1722
object autoImport {
1823
val isDotty = settingKey[Boolean]("Is this project compiled with Dotty?")
@@ -534,15 +539,34 @@ object DottyPlugin extends AutoPlugin {
534539
scalaLibraryJar,
535540
dottyLibraryJar,
536541
compilerJar,
537-
allJars
542+
allJars,
543+
appConfiguration.value
538544
)
539545
}
540546

541547
// Adapted from private mkScalaInstance in sbt
542548
def makeScalaInstance(
543-
state: State, dottyVersion: String, scalaLibrary: File, dottyLibrary: File, compiler: File, all: Seq[File]
549+
state: State, dottyVersion: String, scalaLibrary: File, dottyLibrary: File, compiler: File, all: Seq[File], appConfiguration: AppConfiguration
544550
): ScalaInstance = {
545-
val libraryLoader = state.classLoaderCache(List(dottyLibrary, scalaLibrary))
551+
/**
552+
* The compiler bridge must load the xsbti classes from the sbt
553+
* classloader, and similarly the Scala repl must load the sbt provided
554+
* jline terminal. To do so we add the `appConfiguration` loader in
555+
* the parent hierarchy of the scala 3 instance loader.
556+
*
557+
* The [[FilteringClassLoader]] ensures that the JNA, JDK and xsbti
558+
* classes only are loaded from the sbt loader. That is necessary because
559+
* the sbt class loader contains the Scala 2.12 library and compiler
560+
* bridge.
561+
*/
562+
val topLoader = new FilteringClassLoader(appConfiguration.provider.loader)
563+
564+
val libraryJars = Array(dottyLibrary, scalaLibrary)
565+
val libraryLoader = state.classLoaderCache.cachedCustomClassloader(
566+
libraryJars.toList,
567+
() => new URLClassLoader(libraryJars.map(_.toURI.toURL), topLoader)
568+
)
569+
546570
class DottyLoader
547571
extends URLClassLoader(all.map(_.toURI.toURL).toArray, libraryLoader)
548572
val fullLoader = state.classLoaderCache.cachedCustomClassloader(
@@ -553,10 +577,33 @@ object DottyPlugin extends AutoPlugin {
553577
dottyVersion,
554578
fullLoader,
555579
libraryLoader,
556-
Array(dottyLibrary, scalaLibrary),
580+
libraryJars,
557581
compiler,
558582
all.toArray,
559583
None)
584+
}
585+
}
586+
587+
private class FilteringClassLoader(parent: ClassLoader) extends ClassLoader(parent) {
588+
private val prefixes = List(
589+
"xsbti.",
590+
"org.jline.",
591+
"java.",
592+
"sun.",
593+
"jdk.internal.reflect.",
594+
"javax."
595+
)
596+
597+
override def loadClass(name: String, resolve: Boolean): Class[_] = {
598+
if (prefixes.exists(name.startsWith(_))) super.loadClass(name, resolve)
599+
else null
600+
}
601+
602+
override def getResource(name: String): URL = {
603+
null
604+
}
560605

606+
override def getResources(name: String): Enumeration[URL] = {
607+
Collections.enumeration(Collections.emptyList());
561608
}
562609
}

0 commit comments

Comments
 (0)