[2.x] fix: concurrency control around Scala 3 compiler (#7938)

**Problem**
Early initialization thread throws ConcurrentModificationException.

**Solution**
This puts wraps it in Retry.
This commit is contained in:
eugene yokota 2024-12-10 08:30:17 -05:00 committed by GitHub
parent 35eda2e40e
commit ebee3a86d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 14 additions and 11 deletions

View File

@ -10,6 +10,7 @@ package internal
package parser
import sbt.internal.util.{ LineRange, MessageOnlyException }
import sbt.internal.io.Retry
import java.io.File
import java.nio.charset.StandardCharsets
import java.util.concurrent.ConcurrentHashMap
@ -132,7 +133,9 @@ private[sbt] object SbtParser:
private[sbt] var scalacGlobalInitReporter: Option[ConsoleReporter] = None
private[sbt] val globalReporter = UniqueParserReporter()
private[sbt] val defaultGlobalForParser = ParseDriver()
// Retry since Scala 3 compiler initialization can fail due to sys.props change
private[sbt] val defaultGlobalForParser: ParseDriver =
Retry(ParseDriver())
private[sbt] final class ParseDriver extends Driver:
override protected val sourcesRequired: Boolean = false
val compileCtx0 = initCtx.fresh
@ -171,15 +174,17 @@ private[sbt] object SbtParser:
parsedTrees
end SbtParser
private class SbtParserInit {
new Thread("sbt-parser-init-thread") {
/**
* This gives JVM a head start to JIT Scala 3 compiler JAR.
* Called by sbt.internal.ClassLoaderWarmup.
*/
private class SbtParserInit:
val t = new Thread("sbt-parser-init-thread"):
setDaemon(true)
start()
override def run(): Unit = {
override def run(): Unit =
val _ = SbtParser.defaultGlobalForParser
}
}
}
t.start()
end SbtParserInit
/**
* This method solely exists to add scaladoc to members in SbtParser which
@ -222,8 +227,6 @@ private[sbt] case class SbtParser(path: VirtualFileRef, lines: Seq[String])
// parsed trees.
val (imports, settings, settingsTrees) = splitExpressions(path, lines)
import SbtParser.defaultGlobalForParser.*
private def splitExpressions(
path: VirtualFileRef,
lines: Seq[String]
@ -239,7 +242,7 @@ private[sbt] case class SbtParser(path: VirtualFileRef, lines: Seq[String])
VirtualFile(reporterId, wrapCode.getBytes(StandardCharsets.UTF_8)),
scala.io.Codec.UTF8
)
given Context = compileCtx.fresh.setSource(sourceFile)
given Context = SbtParser.defaultGlobalForParser.compileCtx.fresh.setSource(sourceFile)
val parsedTrees = parse(fileName, reporterId)
// Check No val (a,b) = foo *or* val a,b = foo as these are problematic to range positions and the WHOLE architecture.