Debug issues with implicit usage for CompileSetup.

* Force CompileSetup Equiv typeclass to use Equiv relations defined locally.
* Add toString methods on many of the incremental compiler datatypes.
* Remove remaining binary compatibility issues in Defaults.scala.
This commit is contained in:
Josh Suereth 2014-11-04 15:07:52 -05:00
parent 045ac1d984
commit 067479f59e
7 changed files with 50 additions and 12 deletions

View File

@ -10,24 +10,41 @@ import java.io.File
// We cannot require an implicit parameter Equiv[Seq[String]] to construct Equiv[CompileSetup]
// because complexity(Equiv[Seq[String]]) > complexity(Equiv[CompileSetup])
// (6 > 4)
final class CompileOptions(val options: Seq[String], val javacOptions: Seq[String])
final class CompileOptions(val options: Seq[String], val javacOptions: Seq[String]) {
override def toString = s"CompileOptions(scalac=$options, javac=$javacOptions)"
}
final class CompileSetup(val output: APIOutput, val options: CompileOptions, val compilerVersion: String,
val order: CompileOrder, val nameHashing: Boolean) {
@deprecated("Use the other overloaded variant of the constructor that takes `nameHashing` value, instead.", "0.13.2")
def this(output: APIOutput, options: CompileOptions, compilerVersion: String, order: CompileOrder) = {
this(output, options, compilerVersion, order, false)
}
override def toString = s"""CompileSetup(
| options = $options
| compilerVersion = $compilerVersion
| order = $order
| nameHashing = $nameHashing
| output = $output
|)""".stripMargin
}
object CompileSetup {
// Equiv[CompileOrder.Value] dominates Equiv[CompileSetup]
implicit def equivCompileSetup(implicit equivOutput: Equiv[APIOutput], equivOpts: Equiv[CompileOptions], equivComp: Equiv[String] /*, equivOrder: Equiv[CompileOrder]*/ ): Equiv[CompileSetup] = new Equiv[CompileSetup] {
def equiv(a: CompileSetup, b: CompileSetup) =
equivOutput.equiv(a.output, b.output) &&
equivOpts.equiv(a.options, b.options) &&
equivComp.equiv(a.compilerVersion, b.compilerVersion) &&
a.order == b.order && // equivOrder.equiv(a.order, b.order)
a.nameHashing == b.nameHashing
def equiv(a: CompileSetup, b: CompileSetup) = {
// For some reason, an Equiv[Nothing] or some such is getting injected into here now, and borking all our results.
// We hardcode these to use the Equiv defined in this class.
def sameOutput = CompileSetup.equivOutput.equiv(a.output, b.output)
def sameOptions = CompileSetup.equivOpts.equiv(a.options, b.options)
def sameCompiler = equivComp.equiv(a.compilerVersion, b.compilerVersion)
def sameOrder = a.order == b.order
def sameNameHasher = a.nameHashing == b.nameHashing
sameOutput &&
sameOptions &&
sameCompiler &&
sameOrder && // equivOrder.equiv(a.order, b.order)
sameNameHasher
}
}
implicit val equivFile: Equiv[File] = new Equiv[File] {
def equiv(a: File, b: File) = a.getAbsoluteFile == b.getAbsoluteFile
@ -41,14 +58,17 @@ object CompileSetup {
case (a, b) =>
equivFile.equiv(a.sourceDirectory, b.sourceDirectory) && equivFile.equiv(a.outputDirectory, b.outputDirectory)
})
case (s1: SingleOutput, s2: SingleOutput) => equivFile.equiv(s1.outputDirectory, s2.outputDirectory)
case _ => false
case (s1: SingleOutput, s2: SingleOutput) =>
equivFile.equiv(s1.outputDirectory, s2.outputDirectory)
case _ =>
false
}
}
implicit val equivOpts: Equiv[CompileOptions] = new Equiv[CompileOptions] {
def equiv(a: CompileOptions, b: CompileOptions) =
def equiv(a: CompileOptions, b: CompileOptions) = {
(a.options sameElements b.options) &&
(a.javacOptions sameElements b.javacOptions)
}
}
implicit val equivCompilerVersion: Equiv[String] = new Equiv[String] {
def equiv(a: String, b: String) = a == b

View File

@ -17,6 +17,9 @@ import xsbti.compile._
/**
* This is a compiler that mixes the `sbt.compiler.AnalyzingCompiler` for Scala incremental compilation
* with a `xsbti.JavaCompiler`, allowing cross-compilation of mixed Java/Scala projects with analysis output.
*
*
* NOTE: this is actually the core logic of the incremental compiler for sbt.
*/
object MixedAnalyzingCompiler {
/** The result of running the compilation. */
@ -90,6 +93,7 @@ object MixedAnalyzingCompiler {
cache: GlobalsCache,
incrementalCompilerOptions: IncOptions)(implicit log: Logger): (Analysis, Boolean) =
{
import CompileSetup._
if (skip)
(previousAnalysis, false)
else {

View File

@ -149,6 +149,7 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
val args = Array.empty[String]
object output extends SingleOutput {
def outputDirectory: File = outputDir
override def toString = s"SingleOutput($outputDirectory)"
}
val weakLog = new WeakLog(ConsoleLogger(), ConsoleReporter)
val cachedCompiler = new CachedCompiler0(args, output, weakLog, false)

View File

@ -76,7 +76,13 @@ object AnalysisFormats {
implicit val multipleOutputFormat: Format[MultipleOutput] =
wrap[MultipleOutput, Array[OutputGroup]](
(_.outputGroups),
{ groups => new MultipleOutput { def outputGroups = groups } }
{
groups =>
new MultipleOutput {
def outputGroups = groups
override def toString = s"MultipleOutput($outputGroups)"
}
}
)
implicit val singleOutputFormat: Format[SingleOutput] =
wrap[SingleOutput, File](

View File

@ -308,8 +308,10 @@ object TextAnalysisFormat {
case (src: File, out: File) => new MultipleOutput.OutputGroup {
val sourceDirectory = src
val outputDirectory = out
override def toString = s"OutputGroup($src -> $out)"
}
}
override def toString = s"MultipleOuput($outputGroups)"
}
case str: String => throw new ReadException("Unrecognized output mode: " + str)
}

View File

@ -8,9 +8,11 @@ package compiler
import xsbti.compile.{ Output, SingleOutput, MultipleOutput }
import java.io.File
/** Constructor for the `Output` ADT for incremental compiler. Can either take groups (src -> out) or a single output. */
object CompileOutput {
def apply(dir: File): Output = new SingleOutput {
def outputDirectory = dir
override def toString = s"SingleOutput($outputDirectory)"
}
def apply(groups: (File, File)*): Output = new MultipleOutput {
@ -18,7 +20,9 @@ object CompileOutput {
case (src, out) => new MultipleOutput.OutputGroup {
def sourceDirectory = src
def outputDirectory = out
override def toString = s"OutputGroup($src -> $out)"
}
}
override def toString = s"MultiOutput($outputGroups)"
}
}

View File

@ -783,7 +783,8 @@ object Defaults extends BuildCommon {
def compileTask: Initialize[Task[inc.Analysis]] = Def.task { saveAnalysis.value }
def compileIncrementalTask = Def.task {
compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value, (readAnalysis in compile).value, (compilerReporter in compile).value)
// TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too?
compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value, readAnalysis.value, (compilerReporter in compile).value)
}
private[this] def compileIncrementalTaskImpl(s: TaskStreams, ci: Compiler.Inputs, previous: Compiler.PreviousAnalysis, reporter: Option[xsbti.Reporter]): Compiler.CompileResult =
{