diff options
25 files changed, 171 insertions, 41 deletions
@@ -32,6 +32,7 @@ * - to modularize the Scala compiler or library further */ +import scala.build._ import VersionUtil._ // Scala dependencies: diff --git a/project/BuildSettings.scala b/project/BuildSettings.scala index 76cd888a2d..8456f91f86 100644 --- a/project/BuildSettings.scala +++ b/project/BuildSettings.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ /** This object defines keys that should be visible with an unqualified name in all .sbt files and the command line */ diff --git a/project/GenerateAnyVals.scala b/project/GenerateAnyVals.scala index 84454cb0ed..f349bfd16b 100644 --- a/project/GenerateAnyVals.scala +++ b/project/GenerateAnyVals.scala @@ -1,3 +1,5 @@ +package scala.build + /** Code generation of the AnyVal types and their companions. */ trait GenerateAnyValReps { self: GenerateAnyVals => diff --git a/project/JarJar.scala b/project/JarJar.scala index 918060c9ee..3cb9e4cfff 100644 --- a/project/JarJar.scala +++ b/project/JarJar.scala @@ -1,3 +1,5 @@ +package scala.build + import org.pantsbuild.jarjar import org.pantsbuild.jarjar._ import org.pantsbuild.jarjar.util._ diff --git a/project/MiMa.scala b/project/MiMa.scala index ceda8f5594..fb9bb175ab 100644 --- a/project/MiMa.scala +++ b/project/MiMa.scala @@ -1,3 +1,5 @@ +package scala.build + // It would be nice to use sbt-mima-plugin here, but the plugin is missing // at least two features we need: // * ability to run MiMa twice, swapping `curr` and `prev`, to detect diff --git a/project/Osgi.scala b/project/Osgi.scala index 082fd91ed1..b05751958a 100644 --- a/project/Osgi.scala +++ b/project/Osgi.scala @@ -1,3 +1,5 @@ +package scala.build + import aQute.bnd.osgi.Builder import aQute.bnd.osgi.Constants._ import java.util.Properties diff --git a/project/ParserUtil.scala b/project/ParserUtil.scala index cdaf8831a5..bbd9129dbe 100644 --- a/project/ParserUtil.scala +++ b/project/ParserUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import sbt.complete.Parser._ import sbt.complete.Parsers._ diff --git a/project/PartestUtil.scala b/project/PartestUtil.scala index 23570a88ec..127dcafefa 100644 --- a/project/PartestUtil.scala +++ b/project/PartestUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import sbt.complete._, Parser._, Parsers._ diff --git a/project/Quiet.scala b/project/Quiet.scala index 0a186d8f28..8ae08ad5a6 100644 --- a/project/Quiet.scala +++ b/project/Quiet.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ diff --git a/project/ScalaOptionParser.scala b/project/ScalaOptionParser.scala index 27ed1f0e6f..0208921959 100644 --- a/project/ScalaOptionParser.scala +++ b/project/ScalaOptionParser.scala @@ -1,3 +1,5 @@ +package scala.build + import ParserUtil._ import sbt._ import sbt.complete.Parser._ diff --git a/project/ScalaTool.scala b/project/ScalaTool.scala index 98e18235c4..ace547c640 100644 --- a/project/ScalaTool.scala +++ b/project/ScalaTool.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.StringUtils.replaceEach diff --git a/project/ScriptCommands.scala b/project/ScriptCommands.scala index 8d5d09943a..f6b700f007 100644 --- a/project/ScriptCommands.scala +++ b/project/ScriptCommands.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ import BuildSettings.autoImport._ diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 7c4909697f..ebc2488345 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ import java.util.Properties diff --git a/spec/README.md b/spec/README.md index b19ce6441f..ad524dfdf3 100644 --- a/spec/README.md +++ b/spec/README.md @@ -8,7 +8,11 @@ Third, we'd like to support different output formats. An html page per chapter w ## Editing -We use Jekyll 2 and [Redcarpet](https://github.com/vmg/redcarpet) to generate the html. Essentially, this is what github pages use. +At the time of writing we are using Jekyll 3.3.0 and [Redcarpet 3.3.2](https://github.com/vmg/redcarpet) to generate the html. + +Check `Gemfile` for the current versions. + +We aim to track the configuration GitHub Pages use but at times differences will arise as GitHub Pages evolves. ## Building diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 226c49ec07..3ed1570c1c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -983,6 +983,8 @@ trait Scanners extends ScannersCommon { def intVal: Long = intVal(negated = false) + private val zeroFloat = raw"[0.]+(?:[eE][+-]?[0-9]+)?[fFdD]?".r + /** Convert current strVal, base to float value. */ def floatVal(negated: Boolean): Float = { @@ -990,8 +992,7 @@ trait Scanners extends ScannersCommon { val value: Float = java.lang.Float.parseFloat(strVal) if (value > Float.MaxValue) syntaxError("floating point number too large") - val zeroly = "0.fF" - if (value == 0.0f && strVal.exists(c => !zeroly.contains(c))) + if (value == 0.0f && !zeroFloat.pattern.matcher(strVal).matches) syntaxError("floating point number too small") if (negated) -value else value } catch { @@ -1010,8 +1011,7 @@ trait Scanners extends ScannersCommon { val value: Double = java.lang.Double.parseDouble(strVal) if (value > Double.MaxValue) syntaxError("double precision floating point number too large") - val zeroly = "0.dD" - if (value == 0.0d && strVal.exists(c => !zeroly.contains(c))) + if (value == 0.0d && !zeroFloat.pattern.matcher(strVal).matches) syntaxError("double precision floating point number too small") if (negated) -value else value } catch { diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index 1ea152b29c..fbd59eb04a 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -10,9 +10,10 @@ import java.util.function.IntFunction import java.util import java.util.Comparator -import scala.reflect.io.{AbstractFile, PlainFile} +import scala.reflect.io.{AbstractFile, PlainFile, PlainNioFile} import scala.tools.nsc.util.{ClassPath, ClassRepresentation} import FileUtils._ +import scala.collection.JavaConverters._ /** * A trait allowing to look for classpath entries in directories. It provides common logic for @@ -121,51 +122,78 @@ 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] = { +object JrtClassPath { + import java.nio.file._, java.net.URI + def apply(): Option[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)) + Some(new JrtClassPath(fs)) } catch { case _: ProviderNotFoundException | _: FileSystemNotFoundException => - Nil + None } } } -class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { + +/** + * Implementation `ClassPath` based on the JDK 9 encapsulated runtime modules (JEP-220) + * + * https://bugs.openjdk.java.net/browse/JDK-8066492 is the most up to date reference + * for the structure of the jrt:// filesystem. + * + * The implementation assumes that no classes exist in the empty package. + */ +final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with NoSourcePaths { import java.nio.file.Path, java.nio.file._ type F = Path - val dir: Path = fs.getPath("/modules/" + module) + private val dir: Path = fs.getPath("/packages") - 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 + // e.g. "java.lang" -> Seq("/modules/java.base") + private val packageToModuleBases: Map[String, Seq[Path]] = { + val ps = Files.newDirectoryStream(dir).iterator().asScala + def lookup(pack: Path): Seq[Path] = { + Files.list(pack).iterator().asScala.map(l => if (Files.isSymbolicLink(l)) Files.readSymbolicLink(l) else l).toList + } + ps.map(p => (p.toString.stripPrefix("/packages/"), lookup(p))).toMap } - 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] + + override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { + def matches(packageDottedName: String) = + if (packageDottedName.contains(".")) + packageOf(packageDottedName) == inPackage + else inPackage == "" + packageToModuleBases.keysIterator.filter(matches).map(PackageEntryImpl(_)).toVector + } + private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = { + if (inPackage == "") Nil + else { + packageToModuleBases.getOrElse(inPackage, Nil).flatMap(x => + Files.list(x.resolve(inPackage.replace('.', '/'))).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x => + ClassFileEntryImpl(new PlainNioFile(x))).toVector + } } - 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) + + override private[nsc] def list(inPackage: String): ClassPathEntries = + if (inPackage == "") ClassPathEntries(packages(inPackage), Nil) + else ClassPathEntries(packages(inPackage), classes(inPackage)) def asURLs: Seq[URL] = Seq(dir.toUri.toURL) - def asClassPathStrings: Seq[String] = asURLs.map(_.toString) + // We don't yet have a scheme to represent the JDK modules in our `-classpath`. + // java models them as entries in the new "module path", we'll probably need to follow this. + def asClassPathStrings: Seq[String] = Nil 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 + if (!className.contains(".")) None + else { + val inPackage = packageOf(className) + packageToModuleBases.getOrElse(inPackage, Nil).iterator.flatMap{x => + val file = x.resolve(className.replace('.', '/') + ".class") + if (Files.exists(file)) new scala.reflect.io.PlainNioFile(file) :: Nil else Nil + }.take(1).toList.headOption + } } - 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) + private def packageOf(dottedClassName: String): String = + dottedClassName.substring(0, dottedClassName.lastIndexOf(".")) } case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index 99263bf834..f1f5f37c36 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -14,8 +14,10 @@ import StringOps.{countElementsAsString => countAs, trimAllTrailingSpace => trim /** This class implements a Reporter that displays messages on a text console. */ -class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter) extends AbstractReporter { - def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true)) +class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter, echoWriter: PrintWriter) extends AbstractReporter { + def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true), new PrintWriter(Console.out, true)) + def this(settings: Settings, reader: BufferedReader, writer: PrintWriter) = + this(settings, reader, writer, writer) /** Whether a short file name should be displayed before errors */ var shortname: Boolean = false @@ -41,6 +43,12 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr writer.flush() } + /** Prints the message to the echoWriter, which is usually stdout. */ + override def echo(msg: String): Unit = { + echoWriter.println(trimTrailing(msg)) + echoWriter.flush() + } + /** Prints the message with the given position indication. */ def printMessage(posIn: Position, msg: String): Unit = printMessage(formatMessage(posIn, msg, shortname)) diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 188cabbc8d..f845656980 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -234,7 +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) + JrtClassPath.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system, if available) 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/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 24f8aa88e6..07ae71538c 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -161,6 +161,11 @@ trait Erasure { } if (newParents eq parents) tp else ClassInfoType(newParents, decls, clazz) + + // can happen while this map is being used before erasure (e.g. when reasoning about sam types) + // the regular mapOver will cause a class cast exception because TypeBounds don't erase to TypeBounds + case _: BoundedWildcardType => tp // skip + case _ => mapOver(tp) } diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala index 3cede1b3c5..49ab0cb30e 100644 --- a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala @@ -92,7 +92,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) } } - private val packages = mutable.Map[String, Package]() + private[this] val packages = mutable.Map[String, Package]() override def definePackage(name: String, specTitle: String, specVersion: String, specVendor: String, implTitle: String, implVersion: String, implVendor: String, sealBase: URL): Package = { throw new UnsupportedOperationException() diff --git a/src/repl/scala/tools/nsc/interpreter/Scripted.scala b/src/repl/scala/tools/nsc/interpreter/Scripted.scala index 6aef486957..8d87d98e53 100644 --- a/src/repl/scala/tools/nsc/interpreter/Scripted.scala +++ b/src/repl/scala/tools/nsc/interpreter/Scripted.scala @@ -331,7 +331,7 @@ class WriterOutputStream(writer: Writer) extends OutputStream { byteBuffer.flip() val result = decoder.decode(byteBuffer, charBuffer, /*eoi=*/ false) if (byteBuffer.remaining == 0) byteBuffer.clear() - if (charBuffer.position > 0) { + if (charBuffer.position() > 0) { charBuffer.flip() writer write charBuffer.toString charBuffer.clear() diff --git a/test/files/pos/sam_erasure_boundedwild.scala b/test/files/pos/sam_erasure_boundedwild.scala new file mode 100644 index 0000000000..1ec27e0ea4 --- /dev/null +++ b/test/files/pos/sam_erasure_boundedwild.scala @@ -0,0 +1,11 @@ +class Test { + trait Q[T] { + def toArray[T](x: Array[T]): Array[T] + def toArray(): Array[T] + } + + def crashTyper: Array[_] = { + val x : Q[_] = ??? + x.toArray // crashes while doing overload resolution + } +}
\ No newline at end of file diff --git a/test/files/run/literals.scala b/test/files/run/literals.scala index 25501123b5..a7962e5cd9 100644 --- a/test/files/run/literals.scala +++ b/test/files/run/literals.scala @@ -6,7 +6,7 @@ object Test { - /* I add a couple of Unicode identifier tests here temporarily */ + /* I add a couple of Unicode identifier tests here "temporarily" */ def \u03b1\u03c1\u03b5\u03c4\u03b7 = "alpha rho epsilon tau eta" @@ -80,6 +80,9 @@ object Test { check_success("1e1f == 10.0f", 1e1f, 10.0f) check_success(".3f == 0.3f", .3f, 0.3f) check_success("0f == 0.0f", 0f, 0.0f) + check_success("0f == -0.000000000000000000e+00f", 0f, -0.000000000000000000e+00f) + check_success("0f == -0.000000000000000000e+00F", 0f, -0.000000000000000000e+00F) + check_success("0f == -0.0000000000000000e14f", 0f, -0.0000000000000000e14f) check_success("01.23f == 1.23f", 01.23f, 1.23f) check_success("3.14f == 3.14f", 3.14f, 3.14f) check_success("6.022e23f == 6.022e23f", 6.022e23f, 6.022e23f) @@ -96,6 +99,11 @@ object Test { check_success(".3 == 0.3", .3, 0.3) check_success("0.0 == 0.0", 0.0, 0.0) check_success("0d == 0.0", 0d, 0.0) + check_success("0d == 0.000000000000000000e+00d", 0d, 0.000000000000000000e+00d) + check_success("0d == -0.000000000000000000e+00d", 0d, -0.000000000000000000e+00d) + check_success("0d == -0.000000000000000000e+00D", 0d, -0.000000000000000000e+00D) + check_success("0.0 == 0.000000000000000000e+00", 0.0, 0.000000000000000000e+00) + check_success("0.0 == -0.000000000000000000e+00", 0.0, -0.000000000000000000e+00) check_success("01.23 == 1.23", 01.23, 1.23) check_success("01.23d == 1.23d", 01.23d, 1.23d) check_success("3.14 == 3.14", 3.14, 3.14) diff --git a/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala new file mode 100644 index 0000000000..2c3c5134da --- /dev/null +++ b/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ +package scala.tools.nsc.classpath + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.nsc.Settings +import scala.tools.nsc.backend.jvm.AsmUtils +import scala.tools.nsc.util.ClassPath +import scala.tools.util.PathResolver + +@RunWith(classOf[JUnit4]) +class JrtClassPathTest { + + @Test def lookupJavaClasses(): Unit = { + val specVersion = scala.util.Properties.javaSpecVersion + // Run the test using the JDK8 or 9 provider for rt.jar depending on the platform the test is running on. + val cp: ClassPath = + if (specVersion == "" || specVersion == "1.8") { + val settings = new Settings() + val resolver = new PathResolver(settings) + val elements = new ClassPathFactory(settings).classesInPath(resolver.Calculated.javaBootClassPath) + AggregateClassPath(elements) + } + else JrtClassPath().get + + assertEquals(Nil, cp.classes("")) + assertTrue(cp.packages("java").toString, cp.packages("java").exists(_.name == "java.lang")) + assertTrue(cp.classes("java.lang").exists(_.name == "Object")) + val jl_Object = cp.classes("java.lang").find(_.name == "Object").get + assertEquals("java/lang/Object", AsmUtils.classFromBytes(jl_Object.file.toByteArray).name) + assertTrue(cp.list("java.lang").packages.exists(_.name == "java.lang.annotation")) + assertTrue(cp.list("java.lang").classesAndSources.exists(_.name == "Object")) + assertTrue(cp.findClass("java.lang.Object").isDefined) + assertTrue(cp.findClassFile("java.lang.Object").isDefined) + } +} diff --git a/versions.properties b/versions.properties index 26e8324c44..f767dfab7b 100644 --- a/versions.properties +++ b/versions.properties @@ -21,7 +21,7 @@ scala-swing.version.number=2.0.0 scala-swing.version.osgi=2.0.0 jline.version=2.14.3 # this one is shaded and embedded in scala-compiler.jar -scala-asm.version=5.1.0-scala-1 +scala-asm.version=5.1.0-scala-2 # external modules, used internally (not shipped) partest.version.number=1.1.0 |