@@ -8,11 +8,16 @@ import sbt.librarymanagement.{
8
8
VersionNumber
9
9
}
10
10
import sbt .internal .inc .ScalaInstance
11
+ import sbt .internal .inc .classpath .ClassLoaderCache
11
12
import xsbti .compile ._
13
+ import xsbti .AppConfiguration
12
14
import java .net .URLClassLoader
13
15
import java .util .Optional
16
+ import java .util .{Enumeration , Collections }
17
+ import java .net .URL
14
18
import scala .util .Properties .isJavaAtLeast
15
19
20
+
16
21
object DottyPlugin extends AutoPlugin {
17
22
object autoImport {
18
23
val isDotty = settingKey[Boolean ](" Is this project compiled with Dotty?" )
@@ -534,15 +539,34 @@ object DottyPlugin extends AutoPlugin {
534
539
scalaLibraryJar,
535
540
dottyLibraryJar,
536
541
compilerJar,
537
- allJars
542
+ allJars,
543
+ appConfiguration.value
538
544
)
539
545
}
540
546
541
547
// Adapted from private mkScalaInstance in sbt
542
548
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
544
550
): 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
+
546
570
class DottyLoader
547
571
extends URLClassLoader (all.map(_.toURI.toURL).toArray, libraryLoader)
548
572
val fullLoader = state.classLoaderCache.cachedCustomClassloader(
@@ -553,10 +577,33 @@ object DottyPlugin extends AutoPlugin {
553
577
dottyVersion,
554
578
fullLoader,
555
579
libraryLoader,
556
- Array (dottyLibrary, scalaLibrary) ,
580
+ libraryJars ,
557
581
compiler,
558
582
all.toArray,
559
583
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
+ }
560
605
606
+ override def getResources (name : String ): Enumeration [URL ] = {
607
+ Collections .enumeration(Collections .emptyList());
561
608
}
562
609
}
0 commit comments