mirror of https://github.com/sbt/sbt.git
Avoid CCE when scalac internally uses compileLate. Fixes #2452
For example, when the `--sourcepath` option is provided and the refchecks phase compiles an annotation found on a referenced symbol from the sourcepath. `compileLate` assumes that all non-sentinel compiler phases can be down cast to `GlobalPhase`. This commit changes the two phases in SBT to extend this instead of `Phase`. This has the knock on benefit of simplifying the phases by letting the `GlobalPhase.run` iterator over the list of compilation units and feed them to us one by one. I checked that the test case failed before making each change.
This commit is contained in:
parent
d3962a01ff
commit
7d4890b68a
|
|
@ -22,16 +22,19 @@ final class API(val global: CallbackGlobal) extends Compat {
|
|||
@inline def debug(msg: => String) = if (settings.verbose.value) inform(msg)
|
||||
|
||||
def newPhase(prev: Phase) = new ApiPhase(prev)
|
||||
class ApiPhase(prev: Phase) extends Phase(prev) {
|
||||
class ApiPhase(prev: Phase) extends GlobalPhase(prev) {
|
||||
override def description = "Extracts the public API from source files."
|
||||
def name = API.name
|
||||
def run: Unit =
|
||||
override def run(): Unit =
|
||||
{
|
||||
val start = System.currentTimeMillis
|
||||
currentRun.units.foreach(processUnit)
|
||||
super.run
|
||||
val stop = System.currentTimeMillis
|
||||
debug("API phase took : " + ((stop - start) / 1000.0) + " s")
|
||||
}
|
||||
|
||||
def apply(unit: global.CompilationUnit): Unit = processUnit(unit)
|
||||
|
||||
def processUnit(unit: CompilationUnit) = if (!unit.isJava) processScalaUnit(unit)
|
||||
def processScalaUnit(unit: CompilationUnit): Unit = {
|
||||
val sourceFile = unit.source.file.file
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ final class Analyzer(val global: CallbackGlobal) extends LocateClassFile {
|
|||
import global._
|
||||
|
||||
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
|
||||
private class AnalyzerPhase(prev: Phase) extends Phase(prev) {
|
||||
private class AnalyzerPhase(prev: Phase) extends GlobalPhase(prev) {
|
||||
override def description = "Finds concrete instances of provided superclasses, and application entry points."
|
||||
def name = Analyzer.name
|
||||
def run {
|
||||
for (unit <- currentRun.units if !unit.isJava) {
|
||||
def apply(unit: CompilationUnit) {
|
||||
if (!unit.isJava) {
|
||||
val sourceFile = unit.source.file.file
|
||||
// build list of generated classes
|
||||
for (iclass <- unit.icode) {
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
|
|||
import global._
|
||||
|
||||
def newPhase(prev: Phase): Phase = new DependencyPhase(prev)
|
||||
private class DependencyPhase(prev: Phase) extends Phase(prev) {
|
||||
private class DependencyPhase(prev: Phase) extends GlobalPhase(prev) {
|
||||
override def description = "Extracts dependency information"
|
||||
def name = Dependency.name
|
||||
def run: Unit = {
|
||||
for (unit <- currentRun.units if !unit.isJava) {
|
||||
def apply(unit: CompilationUnit): Unit = {
|
||||
if (!unit.isJava) {
|
||||
// build dependencies structure
|
||||
val sourceFile = unit.source.file.file
|
||||
if (global.callback.nameHashing) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
scalaVersion := "2.11.7"
|
||||
|
||||
scalacOptions in Compile ++= "-sourcepath" :: (baseDirectory.value / "srcpath").toString :: Nil
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
object Test {
|
||||
// When the refchecks compiler phase checks if Tuple2 has the
|
||||
// @deprecated annotation, it forces the info for the
|
||||
// `@deprecatedInheritance` annotation (the only annotation on
|
||||
// class Tuple2.
|
||||
//
|
||||
// Because we are compiling with `-sourcpath` that contains a
|
||||
// source file for `deprecatedInheritance`, this triggers a
|
||||
// `compileLate` of that file (which basically runs all previous
|
||||
// compiler phases on that file.)
|
||||
//
|
||||
// `compileLate` assumes that all of the phases are subclasses
|
||||
// of `GlobalPhase`, rather than just `Phase`. This triggers a
|
||||
// `ClassCastException` when it encounters SBT's custom
|
||||
// API phase.
|
||||
new Tuple2("", "")
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package scala
|
||||
|
||||
private[scala] // for now, this needs to be generalized to communicate other modifier deltas
|
||||
class deprecatedInheritance(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation
|
||||
|
|
@ -0,0 +1 @@
|
|||
> compile
|
||||
Loading…
Reference in New Issue