From 47749222941c082ebd64f874fe26e35ff7ccc13e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 24 Nov 2017 14:19:52 +0100 Subject: [PATCH] Fix #3549: Load .tasty from jar if necessary --- .../dotc/core/classfile/ClassfileParser.scala | 30 +++++++++++++++---- compiler/src/dotty/tools/io/JarArchive.scala | 9 ++++-- project/scripts/sbtTests | 13 ++++++-- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index e13311ddeb4d..2ed416ae59d8 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -8,12 +8,13 @@ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotati import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException } +import java.nio import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } import scala.annotation.switch import typer.Checking.checkNonCyclic -import io.{AbstractFile, PlainFile} +import io.{AbstractFile, PlainFile, Path, ZipArchive, JarArchive} import scala.util.control.NonFatal object ClassfileParser { @@ -781,11 +782,28 @@ class ClassfileParser( if (scan(tpnme.TASTYATTR)) { val attrLen = in.nextInt - if (attrLen == 0) { - // A tasty attribute implies the existence of the .tasty file - val file = new PlainFile(io.File(classfile.jpath).changeExtension("tasty")) - if (file.exists) return unpickleTASTY(new AbstractFileReader(file).nextBytes(file.sizeOption.get)) - else ctx.error("Could not find " + file) + if (attrLen == 0) { // A tasty attribute implies the existence of the .tasty file + def readTastyForClass(jpath: nio.file.Path): Array[Byte] = { + val plainFile = new PlainFile(io.File(jpath).changeExtension("tasty")) + if (plainFile.exists) plainFile.toByteArray + else { + ctx.error("Could not find " + plainFile) + Array.empty + } + } + val tastyBytes = classfile.underlyingSource match { // TODO: simplify when #3552 is fixed + case None => + ctx.error("Could not load TASTY from .tasty for virtual file " + classfile) + Array.empty[Byte] + case Some(jar: ZipArchive) => // We are in a jar + val jarFile = JarArchive.open(io.File(jar.jpath)) + try readTastyForClass(jarFile.jpath.resolve(classfile.path)) + finally jarFile.close() + case _ => + readTastyForClass(classfile.jpath) + } + if (tastyBytes.nonEmpty) + return unpickleTASTY(tastyBytes) } else return unpickleTASTY(in.nextBytes(attrLen)) } diff --git a/compiler/src/dotty/tools/io/JarArchive.scala b/compiler/src/dotty/tools/io/JarArchive.scala index ba9818d1b689..0960160d52b7 100644 --- a/compiler/src/dotty/tools/io/JarArchive.scala +++ b/compiler/src/dotty/tools/io/JarArchive.scala @@ -16,12 +16,17 @@ object JarArchive { /** Create a new jar file. Overwrite if file already exists */ def create(path: Path): JarArchive = { require(path.extension == "jar") - path.delete() + open(path, create = true) + } + + /** Create a jar file. */ + def open(path: Path, create: Boolean = false): JarArchive = { + require(path.extension == "jar") // creating a new zip file system by using the JAR URL syntax: // https://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html - val env = Map("create" -> "true").asJava + val env = Map("create" -> create.toString).asJava val uri = java.net.URI.create("jar:file:" + path.toAbsolute.path) val fs = FileSystems.newFileSystem(uri, env) diff --git a/project/scripts/sbtTests b/project/scripts/sbtTests index 08fc8bc4ec0d..7d7e68ee77d9 100755 --- a/project/scripts/sbtTests +++ b/project/scripts/sbtTests @@ -30,7 +30,7 @@ fi # check that `sbt dotc -decompile` runs echo "testing sbt dotc -decompile" -./project/scripts/sbt ";dotc -decompile -code -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out +./project/scripts/sbt ";dotc -decompile -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out cat sbtdotc3.out if grep -e "def main(args: Array\[String\]): Unit =" sbtdotc3.out; then echo "output ok" @@ -39,7 +39,6 @@ else exit -1 fi echo "testing sbt dotr with no -classpath" - ./project/scripts/sbt ";dotc tests/pos/sbtDotrTest.scala; dotr dotrtest.Test" > sbtdotr3.out cat sbtdotr3.out if grep -e "dotr test ok" sbtdotr3.out; then @@ -47,3 +46,13 @@ if grep -e "dotr test ok" sbtdotr3.out; then else exit -1 fi + +echo "testing loading tasty from .tasty file in jar" +./project/scripts/sbt ";dotc -d out/scriptedtest4.jar -YemitTasty tests/pos/sbtDotrTest.scala; dotc -decompile -classpath out/scriptedtest4.jar -color:never dotrtest.Test" > sbtdot4.out +cat sbtdot4.out +if grep -e "def main(args: Array\[String\]): Unit =" sbtdot4.out; then + echo "output ok" +else + echo "failed output check" + exit -1 +fi