diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-06-28 23:10:12 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-06-28 23:17:19 +1000 |
commit | b17a291c2edf28aca1713aa4a30d8bba3886bc8d (patch) | |
tree | bc76e4b01f8d2dc478ab57e9c79acbb44c1719cb | |
parent | 950bb26cdcc3913c1524faaf283b6090b6d83e67 (diff) | |
download | scala-b17a291c2edf28aca1713aa4a30d8bba3886bc8d.tar.gz scala-b17a291c2edf28aca1713aa4a30d8bba3886bc8d.tar.bz2 scala-b17a291c2edf28aca1713aa4a30d8bba3886bc8d.zip |
GenBCode: fix incrementatal compilation by mimicing GenASM
The incremental compiler in SBT uses an implementation detail
of the compiler backend to enumerate the classes that are actually
written to disk.
This commit mimics this in GenBCode by populating `Run#icode` with
an `IClass` for each `ClassDef` processed.
We should revisit this by creating a dedicated API for this purpose
and migrating SBT to use that. We should also revisit this code
as we implement closure elimination in the GenBCode; this commit
assumes that all `ClassDef`s that enter the backend will generate
classfile products.
The enclosed test is extracted from the incrementatl compiler.
I've also manually integration tested this with SBT:
https://gist.github.com/retronym/fabf6f92787ea9c1ce67
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | 5 | ||||
-rw-r--r-- | test/files/run/sbt-icode-interface.scala | 42 |
2 files changed, 47 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 455117d837..af962c4ce0 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -167,6 +167,11 @@ abstract class GenBCode extends BCodeSyncAndTry { ) } + // shim for SBT, see https://github.com/sbt/sbt/issues/2076 + // TODO put this closer to classfile writing once we have closure elimination + // TODO create a nicer public API to find out the correspondence between sourcefile and ultimate classfiles + currentUnit.icode += new icodes.IClass(cd.symbol) + // -------------- mirror class, if needed -------------- val mirrorC = if (isTopLevelModuleClass(claszSymbol)) { diff --git a/test/files/run/sbt-icode-interface.scala b/test/files/run/sbt-icode-interface.scala new file mode 100644 index 0000000000..84d38cc65a --- /dev/null +++ b/test/files/run/sbt-icode-interface.scala @@ -0,0 +1,42 @@ +import scala.tools.partest._ +import scala.tools.nsc._ + +object Test extends DirectTest { + + def code = """ + class C { class D } + object O + """.trim + + def show() { + for (b <- List("GenASM", "GenBCode")) { + val global = newCompiler("-usejavacp", s"-Ybackend:$b") + import global._ + val r = new Run + r.compileSources(newSourceFile(code) :: Nil) + + val results = collection.mutable.Buffer[(Boolean, String)]() + + // Nailing down defacto compiler API from SBT's usage + // https://github.com/sbt/sbt/blob/adb41611cf73260938274915d8462d924df200c8/compile/interface/src/main/scala/xsbt/Analyzer.scala#L29-L41 + def isTopLevelModule(sym: Symbol) = sym.isTopLevel && sym.isModule + for (unit <- currentRun.units if !unit.isJava) { + val sourceFile = unit.source.file.file + for (iclass <- unit.icode) { + val sym = iclass.symbol + def addGenerated(separatorRequired: Boolean) { + results += (separatorRequired -> sym.fullName) + } + if (sym.isModuleClass && !sym.isImplClass) { + if (isTopLevelModule(sym) && sym.companionClass == NoSymbol) + addGenerated(false) + addGenerated(true) + } else + addGenerated(false) + } + } + val expected = List((false, "C"), (true, "O"), (false, "C$D")) + assert(results.toList == expected, b + ": " + results.toList) + } + } +} |