@@ -8,6 +8,7 @@ import java.util.concurrent.Executor
8
8
9
9
import scala .collection .mutable
10
10
import scala .concurrent .Promise
11
+ import scala .util .control .NonFatal
11
12
12
13
import bloop .io .AbsolutePath
13
14
import bloop .io .ParallelOps
@@ -23,6 +24,7 @@ import bloop.task.Task
23
24
import bloop .tracing .BraveTracer
24
25
import bloop .util .AnalysisUtils
25
26
import bloop .util .CacheHashCode
27
+ import bloop .util .JavaRuntime
26
28
import bloop .util .UUIDUtil
27
29
28
30
import monix .execution .Scheduler
@@ -278,39 +280,14 @@ object Compiler {
278
280
)
279
281
}
280
282
281
- var isFatalWarningsEnabled : Boolean = false
283
+ val isFatalWarningsEnabled : Boolean =
284
+ compileInputs.scalacOptions.exists(_ == " -Xfatal-warnings" )
282
285
def getInputs (compilers : Compilers ): Inputs = {
283
- val options = getCompilationOptions(compileInputs)
286
+ val options = getCompilationOptions(compileInputs, logger, newClassesDir )
284
287
val setup = getSetup(compileInputs)
285
288
Inputs .of(compilers, options, setup, compileInputs.previousResult)
286
289
}
287
290
288
- def getCompilationOptions (inputs : CompileInputs ): CompileOptions = {
289
- // Sources are all files
290
- val sources = inputs.sources.map(path => converter.toVirtualFile(path.underlying))
291
- val classpath = inputs.classpath.map(path => converter.toVirtualFile(path.underlying))
292
- val optionsWithoutFatalWarnings = inputs.scalacOptions.flatMap { option =>
293
- if (option != " -Xfatal-warnings" ) List (option)
294
- else {
295
- if (! isFatalWarningsEnabled) isFatalWarningsEnabled = true
296
- Nil
297
- }
298
- }
299
-
300
- // Enable fatal warnings in the reporter if they are enabled in the build
301
- if (isFatalWarningsEnabled)
302
- inputs.reporter.enableFatalWarnings()
303
-
304
- CompileOptions
305
- .create()
306
- .withClassesDirectory(newClassesDir)
307
- .withSources(sources)
308
- .withClasspath(classpath)
309
- .withScalacOptions(optionsWithoutFatalWarnings)
310
- .withJavacOptions(inputs.javacOptions)
311
- .withOrder(inputs.compileOrder)
312
- }
313
-
314
291
def getSetup (compileInputs : CompileInputs ): Setup = {
315
292
val skip = false
316
293
val empty = Array .empty[T2 [String , String ]]
@@ -627,6 +604,85 @@ object Compiler {
627
604
}
628
605
}
629
606
607
+ /**
608
+ * Bloop runs Scala compilation in the same process as the main server,
609
+ * so the compilation process will use the same JDK that Bloop is using.
610
+ * That's why we must ensure that produce class files will be compliant with expected JDK version
611
+ * and compilation errors will show up when using wrong JDK API.
612
+ */
613
+ private def adjustScalacReleaseOptions (
614
+ scalacOptions : Array [String ],
615
+ javacBin : Option [AbsolutePath ],
616
+ logger : Logger
617
+ ): Array [String ] = {
618
+ def existsReleaseSetting = scalacOptions.exists(opt =>
619
+ opt.startsWith(" -release" ) ||
620
+ opt.startsWith(" --release" ) ||
621
+ opt.startsWith(" -java-output-version" )
622
+ )
623
+ def sameHome = javacBin match {
624
+ case Some (bin) => bin.getParent.getParent == JavaRuntime .home
625
+ case None => false
626
+ }
627
+
628
+ javacBin.flatMap(binary =>
629
+ // <JAVA_HOME>/bin/java
630
+ JavaRuntime .getJavaVersionFromJavaHome(binary.getParent.getParent)
631
+ ) match {
632
+ case None => scalacOptions
633
+ case Some (_) if existsReleaseSetting || sameHome => scalacOptions
634
+ case Some (version) =>
635
+ try {
636
+ val numVer = if (version.startsWith(" 1.8" )) 8 else version.takeWhile(_.isDigit).toInt
637
+ val bloopNumVer = JavaRuntime .version.takeWhile(_.isDigit).toInt
638
+ if (bloopNumVer > numVer) {
639
+ scalacOptions ++ List (" -release" , numVer.toString())
640
+ } else {
641
+ logger.warn(
642
+ s " Bloop is runing with ${JavaRuntime .version} but your code requires $version to compile, " +
643
+ " this might cause some compilation issues when using JDK API unsupported by the Bloop's current JVM version"
644
+ )
645
+ scalacOptions
646
+ }
647
+ } catch {
648
+ case NonFatal (_) =>
649
+ scalacOptions
650
+ }
651
+ }
652
+ }
653
+
654
+ private def getCompilationOptions (
655
+ inputs : CompileInputs ,
656
+ logger : Logger ,
657
+ newClassesDir : Path
658
+ ): CompileOptions = {
659
+ // Sources are all files
660
+ val sources = inputs.sources.map(path => converter.toVirtualFile(path.underlying))
661
+ val classpath = inputs.classpath.map(path => converter.toVirtualFile(path.underlying))
662
+
663
+ val scalacOptions = adjustScalacReleaseOptions(
664
+ scalacOptions = inputs.scalacOptions,
665
+ javacBin = inputs.javacBin,
666
+ logger = logger
667
+ )
668
+
669
+ val optionsWithoutFatalWarnings = scalacOptions.filter(_ != " -Xfatal-warnings" )
670
+ val areFatalWarningsEnabled = scalacOptions.length != optionsWithoutFatalWarnings.length
671
+
672
+ // Enable fatal warnings in the reporter if they are enabled in the build
673
+ if (areFatalWarningsEnabled)
674
+ inputs.reporter.enableFatalWarnings()
675
+
676
+ CompileOptions
677
+ .create()
678
+ .withClassesDirectory(newClassesDir)
679
+ .withSources(sources)
680
+ .withClasspath(classpath)
681
+ .withScalacOptions(optionsWithoutFatalWarnings)
682
+ .withJavacOptions(inputs.javacOptions)
683
+ .withOrder(inputs.compileOrder)
684
+ }
685
+
630
686
def toBackgroundTasks (
631
687
tasks : List [(AbsolutePath , Reporter , BraveTracer ) => Task [Unit ]]
632
688
): CompileBackgroundTasks = {
0 commit comments