@@ -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?" )
@@ -521,15 +526,34 @@ object DottyPlugin extends AutoPlugin {
521
526
scalaLibraryJar,
522
527
dottyLibraryJar,
523
528
compilerJar,
524
- allJars
529
+ allJars,
530
+ appConfiguration.value
525
531
)
526
532
}
527
533
528
534
// Adapted from private mkScalaInstance in sbt
529
535
def makeScalaInstance (
530
- state : State , dottyVersion : String , scalaLibrary : File , dottyLibrary : File , compiler : File , all : Seq [File ]
536
+ state : State , dottyVersion : String , scalaLibrary : File , dottyLibrary : File , compiler : File , all : Seq [File ], appConfiguration : AppConfiguration
531
537
): ScalaInstance = {
532
- val libraryLoader = state.classLoaderCache(List (dottyLibrary, scalaLibrary))
538
+ /**
539
+ * The compiler bridge must load the xsbti classes from the sbt
540
+ * classloader, and similarly the Scala repl must load the sbt provided
541
+ * jline terminal. To do so we add the `appConfiguration` loader in
542
+ * the parent hierarchy of the scala 3 instance loader.
543
+ *
544
+ * The [[TopClassLoader ]] ensures that the xsbti and jline classes
545
+ * only are loaded from the sbt loader. That is necessary because
546
+ * the sbt class loader contains the Scala 2.12 library and compiler
547
+ * bridge.
548
+ */
549
+ val topLoader = new TopClassLoader (appConfiguration.provider.loader)
550
+
551
+ val libraryJars = Array (dottyLibrary, scalaLibrary)
552
+ val libraryLoader = state.classLoaderCache.cachedCustomClassloader(
553
+ libraryJars.toList,
554
+ () => new URLClassLoader (libraryJars.map(_.toURI.toURL), topLoader)
555
+ )
556
+
533
557
class DottyLoader
534
558
extends URLClassLoader (all.map(_.toURI.toURL).toArray, libraryLoader)
535
559
val fullLoader = state.classLoaderCache.cachedCustomClassloader(
@@ -540,10 +564,25 @@ object DottyPlugin extends AutoPlugin {
540
564
dottyVersion,
541
565
fullLoader,
542
566
libraryLoader,
543
- Array (dottyLibrary, scalaLibrary) ,
567
+ libraryJars ,
544
568
compiler,
545
569
all.toArray,
546
570
None )
571
+ }
572
+ }
573
+
574
+ private class TopClassLoader (sbtLoader : ClassLoader ) extends ClassLoader (null ) {
575
+ private val sharedPrefixes = List (
576
+ " xsbti." ,
577
+ " org.jline."
578
+ )
547
579
580
+ override protected def loadClass (name : String , resolve : Boolean ): Class [_] = {
581
+ if (sharedPrefixes.exists(name.startsWith(_))) {
582
+ val c = sbtLoader.loadClass(name)
583
+ if (resolve) resolveClass(c)
584
+ c
585
+ }
586
+ else super .loadClass(name, resolve)
548
587
}
549
588
}
0 commit comments