diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index 7b0c294e5cf3..49f5ff79130b 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -216,7 +216,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) { val store = if (mirrorC ne null) mirrorC else plainC val tasty = - if (ctx.settings.YemitTasty.value) { + if (!ctx.settings.YemitTastyInClass.value) { val outTastyFile = getFileForClassfile(outF, store.name, ".tasty") val outstream = new DataOutputStream(outTastyFile.bufferedOutput) try outstream.write(binary) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 94d1b689c9e0..7fb8b9b79863 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -90,7 +90,7 @@ class ScalaSettings extends Settings.SettingGroup { val YdebugNames = BooleanSetting("-Ydebug-names", "Show internal representation of names") val YtermConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") val Ylog = PhasesSetting("-Ylog", "Log operations during") - val YemitTasty = BooleanSetting("-Yemit-tasty", "Generate tasty in separate *.tasty file.") + val YemitTastyInClass = BooleanSetting("-Yemit-tasty-in-class", "Generate tasty in the .class file and add an empty *.hasTasty file.") val YlogClasspath = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.") val YdisableFlatCpCaching = BooleanSetting("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.") diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 2379ddfc610b..ac6af4dfd2c3 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -7,9 +7,11 @@ import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ -import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException } +import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, DataInputStream, File, IOException } import java.nio import java.lang.Integer.toHexString +import java.net.URLClassLoader + import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } import scala.annotation.switch @@ -784,24 +786,35 @@ class ClassfileParser( if (scan(tpnme.TASTYATTR)) { val attrLen = in.nextInt 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 + val tastyBytes: Array[Byte] = 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] + Array.empty 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() + val cl = new URLClassLoader(Array(jar.jpath.toUri.toURL)) + val path = classfile.path.stripSuffix(".class") + ".tasty" + val stream = cl.getResourceAsStream(path) + if (stream != null) { + val tastyOutStream = new ByteArrayOutputStream() + val buffer = new Array[Byte](1024) + var read = stream.read(buffer, 0, buffer.length) + while (read != -1) { + tastyOutStream.write(buffer, 0, read) + read = stream.read(buffer, 0, buffer.length) + } + tastyOutStream.flush() + tastyOutStream.toByteArray + } else { + ctx.error(s"Could not find $path in $jar") + Array.empty + } case _ => - readTastyForClass(classfile.jpath) + val plainFile = new PlainFile(io.File(classfile.jpath).changeExtension("tasty")) + if (plainFile.exists) plainFile.toByteArray + else { + ctx.error("Could not find " + plainFile) + Array.empty + } } if (tastyBytes.nonEmpty) return unpickleTASTY(tastyBytes) diff --git a/compiler/src/dotty/tools/io/JarArchive.scala b/compiler/src/dotty/tools/io/JarArchive.scala index 0960160d52b7..e039e7ae4cb0 100644 --- a/compiler/src/dotty/tools/io/JarArchive.scala +++ b/compiler/src/dotty/tools/io/JarArchive.scala @@ -1,6 +1,6 @@ package dotty.tools.io -import java.nio.file.{Files, FileSystem, FileSystems} +import java.nio.file.{FileSystemAlreadyExistsException, FileSystems} import scala.collection.JavaConverters._ @@ -9,7 +9,7 @@ import scala.collection.JavaConverters._ * that be can used as the compiler's output directory. */ class JarArchive private (root: Directory) extends PlainDirectory(root) { - def close() = jpath.getFileSystem().close() + def close(): Unit = jpath.getFileSystem().close() } object JarArchive { @@ -28,8 +28,12 @@ object JarArchive { // https://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html val env = Map("create" -> create.toString).asJava val uri = java.net.URI.create("jar:file:" + path.toAbsolute.path) - val fs = FileSystems.newFileSystem(uri, env) - + val fs = { + try FileSystems.newFileSystem(uri, env) + catch { + case _: FileSystemAlreadyExistsException => FileSystems.getFileSystem(uri) + } + } val root = fs.getRootDirectories().iterator.next() new JarArchive(Directory(root)) } diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index c898d370c0f4..1efccb4ac3d2 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -101,7 +101,7 @@ class CompilationTests extends ParallelTesting { compileFilesInDir("tests/pos", defaultOptions) + compileFilesInDir("tests/pos-deep-subtype", allowDeepSubtypes) + compileFilesInDir("tests/pos-kind-polymorphism", defaultOptions and "-Ykind-polymorphism") + - compileDir("tests/pos/i1137-1", defaultOptions and "-Yemit-tasty") + + compileDir("tests/pos/i1137-1", defaultOptions) + compileFile( // succeeds despite -Xfatal-warnings because of -nowarn "tests/neg-custom-args/fatal-warnings/xfatalWarnings.scala", @@ -254,7 +254,7 @@ class CompilationTests extends ParallelTesting { defaultOutputDir + dotty1Group + "/dotty/:" + // and the other compiler dependecies: Jars.dottyInterfaces + ":" + Jars.jline, - Array("-Ycheck-reentrant") + Array("-Ycheck-reentrant", "-Yemit-tasty-in-class") ) val lib = diff --git a/compiler/test/dotty/tools/dotc/IdempotencyTests.scala b/compiler/test/dotty/tools/dotc/IdempotencyTests.scala index 8c969d6ff011..e17045882f20 100644 --- a/compiler/test/dotty/tools/dotc/IdempotencyTests.scala +++ b/compiler/test/dotty/tools/dotc/IdempotencyTests.scala @@ -28,7 +28,7 @@ class IdempotencyTests extends ParallelTesting { @Category(Array(classOf[SlowTests])) @Test def idempotency: Unit = { implicit val testGroup: TestGroup = TestGroup("idempotency") - val opt = defaultOptions.and("-Yemit-tasty") + val opt = defaultOptions def sourcesFrom(dir: Path) = CompilationTests.sources(Files.walk(dir)) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 26593ffd7fc5..85b1abeb5b7a 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -404,9 +404,11 @@ trait ParallelTesting extends RunnerOrchestration { self => tastyOutput.mkdir() val flags = flags0 and ("-d", tastyOutput.getAbsolutePath) and "-from-tasty" - def hasTastyFileToClassName(f: JFile): String = - targetDir.toPath.relativize(f.toPath).toString.dropRight(".hasTasty".length).replace('/', '.') - val classes = flattenFiles(targetDir).filter(isHasTastyFile).map(hasTastyFileToClassName) + def tastyFileToClassName(f: JFile): String = { + val pathStr = targetDir.toPath.relativize(f.toPath).toString.replace('/', '.') + pathStr.stripSuffix(".tasty").stripSuffix(".hasTasty") + } + val classes = flattenFiles(targetDir).filter(isTastyFile).map(tastyFileToClassName) val reporter = TestReporter.reporter(realStdout, logLevel = @@ -434,8 +436,8 @@ trait ParallelTesting extends RunnerOrchestration { self => "-decompile" and "-pagewidth" and "80" def hasTastyFileToClassName(f: JFile): String = - targetDir0.toPath.relativize(f.toPath).toString.dropRight(".hasTasty".length).replace('/', '.') - val classes = flattenFiles(targetDir0).filter(isHasTastyFile).map(hasTastyFileToClassName).sorted + targetDir0.toPath.relativize(f.toPath).toString.stripSuffix(".hasTasty").stripSuffix(".tasty").replace('/', '.') + val classes = flattenFiles(targetDir0).filter(isTastyFile).map(hasTastyFileToClassName).sorted val reporter = TestReporter.reporter(realStdout, logLevel = @@ -1368,6 +1370,6 @@ object ParallelTesting { name.endsWith(".scala") || name.endsWith(".java") } - def isHasTastyFile(f: JFile): Boolean = - f.getName.endsWith(".hasTasty") + def isTastyFile(f: JFile): Boolean = + f.getName.endsWith(".hasTasty") || f.getName.endsWith(".tasty") } diff --git a/project/scripts/cmdTests b/project/scripts/cmdTests index 1f78f076c7d9..203b8e78fa01 100755 --- a/project/scripts/cmdTests +++ b/project/scripts/cmdTests @@ -47,7 +47,7 @@ grep -qe "$EXPECTED_OUTPUT" "$tmp" echo "testing loading tasty from .tasty file in jar" clear_out "$OUT" -"$SBT" ";dotc -d $OUT/out.jar -Yemit-tasty $SOURCE; dotc -decompile -classpath $OUT/out.jar -color:never $MAIN" > "$tmp" +"$SBT" ";dotc -d $OUT/out.jar $SOURCE; dotc -decompile -classpath $OUT/out.jar -color:never $MAIN" > "$tmp" grep -qe "def main(args: scala.Array\[scala.Predef.String\]): scala.Unit =" "$tmp" echo "testing scala.quoted.Expr.run from sbt dotr"