summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-12-02 09:31:04 +0100
committerGitHub <noreply@github.com>2016-12-02 09:31:04 +0100
commitccfa36071f0623d64474f37b12d40a838aac1b4e (patch)
tree741982f0327fd013d6f218b5582adea5d7d93fd4
parentaacef6d66e14096e36f849945800c092d4688f2a (diff)
parent159480f2504cc08f9cc35660cc33090a49e0228e (diff)
downloadscala-ccfa36071f0623d64474f37b12d40a838aac1b4e.tar.gz
scala-ccfa36071f0623d64474f37b12d40a838aac1b4e.tar.bz2
scala-ccfa36071f0623d64474f37b12d40a838aac1b4e.zip
Merge pull request #5385 from retronym/topic/JEP-220
Preliminary support for Java 9
-rw-r--r--bincompat-forward.whitelist.conf4
-rwxr-xr-xsrc/compiler/scala/tools/ant/templates/tool-unix.tmpl15
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala6
-rw-r--r--src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala51
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FileUtils.scala2
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala1
-rw-r--r--src/reflect/scala/reflect/io/PlainFile.scala80
7 files changed, 151 insertions, 8 deletions
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index 4461974081..7ccd2ea8fa 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -25,6 +25,10 @@ filter {
matchName="scala.reflect.runtime.Settings.Yvirtpatmat"
problemName=DirectMissingMethodProblem
},
+ {
+ matchName="scala.reflect.io.PlainNioFile"
+ problemName=MissingClassProblem
+ },
# this one can be removed once there is a fix for
# https://github.com/typesafehub/migration-manager/issues/147
{
diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
index 5e6b3c041e..b5a238f7be 100755
--- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
@@ -160,7 +160,7 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
-nobootcp)
- unset usebootcp
+ usebootcp="false"
shift
;;
-usebootcp)
@@ -189,15 +189,22 @@ declare -a classpath_args
# default to the boot classpath for speed, except on cygwin/mingw/msys because
# JLine on Windows requires a custom DLL to be loaded.
-unset usebootcp
-if [[ -z "$cygwin$mingw$msys" ]]; then
+if [[ "$usebootcp" != "false" && -z "$cygwin$mingw$msys" ]]; then
usebootcp="true"
fi
# If using the boot classpath, also pass an empty classpath
# to java to suppress "." from materializing.
-if [[ -n $usebootcp ]]; then
+if [[ "$usebootcp" == "true" ]]; then
classpath_args=("-Xbootclasspath/a:$TOOL_CLASSPATH" -classpath "\"\"")
+ # Note that the version numbers go 1.7, 1.8, 9, 10, ...
+ java_release="$(cat $JAVA_HOME/release | grep JAVA_VERSION)"
+ if [[ ! "$java_release" =~ JAVA_VERSION=\"1\. ]]; then
+ # Java 9 removed sun.boot.class.path, and the supposed replacement to at least see
+ # the appended boot classpath (jdk.boot.class.path.append) is not visible.
+ # So we have to pass a custom system property that PathResolver will find.
+ classpath_args+=("-Dscala.boot.class.path=$TOOL_CLASSPATH")
+ fi
else
classpath_args=(-classpath "$TOOL_CLASSPATH")
fi
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
index 3a29f1ba11..80c5ec8828 100644
--- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
@@ -4,6 +4,7 @@
package scala.tools.nsc.classpath
import scala.reflect.io.{AbstractFile, VirtualDirectory}
+import scala.reflect.io.Path.string2path
import scala.tools.nsc.Settings
import FileUtils.AbstractFileOps
import scala.tools.nsc.util.ClassPath
@@ -52,7 +53,10 @@ class ClassPathFactory(settings: Settings) {
protected def classesInPathImpl(path: String, expand: Boolean) =
for {
file <- expandPath(path, expand)
- dir <- Option(AbstractFile.getDirectory(file))
+ dir <- {
+ def asImage = if (file.endsWith(".jimage")) Some(AbstractFile.getFile(file)) else None
+ Option(AbstractFile.getDirectory(file)).orElse(asImage)
+ }
} yield newClassPath(dir)
private def createSourcePath(file: AbstractFile): ClassPath =
diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
index c4be59d7eb..133a656206 100644
--- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
@@ -4,7 +4,9 @@
package scala.tools.nsc.classpath
import java.io.File
-import java.net.URL
+import java.net.{URI, URL}
+import java.nio.file.{FileSystems, Files, SimpleFileVisitor}
+import java.util.function.IntFunction
import java.util
import java.util.Comparator
@@ -119,6 +121,53 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo
def asClassPathStrings: Seq[String] = Seq(dir.getPath)
}
+object JImageDirectoryLookup {
+ import java.nio.file._, java.net.URI, scala.collection.JavaConverters._
+ def apply(): List[ClassPath] = {
+ try {
+ val fs = FileSystems.getFileSystem(URI.create("jrt:/"))
+ val dir: Path = fs.getPath("/modules")
+ val modules = Files.list(dir).iterator().asScala.toList
+ modules.map(m => new JImageDirectoryLookup(fs, m.getFileName.toString))
+ } catch {
+ case _: ProviderNotFoundException | _: FileSystemNotFoundException =>
+ Nil
+ }
+ }
+}
+class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ import java.nio.file.Path, java.nio.file._
+ type F = Path
+ val dir: Path = fs.getPath("/modules/" + module)
+
+ protected def emptyFiles: Array[Path] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[Path] = {
+ val packageDir = dir.resolve(packageDirName)
+ if (Files.exists(packageDir) && Files.isDirectory(packageDir)) Some(packageDir)
+ else None
+ }
+ protected def listChildren(dir: Path, filter: Option[Path => Boolean]): Array[Path] = {
+ import scala.collection.JavaConverters._
+ val f = filter.getOrElse((p: Path) => true)
+ Files.list(dir).iterator().asScala.filter(f).toArray[Path]
+ }
+ protected def getName(f: Path): String = f.getFileName.toString
+ protected def toAbstractFile(f: Path): AbstractFile = new scala.reflect.io.PlainNioFile(f)
+ protected def isPackage(f: Path): Boolean = Files.isDirectory(f) && mayBeValidPackage(f.getFileName.toString)
+
+ def asURLs: Seq[URL] = Seq(dir.toUri.toURL)
+ def asClassPathStrings: Seq[String] = asURLs.map(_.toString)
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className) + ".class"
+ val classFile = dir.resolve(relativePath)
+ if (Files.exists(classFile)) Some(new scala.reflect.io.PlainNioFile(classFile)) else None
+ }
+ override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ override protected def isMatchingFile(f: Path): Boolean = Files.isRegularFile(f) && f.getFileName.toString.endsWith(".class")
+ override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+}
+
case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
diff --git a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
index bbcfcb24ca..2ade83c6f9 100644
--- a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
+++ b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
@@ -63,7 +63,7 @@ object FileUtils {
// probably it should match a pattern like [a-z_]{1}[a-z0-9_]* but it cannot be changed
// because then some tests in partest don't pass
- private def mayBeValidPackage(dirName: String): Boolean =
+ def mayBeValidPackage(dirName: String): Boolean =
(dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.')
def mkFileFilter(f: JFile => Boolean) = new FileFilter {
diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala
index c351b6ace1..188cabbc8d 100644
--- a/src/compiler/scala/tools/util/PathResolver.scala
+++ b/src/compiler/scala/tools/util/PathResolver.scala
@@ -234,6 +234,7 @@ final class PathResolver(settings: Settings) {
// Assemble the elements!
def basis = List[Traversable[ClassPath]](
+ JImageDirectoryLookup.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system)
classesInPath(javaBootClassPath), // 1. The Java bootstrap class path.
contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path.
classesInExpandedPath(javaUserClassPath), // 3. The Java application class path.
diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala
index eb0940e703..989081ebe0 100644
--- a/src/reflect/scala/reflect/io/PlainFile.scala
+++ b/src/reflect/scala/reflect/io/PlainFile.scala
@@ -40,7 +40,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
override def output = givenPath.toFile.outputStream()
override def sizeOption = Some(givenPath.length.toInt)
- override def toString = path
override def hashCode(): Int = fpath.hashCode()
override def equals(that: Any): Boolean = that match {
case x: PlainFile => fpath == x.fpath
@@ -91,3 +90,82 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
new PlainFile(givenPath / name)
}
+
+private[scala] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile {
+ import java.nio.file._
+
+ assert(nioPath ne null)
+
+ /** Returns the underlying File if any and null otherwise. */
+ override def file: java.io.File = try {
+ nioPath.toFile
+ } catch {
+ case _: UnsupportedOperationException => null
+ }
+
+ override def underlyingSource = Some(this)
+
+ private val fpath = nioPath.toAbsolutePath.toString
+
+ /** Returns the name of this abstract file. */
+ def name = nioPath.getFileName.toString
+
+ /** Returns the path of this abstract file. */
+ def path = nioPath.toString
+
+ /** The absolute file. */
+ def absolute = new PlainNioFile(nioPath.toAbsolutePath)
+
+ override def container: AbstractFile = new PlainNioFile(nioPath.getParent)
+ override def input = Files.newInputStream(nioPath)
+ override def output = Files.newOutputStream(nioPath)
+ override def sizeOption = Some(Files.size(nioPath).toInt)
+ override def hashCode(): Int = fpath.hashCode()
+ override def equals(that: Any): Boolean = that match {
+ case x: PlainNioFile => fpath == x.fpath
+ case _ => false
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = Files.isDirectory(nioPath)
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = Files.getLastModifiedTime(nioPath).toMillis
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ try {
+ import scala.collection.JavaConverters._
+ val it = Files.newDirectoryStream(nioPath).iterator()
+ it.asScala.map(new PlainNioFile(_))
+ } catch {
+ case _: NotDirectoryException => Iterator.empty
+ }
+ }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ val child = nioPath.resolve(name)
+ if ((Files.isDirectory(child) && directory) || (Files.isRegularFile(child) && !directory)) new PlainNioFile(child)
+ else null
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create(): Unit = if (!exists) Files.createFile(nioPath)
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit =
+ if (Files.isRegularFile(nioPath)) Files.deleteIfExists(nioPath)
+ else if (Files.isDirectory(nioPath)) new Directory(nioPath.toFile).deleteRecursively()
+
+ /** Returns a plain file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainNioFile(nioPath.resolve(name))
+}