summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt72
-rw-r--r--project/Osgi.scala1
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenUtils.scala2
-rw-r--r--src/compiler/scala/reflect/reify/utils/NodePrinters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala144
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala9
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala38
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala23
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala148
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala37
-rw-r--r--src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala)54
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPath.scala60
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala63
-rw-r--r--src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala)23
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala98
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala44
-rw-r--r--src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala2
-rw-r--r--src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala)5
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala45
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala9
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala51
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala20
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassFileLookup.scala78
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala367
-rw-r--r--src/compiler/scala/tools/reflect/ReflectMain.scala4
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala67
-rw-r--r--src/eclipse/partest/.classpath2
-rw-r--r--src/eclipse/scaladoc/.classpath2
-rw-r--r--src/library/scala/Product.scala2
-rw-r--r--src/library/scala/collection/immutable/BitSet.scala12
-rw-r--r--src/library/scala/collection/mutable/PriorityQueue.scala4
-rw-r--r--src/library/scala/concurrent/Future.scala4
-rw-r--r--src/library/scala/util/matching/Regex.scala29
-rw-r--r--src/partest-extras/scala/tools/partest/BytecodeTest.scala18
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala4
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala16
-rw-r--r--src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala25
-rw-r--r--src/repl/scala/tools/nsc/interpreter/package.scala12
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala30
-rw-r--r--test/files/pos/t9397.scala12
-rw-r--r--test/files/run/reify_printf.scala1
-rw-r--r--test/files/run/repl-implicits-nopredef.check5
-rw-r--r--test/files/run/repl-implicits-nopredef.scala10
-rw-r--r--test/files/run/repl-implicits.check5
-rw-r--r--test/files/run/repl-implicits.scala5
-rw-r--r--test/files/run/t6502.scala18
-rw-r--r--test/files/run/various-flat-classpath-types.scala9
-rw-r--r--test/junit/scala/collection/mutable/PriorityQueueTest.scala7
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala41
-rw-r--r--test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala (renamed from test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala)27
-rw-r--r--test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala (renamed from test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala)59
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala27
-rw-r--r--test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala143
-rw-r--r--test/junit/scala/util/matching/RegexTest.scala64
-rw-r--r--versions.properties2
62 files changed, 785 insertions, 1317 deletions
diff --git a/build.sbt b/build.sbt
index 4962e4e41c..e9ea2c7153 100644
--- a/build.sbt
+++ b/build.sbt
@@ -4,7 +4,7 @@
* What you see below is very much work-in-progress. The following features are implemented:
* - Compiling all classses for the compiler and library ("compile" in the respective subprojects)
* - Running JUnit tests ("test") and partest ("test/it:test")
- * - Creating build/quick with all compiled classes and launcher scripts ("dist/mkQuick")
+ * - Creating build/quick with all compiled classes and launcher scripts ("˜")
* - Creating build/pack with all JARs and launcher scripts ("dist/mkPack")
* - Building all scaladoc sets ("doc")
* - Publishing ("publishDists" and standard sbt tasks like "publish" and "publishLocal")
@@ -84,7 +84,7 @@ lazy val publishSettings : Seq[Setting[_]] = Seq(
val mappings = artifacts.toSeq.map { case (a, f) =>
val typeSuffix = a.`type` match {
case "pom" => "-pom.xml"
- case "bundle" | "jar" => ".jar"
+ case "jar" => ".jar"
case "doc" => "-docs.jar"
case tpe => s"-$tpe.${a.extension}"
}
@@ -99,6 +99,8 @@ lazy val publishSettings : Seq[Setting[_]] = Seq(
if (file.exists) List(Credentials(file))
else Nil
},
+ // Add a "default" Ivy configuration because sbt expects the Scala distribution to have one:
+ ivyConfigurations += Configuration("default", "Default", true, List(Configurations.Runtime), true),
publishMavenStyle := true
)
@@ -236,8 +238,8 @@ def fixPom(extra: (String, scala.xml.Node)*): Setting[_] = {
) ++ extra) }
}
-/** Remove unwanted dependencies from the POM. */
-def removePomDependencies(deps: (String, String)*): Setting[_] = {
+/** Remove unwanted dependencies from the POM and ivy.xml. */
+def removePomDependencies(deps: (String, String)*): Seq[Setting[_]] = Seq(
pomPostProcess := { n =>
val n2 = pomPostProcess.value.apply(n)
import scala.xml._
@@ -252,14 +254,40 @@ def removePomDependencies(deps: (String, String)*): Setting[_] = {
case n => Seq(n)
}
})).transform(Seq(n2)).head
+ },
+ deliverLocal := {
+ import scala.xml._
+ import scala.xml.transform._
+ val f = deliverLocal.value
+ val e = (new RuleTransformer(new RewriteRule {
+ override def transform(node: Node) = node match {
+ case e: Elem if e.label == "dependency" && {
+ val org = e.attribute("org").getOrElse("").toString
+ val name = e.attribute("name").getOrElse("").toString
+ deps.exists { case (g, a) =>
+ org == g && (name == a || name == (a + "_" + scalaBinaryVersion.value))
+ }
+ } => Seq.empty
+ case n => Seq(n)
+ }
+ })).transform(Seq(XML.loadFile(f))).head
+ XML.save(f.getAbsolutePath, e, xmlDecl = true)
+ f
}
-}
+)
val disableDocs = Seq[Setting[_]](
sources in (Compile, doc) := Seq.empty,
publishArtifact in (Compile, packageDoc) := false
)
+val disablePublishing = Seq[Setting[_]](
+ publishArtifact := false,
+ // The above is enough for Maven repos but it doesn't prevent publishing of ivy.xml files
+ publish := {},
+ publishLocal := {}
+)
+
lazy val setJarLocation: Setting[_] =
artifactPath in packageBin in Compile := {
// two lines below are copied over from sbt's sources:
@@ -397,43 +425,44 @@ lazy val compiler = configureAsSubproject(project)
"/project/description" -> <description>Compiler for the Scala Programming Language</description>,
"/project/packaging" -> <packaging>jar</packaging>
),
- apiURL := None,
- removePomDependencies(
- ("org.apache.ant", "ant"),
- ("org.scala-lang.modules", "scala-asm")
- )
+ apiURL := None
)
+ .settings(removePomDependencies(
+ ("org.apache.ant", "ant"),
+ ("org.scala-lang.modules", "scala-asm")
+ ): _*)
.dependsOn(library, reflect)
lazy val interactive = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-compiler-interactive",
- description := "Scala Interactive Compiler",
- publishArtifact := false
+ description := "Scala Interactive Compiler"
)
.dependsOn(compiler)
lazy val repl = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
connectInput in run := true,
- publishArtifact := false,
run <<= (run in Compile).partialInput(" -usejavacp") // Automatically add this so that `repl/run` works without additional arguments.
)
.dependsOn(compiler, interactive)
lazy val replJline = configureAsSubproject(Project("repl-jline", file(".") / "src" / "repl-jline"))
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
libraryDependencies += jlineDep,
- name := "scala-repl-jline",
- publishArtifact := false
+ name := "scala-repl-jline"
)
.dependsOn(repl)
lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target" / "repl-jline-embedded-src-dummy")
.settings(scalaSubprojectSettings: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-repl-jline-embedded",
// There is nothing to compile for this project. Instead we use the compile task to create
@@ -464,18 +493,17 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
val outdir = (classDirectory in Compile).value
JarJar(inputs, outdir, config)
}),
- publishArtifact := false,
connectInput in run := true
)
.dependsOn(replJline)
lazy val scaladoc = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-compiler-doc",
description := "Scala Documentation Generator",
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep),
- publishArtifact := false,
includeFilter in unmanagedResources in Compile := "*.html" | "*.css" | "*.gif" | "*.png" | "*.js" | "*.txt"
)
.dependsOn(compiler)
@@ -497,10 +525,10 @@ lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".
.dependsOn(replJlineEmbedded)
.settings(clearSourceAndResourceDirectories: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-partest-extras",
description := "Scala Compiler Testing Tool (compiler-specific extras)",
- publishArtifact := false,
libraryDependencies += partestDep,
unmanagedSourceDirectories in Compile := List(baseDirectory.value)
)
@@ -510,8 +538,8 @@ lazy val junit = project.in(file("test") / "junit")
.settings(clearSourceAndResourceDirectories: _*)
.settings(commonSettings: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
- publishArtifact := false,
fork in Test := true,
libraryDependencies ++= Seq(junitDep, junitIntefaceDep),
testOptions += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"),
@@ -543,9 +571,9 @@ lazy val test = project
.configs(IntegrationTest)
.settings(commonSettings: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(Defaults.itSettings: _*)
.settings(
- publishArtifact := false,
libraryDependencies ++= Seq(asmDep, partestDep, scalaXmlDep, scalacheckDep),
unmanagedBase in IntegrationTest := baseDirectory.value / "files" / "lib",
unmanagedJars in IntegrationTest <+= (unmanagedBase) (j => Attributed.blank(j)) map(identity),
@@ -572,8 +600,8 @@ lazy val test = project
lazy val manual = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
- publishArtifact := false,
libraryDependencies ++= Seq(scalaXmlDep, antDep),
classDirectory in Compile := (target in Compile).value / "classes"
)
@@ -643,9 +671,9 @@ lazy val scalaDist = Project("scala-dist", file(".") / "target" / "scala-dist-di
lazy val root = (project in file("."))
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(generateBuildCharacterFileSettings: _*)
.settings(
- publishArtifact := false,
publish := {},
publishLocal := {},
commands ++= ScriptCommands.all,
diff --git a/project/Osgi.scala b/project/Osgi.scala
index d88c282383..36803c0e44 100644
--- a/project/Osgi.scala
+++ b/project/Osgi.scala
@@ -40,7 +40,6 @@ object Osgi {
},
packagedArtifact in (Compile, packageBin) <<= (artifact in (Compile, packageBin), bundle).identityMap,
// Also create OSGi source bundles:
- artifact in (Compile, packageBin) ~= (_.copy(`type` = "bundle")),
packageOptions in (Compile, packageSrc) += Package.ManifestAttributes(
"Bundle-Name" -> (description.value + " Sources"),
"Bundle-SymbolicName" -> (bundleSymbolicName.value + ".source"),
diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
index b5b0f93750..242e5d60b3 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
@@ -55,7 +55,7 @@ trait GenUtils {
mirrorCall(TermName("" + prefix), args: _*)
def scalaFactoryCall(name: TermName, args: Tree*): Tree =
- call(s"scala.$name.apply", args: _*)
+ call(s"_root_.scala.$name.apply", args: _*)
def scalaFactoryCall(name: String, args: Tree*): Tree =
scalaFactoryCall(TermName(name), args: _*)
diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
index 3b91d28360..a5c4c7e0a3 100644
--- a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
+++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
@@ -28,7 +28,7 @@ trait NodePrinters {
var s = line substring 2
s = s.replace(nme.UNIVERSE_PREFIX.toString, "")
s = s.replace(".apply", "")
- s = "([^\"])scala\\.collection\\.immutable\\.".r.replaceAllIn(s, "$1")
+ s = "([^\"])(_root_\\.)?scala\\.collection\\.immutable\\.".r.replaceAllIn(s, "$1")
s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List")
s = "List\\[.*?\\]".r.replaceAllIn(s, "List")
s = s.replace("immutable.this.Nil", "List()")
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
index e99cce9186..c82ed68da8 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
@@ -6,10 +6,10 @@
package scala.tools.nsc
import java.net.URL
-import scala.tools.util.PathResolverFactory
+import scala.tools.util.PathResolver
class GenericRunnerSettings(error: String => Unit) extends Settings(error) {
- lazy val classpathURLs: Seq[URL] = PathResolverFactory.create(this).resultAsURLs
+ lazy val classpathURLs: Seq[URL] = new PathResolver(this).resultAsURLs
val howtorun =
ChoiceSetting(
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 94a6a0e4e2..7417d9c09d 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -13,7 +13,7 @@ import java.nio.charset.{Charset, CharsetDecoder, IllegalCharsetNameException, U
import scala.collection.{immutable, mutable}
import io.{AbstractFile, Path, SourceReader}
import reporters.Reporter
-import util.{ClassFileLookup, ClassPath, StatisticsInfo, returning}
+import util.{ClassPath, StatisticsInfo, returning}
import scala.reflect.ClassTag
import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, ScalaClassLoader, ScriptSourceFile, SourceFile}
import scala.reflect.internal.pickling.PickleBuffer
@@ -30,7 +30,6 @@ import backend.jvm.GenBCode
import scala.language.postfixOps
import scala.tools.nsc.ast.{TreeGen => AstTreeGen}
import scala.tools.nsc.classpath._
-import scala.tools.nsc.settings.ClassPathRepresentationType
class Global(var currentSettings: Settings, var reporter: Reporter)
extends SymbolTable
@@ -54,12 +53,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
class GlobalMirror extends Roots(NoSymbol) {
val universe: self.type = self
- def rootLoader: LazyType = {
- settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
- case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(recursiveClassPath)
- }
- }
+ def rootLoader: LazyType = new loaders.PackageLoader(ClassPath.RootPackage, classPath)
override def toString = "compiler mirror"
}
implicit val MirrorTag: ClassTag[Mirror] = ClassTag[Mirror](classOf[GlobalMirror])
@@ -102,14 +96,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
type ThisPlatform = JavaPlatform { val global: Global.this.type }
lazy val platform: ThisPlatform = new GlobalPlatform
- def classPath: ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => flatClassPath
- case ClassPathRepresentationType.Recursive => recursiveClassPath
- }
-
- private def recursiveClassPath: ClassPath[AbstractFile] = platform.classPath
-
- private def flatClassPath: FlatClassPath = platform.flatClassPath
+ def classPath: ClassPath = platform.classPath
// sub-components --------------------------------------------------
@@ -771,17 +758,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Extend classpath of `platform` and rescan updated packages. */
def extendCompilerClassPath(urls: URL*): Unit = {
- if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
- val urlClasspaths = urls.map(u => FlatClassPathFactory.newClassPath(AbstractFile.getURL(u), settings))
- val newClassPath = AggregateFlatClassPath.createAggregate(platform.flatClassPath +: urlClasspaths : _*)
- platform.currentFlatClassPath = Some(newClassPath)
- invalidateClassPathEntries(urls.map(_.getPath): _*)
- } else {
- val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls: _*)
- platform.currentClassPath = Some(newClassPath)
- // Reload all specified jars into this compiler instance
- invalidateClassPathEntries(urls.map(_.getPath): _*)
- }
+ val urlClasspaths = urls.map(u => ClassPathFactory.newClassPath(AbstractFile.getURL(u), settings))
+ val newClassPath = AggregateClassPath.createAggregate(platform.classPath +: urlClasspaths : _*)
+ platform.currentClassPath = Some(newClassPath)
+ invalidateClassPathEntries(urls.map(_.getPath): _*)
}
// ------------ Invalidations ---------------------------------
@@ -813,28 +793,26 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
* entries on the classpath.
*/
def invalidateClassPathEntries(paths: String*): Unit = {
- implicit object ClassPathOrdering extends Ordering[ClassFileLookup[AbstractFile]] {
- def compare(a:ClassFileLookup[AbstractFile], b:ClassFileLookup[AbstractFile]) = a.asClassPathString compare b.asClassPathString
+ implicit object ClassPathOrdering extends Ordering[ClassPath] {
+ def compare(a: ClassPath, b: ClassPath): Int = a.asClassPathString compareTo b.asClassPathString
}
val invalidated, failed = new mutable.ListBuffer[ClassSymbol]
- def assoc(path: String): Option[(ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile])] = {
- def origin(lookup: ClassFileLookup[AbstractFile]): Option[String] = lookup match {
- case cp: ClassPath[_] => cp.origin
+ def assoc(path: String): Option[(ClassPath, ClassPath)] = {
+ def origin(lookup: ClassPath): Option[String] = lookup match {
case cp: JFileDirectoryLookup[_] => Some(cp.dir.getPath)
case cp: ZipArchiveFileLookup[_] => Some(cp.zipFile.getPath)
case _ => None
}
- def entries(lookup: ClassFileLookup[AbstractFile]): Seq[ClassFileLookup[AbstractFile]] = lookup match {
- case cp: ClassPath[_] => cp.entries
- case cp: AggregateFlatClassPath => cp.aggregates
- case cp: FlatClassPath => Seq(cp)
+ def entries(lookup: ClassPath): Seq[ClassPath] = lookup match {
+ case cp: AggregateClassPath => cp.aggregates
+ case cp: ClassPath => Seq(cp)
}
val dir = AbstractFile.getDirectory(path) // if path is a `jar`, this is a FileZipArchive (isDirectory is true)
val canonical = dir.canonicalPath // this is the canonical path of the .jar
- def matchesCanonical(e: ClassFileLookup[AbstractFile]) = origin(e) match {
+ def matchesCanonical(e: ClassPath) = origin(e) match {
case Some(opath) =>
AbstractFile.getDirectory(opath).canonicalPath == canonical
case None =>
@@ -842,7 +820,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
entries(classPath) find matchesCanonical match {
case Some(oldEntry) =>
- Some(oldEntry -> ClassFileLookup.createForFile(dir, classPath, settings))
+ Some(oldEntry -> ClassPathFactory.newClassPath(dir, settings))
case None =>
error(s"Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath")
None
@@ -852,19 +830,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
if (subst.nonEmpty) {
platform updateClassPath subst
informProgress(s"classpath updated on entries [${subst.keys mkString ","}]")
- def mkClassPath(elems: Iterable[ClassFileLookup[AbstractFile]]): ClassFileLookup[AbstractFile] =
+ def mkClassPath(elems: Iterable[ClassPath]): ClassPath =
if (elems.size == 1) elems.head
- else ClassFileLookup.createAggregate(elems, classPath)
+ else AggregateClassPath.createAggregate(elems.toSeq: _*)
val oldEntries = mkClassPath(subst.keys)
val newEntries = mkClassPath(subst.values)
classPath match {
- case rcp: ClassPath[_] => mergeNewEntriesRecursive(
- newEntries.asInstanceOf[ClassPath[AbstractFile]], RootClass, Some(rcp), Some(oldEntries.asInstanceOf[ClassPath[AbstractFile]]),
- invalidated, failed)
-
- case fcp: FlatClassPath => mergeNewEntriesFlat(
+ case cp: ClassPath => mergeNewEntries(
RootClass, "",
- oldEntries.asInstanceOf[FlatClassPath], newEntries.asInstanceOf[FlatClassPath], fcp,
+ oldEntries, newEntries, cp,
invalidated, failed)
}
}
@@ -875,69 +849,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
show("could not invalidate system packages", failed)
}
- /** Merges new classpath entries into the symbol table
- *
- * @param newEntries The new classpath entries
- * @param root The root symbol to be resynced (a package class)
- * @param allEntries Optionally, the corresponding package in the complete current classpath
- * @param oldEntries Optionally, the corresponding package in the old classpath entries
- * @param invalidated A listbuffer collecting the invalidated package classes
- * @param failed A listbuffer collecting system package classes which could not be invalidated
- *
- * The merging strategy is determined by the absence or presence of classes and packages.
- *
- * If either oldEntries or newEntries contains classes, root is invalidated provided that a corresponding package
- * exists in allEntries. Otherwise it is removed.
- * Otherwise, the action is determined by the following matrix, with columns:
- *
- * old sym action
- * + + recurse into all child packages of newEntries
- * - + invalidate root
- * - - create and enter root
- *
- * Here, old means classpath, and sym means symboltable. + is presence of an entry in its column, - is absence.
- */
- private def mergeNewEntriesRecursive(newEntries: ClassPath[AbstractFile], root: ClassSymbol,
- allEntries: Option[ClassPath[AbstractFile]], oldEntries: Option[ClassPath[AbstractFile]],
- invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]) {
- ifDebug(informProgress(s"syncing $root, $oldEntries -> $newEntries"))
-
- val getPackageName: ClassPath[AbstractFile] => String = _.name
- def hasClasses(cp: Option[ClassPath[AbstractFile]]) = cp.isDefined && cp.get.classes.nonEmpty
- def invalidateOrRemove(root: ClassSymbol) = {
- allEntries match {
- case Some(cp) => root setInfo new loaders.PackageLoader(cp)
- case None => root.owner.info.decls unlink root.sourceModule
- }
- invalidated += root
- }
- def subPackage(cp: ClassPath[AbstractFile], name: String): Option[ClassPath[AbstractFile]] =
- cp.packages find (cp1 => getPackageName(cp1) == name)
-
- val classesFound = hasClasses(oldEntries) || newEntries.classes.nonEmpty
- if (classesFound && !isSystemPackageClass(root)) {
- invalidateOrRemove(root)
- } else {
- if (classesFound) {
- if (root.isRoot) invalidateOrRemove(EmptyPackageClass)
- else failed += root
- }
- if (oldEntries.isEmpty) invalidateOrRemove(root)
- else
- for (pstr <- newEntries.packages.map(getPackageName)) {
- val pname = newTermName(pstr)
- val pkg = (root.info decl pname) orElse {
- // package does not exist in symbol table, create symbol to track it
- assert(subPackage(oldEntries.get, pstr).isEmpty)
- loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get))
- }
- mergeNewEntriesRecursive(subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
- subPackage(allEntries.get, pstr), subPackage(oldEntries.get, pstr),
- invalidated, failed)
- }
- }
- }
-
/**
* Merges new classpath entries into the symbol table
*
@@ -956,20 +867,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
* Otherwise, sub-packages in newEntries are looked up in the symbol table (created if
* non-existent) and the merge function is called recursively.
*/
- private def mergeNewEntriesFlat(
- packageClass: ClassSymbol, fullPackageName: String,
- oldEntries: FlatClassPath, newEntries: FlatClassPath, fullClasspath: FlatClassPath,
- invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = {
+ private def mergeNewEntries(packageClass: ClassSymbol, fullPackageName: String,
+ oldEntries: ClassPath, newEntries: ClassPath, fullClasspath: ClassPath,
+ invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = {
ifDebug(informProgress(s"syncing $packageClass, $oldEntries -> $newEntries"))
- def packageExists(cp: FlatClassPath): Boolean = {
+ def packageExists(cp: ClassPath): Boolean = {
val (parent, _) = PackageNameUtils.separatePkgAndClassNames(fullPackageName)
cp.packages(parent).exists(_.name == fullPackageName)
}
def invalidateOrRemove(pkg: ClassSymbol) = {
if (packageExists(fullClasspath))
- pkg setInfo new loaders.PackageLoaderUsingFlatClassPath(fullPackageName, fullClasspath)
+ pkg setInfo new loaders.PackageLoader(fullPackageName, fullClasspath)
else
pkg.owner.info.decls unlink pkg.sourceModule
invalidated += pkg
@@ -987,9 +897,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val (_, subPackageName) = PackageNameUtils.separatePkgAndClassNames(p.name)
val subPackage = packageClass.info.decl(newTermName(subPackageName)) orElse {
// package does not exist in symbol table, create a new symbol
- loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoaderUsingFlatClassPath(p.name, fullClasspath))
+ loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoader(p.name, fullClasspath))
}
- mergeNewEntriesFlat(
+ mergeNewEntries(
subPackage.moduleClass.asClass, p.name,
oldEntries, newEntries, fullClasspath,
invalidated, failed)
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index bf93ad30bc..1f66657d8d 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -8,10 +8,8 @@ package tools.nsc
import io.{ AbstractFile, Directory, File, Path }
import java.io.IOException
-import scala.tools.nsc.classpath.DirectoryFlatClassPath
+import scala.tools.nsc.classpath.DirectoryClassPath
import scala.tools.nsc.reporters.{Reporter,ConsoleReporter}
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
import util.Exceptional.unwrap
/** An object that runs Scala code in script files.
@@ -115,10 +113,7 @@ class ScriptRunner extends HasCompileSocket {
}
def hasClassToRun(d: Directory): Boolean = {
- val cp = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Recursive => DefaultJavaContext.newClassPath(AbstractFile.getDirectory(d))
- case ClassPathRepresentationType.Flat => DirectoryFlatClassPath(d.jfile)
- }
+ val cp = DirectoryClassPath(d.jfile)
cp.findClass(mainClass).isDefined
}
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 0e2f059a36..dc63b335cc 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -7,11 +7,9 @@ package scala.tools.nsc
package backend
import io.AbstractFile
-import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath}
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.{ClassFileLookup, ClassPath, MergedClassPath}
-import scala.tools.util.FlatClassPathResolver
+import scala.tools.nsc.classpath.AggregateClassPath
import scala.tools.util.PathResolver
+import scala.tools.nsc.util.ClassPath
trait JavaPlatform extends Platform {
val global: Global
@@ -19,38 +17,20 @@ trait JavaPlatform extends Platform {
import global._
import definitions._
- private[nsc] var currentClassPath: Option[MergedClassPath[AbstractFile]] = None
-
- def classPath: ClassPath[AbstractFile] = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
- "To use recursive classpath representation you must enable it with -YclasspathImpl:recursive compiler option.")
+ private[nsc] var currentClassPath: Option[ClassPath] = None
+ private[nsc] def classPath: ClassPath = {
if (currentClassPath.isEmpty) currentClassPath = Some(new PathResolver(settings).result)
currentClassPath.get
}
- private[nsc] var currentFlatClassPath: Option[FlatClassPath] = None
-
- private[nsc] def flatClassPath: FlatClassPath = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
- "To use flat classpath representation you must enable it with -YclasspathImpl:flat compiler option.")
-
- if (currentFlatClassPath.isEmpty) currentFlatClassPath = Some(new FlatClassPathResolver(settings).result)
- currentFlatClassPath.get
- }
-
/** Update classpath with a substituted subentry */
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]]) = global.classPath match {
- case cp: ClassPath[AbstractFile] =>
- val s = subst.asInstanceOf[Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]]
- currentClassPath = Some(new MergedClassPath(cp.entries map (e => s.getOrElse(e, e)), cp.context))
-
- case AggregateFlatClassPath(entries) =>
- val s = subst.asInstanceOf[Map[FlatClassPath, FlatClassPath]]
- currentFlatClassPath = Some(AggregateFlatClassPath(entries map (e => s.getOrElse(e, e))))
+ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = global.classPath match {
+ case AggregateClassPath(entries) =>
+ currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e))))
- case cp: FlatClassPath =>
- currentFlatClassPath = Some(subst.getOrElse(cp, cp).asInstanceOf[FlatClassPath])
+ case cp: ClassPath =>
+ currentClassPath = Some(subst.getOrElse(cp, cp))
}
def platformPhases = List(
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index 369bcc44ed..e464768bb3 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -6,9 +6,8 @@
package scala.tools.nsc
package backend
-import util.{ClassFileLookup, ClassPath}
import io.AbstractFile
-import scala.tools.nsc.classpath.FlatClassPath
+import scala.tools.nsc.util.ClassPath
/** The platform dependent pieces of Global.
*/
@@ -16,14 +15,11 @@ trait Platform {
val symbolTable: symtab.SymbolTable
import symbolTable._
- /** The old, recursive implementation of compiler classpath. */
- def classPath: ClassPath[AbstractFile]
-
/** The new implementation of compiler classpath. */
- private[nsc] def flatClassPath: FlatClassPath
+ private[nsc] def classPath: ClassPath
/** Update classpath with a substitution that maps entries to entries */
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]])
+ def updateClassPath(subst: Map[ClassPath, ClassPath])
/** Any platform-specific phases. */
def platformPhases: List[SubComponent]
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
index 01206aa6eb..4287c24dc8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
@@ -42,15 +42,15 @@ object BackendReporting {
def assertionError(message: String): Nothing = throw new AssertionError(message)
implicit class RightBiasedEither[A, B](val v: Either[A, B]) extends AnyVal {
- def map[U](f: B => U) = v.right.map(f)
- def flatMap[BB](f: B => Either[A, BB]) = v.right.flatMap(f)
+ def map[C](f: B => C): Either[A, C] = v.right.map(f)
+ def flatMap[C](f: B => Either[A, C]): Either[A, C] = v.right.flatMap(f)
def withFilter(f: B => Boolean)(implicit empty: A): Either[A, B] = v match {
case Left(_) => v
case Right(e) => if (f(e)) v else Left(empty) // scalaz.\/ requires an implicit Monoid m to get m.empty
}
- def foreach[U](f: B => U) = v.right.foreach(f)
+ def foreach[U](f: B => U): Unit = v.right.foreach(f)
- def getOrElse[BB >: B](alt: => BB): BB = v.right.getOrElse(alt)
+ def getOrElse[C >: B](alt: => C): C = v.right.getOrElse(alt)
/**
* Get the value, fail with an assertion if this is an error.
@@ -101,11 +101,14 @@ object BackendReporting {
else ""
}
- case MethodNotFound(name, descriptor, ownerInternalName, missingClasses) =>
- val (javaDef, others) = missingClasses.partition(_.definedInJavaSource)
- s"The method $name$descriptor could not be found in the class $ownerInternalName or any of its parents." +
- (if (others.isEmpty) "" else others.map(_.internalName).mkString("\nNote that the following parent classes could not be found on the classpath: ", ", ", "")) +
- (if (javaDef.isEmpty) "" else javaDef.map(_.internalName).mkString("\nNote that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: ", ",", ""))
+ case MethodNotFound(name, descriptor, ownerInternalName, missingClass) =>
+ val missingClassWarning = missingClass match {
+ case None => ""
+ case Some(c) =>
+ if (c.definedInJavaSource) s"\nNote that the parent class ${c.internalName} is defined in a Java source (mixed compilation), no bytecode is available."
+ else s"\nNote that the parent class ${c.internalName} could not be found on the classpath."
+ }
+ s"The method $name$descriptor could not be found in the class $ownerInternalName or any of its parents." + missingClassWarning
case FieldNotFound(name, descriptor, ownerInternalName, missingClass) =>
s"The field node $name$descriptor could not be found because the classfile $ownerInternalName cannot be found on the classpath." +
@@ -127,7 +130,7 @@ object BackendReporting {
}
case class ClassNotFound(internalName: InternalName, definedInJavaSource: Boolean) extends MissingBytecodeWarning
- case class MethodNotFound(name: String, descriptor: String, ownerInternalNameOrArrayDescriptor: InternalName, missingClasses: List[ClassNotFound]) extends MissingBytecodeWarning {
+ case class MethodNotFound(name: String, descriptor: String, ownerInternalNameOrArrayDescriptor: InternalName, missingClass: Option[ClassNotFound]) extends MissingBytecodeWarning {
def isArrayMethod = ownerInternalNameOrArrayDescriptor.charAt(0) == '['
}
case class FieldNotFound(name: String, descriptor: String, ownerInternalName: InternalName, missingClass: Option[ClassNotFound]) extends MissingBytecodeWarning
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 0b53ea2fb1..1feca56923 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -107,6 +107,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val juHashMapRef : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
lazy val sbScalaBeanInfoRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
lazy val jliSerializedLambdaRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.SerializedLambda])
+ lazy val jliMethodHandleRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandle])
lazy val jliMethodHandlesRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandles])
lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
lazy val jliMethodTypeRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodType])
@@ -320,6 +321,7 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def jliCallSiteRef : ClassBType
def jliMethodTypeRef : ClassBType
def jliSerializedLambdaRef : ClassBType
+ def jliMethodHandleRef : ClassBType
def jliMethodHandlesLookupRef : ClassBType
def srBoxesRunTimeRef : ClassBType
def srBoxedUnitRef : ClassBType
@@ -383,6 +385,7 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def juHashMapRef : ClassBType = _coreBTypes.juHashMapRef
def sbScalaBeanInfoRef : ClassBType = _coreBTypes.sbScalaBeanInfoRef
def jliSerializedLambdaRef : ClassBType = _coreBTypes.jliSerializedLambdaRef
+ def jliMethodHandleRef : ClassBType = _coreBTypes.jliMethodHandleRef
def jliMethodHandlesRef : ClassBType = _coreBTypes.jliMethodHandlesRef
def jliMethodHandlesLookupRef : ClassBType = _coreBTypes.jliMethodHandlesLookupRef
def jliMethodTypeRef : ClassBType = _coreBTypes.jliMethodTypeRef
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
index eaf82f5c65..16590ec75c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
@@ -10,11 +10,10 @@ package opt
import scala.tools.asm
import asm.tree._
import scala.collection.JavaConverters._
-import scala.collection.concurrent
+import scala.collection.{concurrent, mutable}
import scala.tools.asm.Attribute
import scala.tools.nsc.backend.jvm.BackendReporting._
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.ClassFileLookup
+import scala.tools.nsc.util.ClassPath
import BytecodeUtils._
import ByteCodeRepository._
import BTypes.InternalName
@@ -26,7 +25,7 @@ import java.util.concurrent.atomic.AtomicLong
*
* @param classPath The compiler classpath where classfiles are searched and read from.
*/
-class ByteCodeRepository[BT <: BTypes](val classPath: ClassFileLookup[AbstractFile], val btypes: BT) {
+class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) {
import btypes._
/**
@@ -132,38 +131,135 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassFileLookup[AbstractFi
* The method node for a method matching `name` and `descriptor`, accessed in class `ownerInternalNameOrArrayDescriptor`.
* The declaration of the method may be in one of the parents.
*
- * TODO: make sure we always return the right method, the one being invoked. write tests.
- * - if there's an abstract and a concrete one. could possibly somehow the abstract be returned?
- * - with traits and default methods, if there is more than one default method inherited and
- * no override: what should be returned? We should not just inline one of the two.
+ * Note that the JVM spec performs method lookup in two steps: resolution and selection.
+ *
+ * Method resolution, defined in jvms-5.4.3.3 and jvms-5.4.3.4, is the first step and is identical
+ * for all invocation styles (virtual, interface, special, static). If C is the receiver class
+ * in the invocation instruction:
+ * 1 find a matching method (name and descriptor) in C
+ * 2 then in C's superclasses
+ * 3 then find the maximally-specific matching superinterface methods, succeed if there's a
+ * single non-abstract one. static and private methods in superinterfaces are not considered.
+ * 4 then pick a random non-static, non-private superinterface method.
+ * 5 then fail.
+ *
+ * Note that for an `invokestatic` instruction, a method reference `B.m` may resolve to `A.m`, if
+ * class `B` doesn't specify a matching method `m`, but the parent `A` does.
+ *
+ * Selection depends on the invocation style and is defined in jvms-6.5.
+ * - invokestatic: invokes the resolved method
+ * - invokevirtual / invokeinterface: searches for an override of the resolved method starting
+ * at the dynamic receiver type. the search procedure is basically the same as in resolution,
+ * but it fails at 4 instead of picking a superinterface method at random.
+ * - invokespecial: if C is the receiver in the invocation instruction, searches for an override
+ * of the resolved method starting at
+ * - the superclass of the current class, if C is a superclass of the current class
+ * - C otherwise
+ * again, the search procedure is the same.
+ *
+ * In the method here we implement method *resolution*. Whether or not the returned method is
+ * actually invoked at runtime depends on the invocation instruction and the class hierarchy, so
+ * the users (e.g. the inliner) have to be aware of method selection.
+ *
+ * Note that the returned method may be abstract (ACC_ABSTRACT), native (ACC_NATIVE) or signature
+ * polymorphic (methods `invoke` and `invokeExact` in class `MehtodHandles`).
*
* @return The [[MethodNode]] of the requested method and the [[InternalName]] of its declaring
- * class, or an error message if the method could not be found.
+ * class, or an error message if the method could not be found. An error message is also
+ * returned if method resolution results in multiple default methods.
*/
def methodNode(ownerInternalNameOrArrayDescriptor: String, name: String, descriptor: String): Either[MethodNotFound, (MethodNode, InternalName)] = {
- // on failure, returns a list of class names that could not be found on the classpath
- def methodNodeImpl(ownerInternalName: InternalName): Either[List[ClassNotFound], (MethodNode, InternalName)] = {
- classNode(ownerInternalName) match {
- case Left(e) => Left(List(e))
- case Right(c) =>
- c.methods.asScala.find(m => m.name == name && m.desc == descriptor) match {
- case Some(m) => Right((m, ownerInternalName))
- case None => findInParents(Option(c.superName) ++: c.interfaces.asScala.toList, Nil)
- }
+ def findMethod(c: ClassNode): Option[MethodNode] = c.methods.asScala.find(m => m.name == name && m.desc == descriptor)
+
+ // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9: "In Java SE 8, the only
+ // signature polymorphic methods are the invoke and invokeExact methods of the class MethodHandle.
+ def isSignaturePolymorphic(owner: InternalName) = owner == coreBTypes.jliMethodHandleRef.internalName && (name == "invoke" || name == "invokeExact")
+
+ // Note: if `owner` is an interface, in the first iteration we search for a matching member in the interface itself.
+ // If that fails, the recursive invocation checks in the superclass (which is Object) with `publicInstanceOnly == true`.
+ // This is specified in jvms-5.4.3.4: interface method resolution only returns public, non-static methods of Object.
+ def findInSuperClasses(owner: ClassNode, publicInstanceOnly: Boolean = false): Either[ClassNotFound, Option[(MethodNode, InternalName)]] = {
+ findMethod(owner) match {
+ case Some(m) if !publicInstanceOnly || (isPublicMethod(m) && !isStaticMethod(m)) => Right(Some((m, owner.name)))
+ case None =>
+ if (isSignaturePolymorphic(owner.name)) Right(Some((owner.methods.asScala.find(_.name == name).get, owner.name)))
+ else if (owner.superName == null) Right(None)
+ else classNode(owner.superName).flatMap(findInSuperClasses(_, isInterface(owner)))
}
}
- // find the MethodNode in one of the parent classes
- def findInParents(parents: List[InternalName], failedClasses: List[ClassNotFound]): Either[List[ClassNotFound], (MethodNode, InternalName)] = parents match {
- case x :: xs => methodNodeImpl(x).left.flatMap(failed => findInParents(xs, failed ::: failedClasses))
- case Nil => Left(failedClasses)
+ def findInInterfaces(initialOwner: ClassNode): Either[ClassNotFound, Option[(MethodNode, InternalName)]] = {
+ val visited = mutable.Set.empty[InternalName]
+ val found = mutable.ListBuffer.empty[(MethodNode, ClassNode)]
+
+ def findIn(owner: ClassNode): Option[ClassNotFound] = {
+ for (i <- owner.interfaces.asScala if !visited(i)) classNode(i) match {
+ case Left(e) => return Some(e)
+ case Right(c) =>
+ visited += i
+ // abstract and static methods are excluded, see jvms-5.4.3.3
+ for (m <- findMethod(c) if !isPrivateMethod(m) && !isStaticMethod(m)) found += ((m, c))
+ val recusionResult = findIn(c)
+ if (recusionResult.isDefined) return recusionResult
+ }
+ None
+ }
+
+ findIn(initialOwner)
+
+ val result =
+ if (found.size <= 1) found.headOption
+ else {
+ val maxSpecific = found.filterNot({
+ case (method, owner) =>
+ isAbstractMethod(method) || {
+ val ownerTp = classBTypeFromClassNode(owner)
+ found exists {
+ case (other, otherOwner) =>
+ (other ne method) && {
+ val otherTp = classBTypeFromClassNode(otherOwner)
+ otherTp.isSubtypeOf(ownerTp).get
+ }
+ }
+ }
+ })
+ // (*) note that if there's no single, non-abstract, maximally-specific method, the jvm
+ // method resolution (jvms-5.4.3.3) returns any of the non-private, non-static parent
+ // methods at random (abstract or concrete).
+ // we chose not to do this here, to prevent the inliner from potentially inlining the
+ // wrong method. in other words, we guarantee that a concrete method is only returned if
+ // it resolves deterministically.
+ // however, there may be multiple abstract methods inherited. in this case we *do* want
+ // to return a result to allow performing accessibility checks in the inliner. note that
+ // for accessibility it does not matter which of these methods is return, as they are all
+ // non-private (i.e., public, protected is not possible, jvms-4.1).
+ // the remaining case (when there's no max-specific method, but some non-abstract one)
+ // does not occur in bytecode generated by scalac or javac. we return no result in this
+ // case. this may at worst prevent some optimizations from happening.
+ if (maxSpecific.size == 1) maxSpecific.headOption
+ else if (found.forall(p => isAbstractMethod(p._1))) found.headOption // (*)
+ else None
+ }
+ Right(result.map(p => (p._1, p._2.name)))
}
// In a MethodInsnNode, the `owner` field may be an array descriptor, for example when invoking `clone`. We don't have a method node to return in this case.
- if (ownerInternalNameOrArrayDescriptor.charAt(0) == '[')
- Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, Nil))
- else
- methodNodeImpl(ownerInternalNameOrArrayDescriptor).left.map(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, _))
+ if (ownerInternalNameOrArrayDescriptor.charAt(0) == '[') {
+ Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, None))
+ } else {
+ def notFound(cnf: Option[ClassNotFound]) = Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, cnf))
+ val res: Either[ClassNotFound, Option[(MethodNode, InternalName)]] = classNode(ownerInternalNameOrArrayDescriptor).flatMap(c =>
+ findInSuperClasses(c) flatMap {
+ case None => findInInterfaces(c)
+ case res => Right(res)
+ }
+ )
+ res match {
+ case Left(e) => notFound(Some(e))
+ case Right(None) => notFound(None)
+ case Right(Some(res)) => Right(res)
+ }
+ }
}
private def parseClass(internalName: InternalName): Either[ClassNotFound, ClassNode] = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index f8c16e34bd..63906d80e5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -99,6 +99,10 @@ object BytecodeUtils {
methodNode.name == INSTANCE_CONSTRUCTOR_NAME || methodNode.name == CLASS_CONSTRUCTOR_NAME
}
+ def isPublicMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_PUBLIC) != 0
+
+ def isPrivateMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_PRIVATE) != 0
+
def isStaticMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_STATIC) != 0
def isAbstractMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_ABSTRACT) != 0
@@ -107,10 +111,12 @@ object BytecodeUtils {
def isNativeMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_NATIVE) != 0
- def hasCallerSensitiveAnnotation(methodNode: MethodNode) = methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.asScala.exists(_.desc == "Lsun/reflect/CallerSensitive;")
+ def hasCallerSensitiveAnnotation(methodNode: MethodNode): Boolean = methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.asScala.exists(_.desc == "Lsun/reflect/CallerSensitive;")
def isFinalClass(classNode: ClassNode): Boolean = (classNode.access & ACC_FINAL) != 0
+ def isInterface(classNode: ClassNode): Boolean = (classNode.access & ACC_INTERFACE) != 0
+
def isFinalMethod(methodNode: MethodNode): Boolean = (methodNode.access & (ACC_FINAL | ACC_PRIVATE | ACC_STATIC)) != 0
def isStrictfpMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_STRICT) != 0
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index 156c80d5a1..d241acf7b1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -131,19 +131,19 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
(method, declarationClass) <- byteCodeRepository.methodNode(call.owner, call.name, call.desc): Either[OptimizerWarning, (MethodNode, InternalName)]
(declarationClassNode, source) <- byteCodeRepository.classNodeAndSource(declarationClass): Either[OptimizerWarning, (ClassNode, Source)]
} yield {
- val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
- val info = analyzeCallsite(method, declarationClassBType, call, source)
- import info._
- Callee(
- callee = method,
- calleeDeclarationClass = declarationClassBType,
- safeToInline = safeToInline,
- canInlineFromSource = canInlineFromSource,
- annotatedInline = annotatedInline,
- annotatedNoInline = annotatedNoInline,
- samParamTypes = info.samParamTypes,
- calleeInfoWarning = warning)
- }
+ val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
+ val info = analyzeCallsite(method, declarationClassBType, call, source)
+ import info._
+ Callee(
+ callee = method,
+ calleeDeclarationClass = declarationClassBType,
+ safeToInline = safeToInline,
+ canInlineFromSource = canInlineFromSource,
+ annotatedInline = annotatedInline,
+ annotatedNoInline = annotatedNoInline,
+ samParamTypes = info.samParamTypes,
+ calleeInfoWarning = warning)
+ }
val argInfos = computeArgInfos(callee, call, prodCons)
@@ -388,12 +388,11 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
* @param calleeInfoWarning An inliner warning if some information was not available while
* gathering the information about this callee.
*/
- final case class Callee(
- callee: MethodNode, calleeDeclarationClass: btypes.ClassBType,
- safeToInline: Boolean, canInlineFromSource: Boolean,
- annotatedInline: Boolean, annotatedNoInline: Boolean,
- samParamTypes: IntMap[btypes.ClassBType],
- calleeInfoWarning: Option[CalleeInfoWarning]) {
+ final case class Callee(callee: MethodNode, calleeDeclarationClass: btypes.ClassBType,
+ safeToInline: Boolean, canInlineFromSource: Boolean,
+ annotatedInline: Boolean, annotatedNoInline: Boolean,
+ samParamTypes: IntMap[btypes.ClassBType],
+ calleeInfoWarning: Option[CalleeInfoWarning]) {
override def toString = s"Callee($calleeDeclarationClass.${callee.name})"
}
diff --git a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
index f97d97548e..6b435542a3 100644
--- a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
@@ -12,15 +12,16 @@ import scala.tools.nsc.util.ClassRepresentation
/**
* A classpath unifying multiple class- and sourcepath entries.
- * Flat classpath can obtain entries for classes and sources independently
+ * The Classpath can obtain entries for classes and sources independently
* so it tries to do operations quite optimally - iterating only these collections
* which are needed in the given moment and only as far as it's necessary.
+ *
* @param aggregates classpath instances containing entries which this class processes
*/
-case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatClassPath {
+case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
override def findClassFile(className: String): Option[AbstractFile] = {
@tailrec
- def find(aggregates: Seq[FlatClassPath]): Option[AbstractFile] =
+ def find(aggregates: Seq[ClassPath]): Option[AbstractFile] =
if (aggregates.nonEmpty) {
val classFile = aggregates.head.findClassFile(className)
if (classFile.isDefined) classFile
@@ -30,22 +31,24 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
find(aggregates)
}
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
- val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
-
+ override def findClass(className: String): Option[ClassRepresentation] = {
@tailrec
- def findEntry[T <: ClassRepClassPathEntry](aggregates: Seq[FlatClassPath], getEntries: FlatClassPath => Seq[T]): Option[T] =
+ def findEntry(aggregates: Seq[ClassPath], isSource: Boolean): Option[ClassRepresentation] =
if (aggregates.nonEmpty) {
- val entry = getEntries(aggregates.head).find(_.name == simpleClassName)
+ val entry = aggregates.head.findClass(className) match {
+ case s @ Some(_: SourceFileEntry) if isSource => s
+ case s @ Some(_: ClassFileEntry) if !isSource => s
+ case _ => None
+ }
if (entry.isDefined) entry
- else findEntry(aggregates.tail, getEntries)
+ else findEntry(aggregates.tail, isSource)
} else None
- val classEntry = findEntry(aggregates, classesGetter(pkg))
- val sourceEntry = findEntry(aggregates, sourcesGetter(pkg))
+ val classEntry = findEntry(aggregates, isSource = false)
+ val sourceEntry = findEntry(aggregates, isSource = true)
(classEntry, sourceEntry) match {
- case (Some(c), Some(s)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
+ case (Some(c: ClassFileEntry), Some(s: SourceFileEntry)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
case (c @ Some(_), _) => c
case (_, s) => s
}
@@ -63,16 +66,16 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
}
override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] =
- getDistinctEntries(classesGetter(inPackage))
+ getDistinctEntries(_.classes(inPackage))
override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] =
- getDistinctEntries(sourcesGetter(inPackage))
+ getDistinctEntries(_.sources(inPackage))
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ override private[nsc] def list(inPackage: String): ClassPathEntries = {
val (packages, classesAndSources) = aggregates.map(_.list(inPackage)).unzip
val distinctPackages = packages.flatten.distinct
val distinctClassesAndSources = mergeClassesAndSources(classesAndSources: _*)
- FlatClassPathEntries(distinctPackages, distinctClassesAndSources)
+ ClassPathEntries(distinctPackages, distinctClassesAndSources)
}
/**
@@ -80,11 +83,11 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
* creates an entry containing both of them. If there would be more than one class or source
* entries for the same class it always would use the first entry of each type found on a classpath.
*/
- private def mergeClassesAndSources(entries: Seq[ClassRepClassPathEntry]*): Seq[ClassRepClassPathEntry] = {
+ private def mergeClassesAndSources(entries: Seq[ClassRepresentation]*): Seq[ClassRepresentation] = {
// based on the implementation from MergedClassPath
var count = 0
val indices = collection.mutable.HashMap[String, Int]()
- val mergedEntries = new ArrayBuffer[ClassRepClassPathEntry](1024)
+ val mergedEntries = new ArrayBuffer[ClassRepresentation](1024)
for {
partOfEntries <- entries
@@ -109,7 +112,7 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
mergedEntries.toIndexedSeq
}
- private def getDistinctEntries[EntryType <: ClassRepClassPathEntry](getEntries: FlatClassPath => Seq[EntryType]): Seq[EntryType] = {
+ private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Seq[EntryType]): Seq[EntryType] = {
val seenNames = collection.mutable.HashSet[String]()
val entriesBuffer = new ArrayBuffer[EntryType](1024)
for {
@@ -121,19 +124,16 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
}
entriesBuffer.toIndexedSeq
}
-
- private def classesGetter(pkg: String) = (cp: FlatClassPath) => cp.classes(pkg)
- private def sourcesGetter(pkg: String) = (cp: FlatClassPath) => cp.sources(pkg)
}
-object AggregateFlatClassPath {
- def createAggregate(parts: FlatClassPath*): FlatClassPath = {
- val elems = new ArrayBuffer[FlatClassPath]()
+object AggregateClassPath {
+ def createAggregate(parts: ClassPath*): ClassPath = {
+ val elems = new ArrayBuffer[ClassPath]()
parts foreach {
- case AggregateFlatClassPath(ps) => elems ++= ps
+ case AggregateClassPath(ps) => elems ++= ps
case p => elems += p
}
if (elems.size == 1) elems.head
- else AggregateFlatClassPath(elems.toIndexedSeq)
+ else AggregateClassPath(elems.toIndexedSeq)
}
}
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPath.scala b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala
new file mode 100644
index 0000000000..08bd98b1d8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import scala.reflect.io.AbstractFile
+import scala.tools.nsc.util.ClassRepresentation
+
+case class ClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepresentation])
+
+object ClassPathEntries {
+ import scala.language.implicitConversions
+ // to have working unzip method
+ implicit def entry2Tuple(entry: ClassPathEntries): (Seq[PackageEntry], Seq[ClassRepresentation]) = (entry.packages, entry.classesAndSources)
+}
+
+trait ClassFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait SourceFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait PackageEntry {
+ def name: String
+}
+
+private[nsc] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry {
+ override def name = FileUtils.stripClassExtension(file.name) // class name
+
+ override def binary: Option[AbstractFile] = Some(file)
+ override def source: Option[AbstractFile] = None
+}
+
+private[nsc] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry {
+ override def name = FileUtils.stripSourceExtension(file.name)
+
+ override def binary: Option[AbstractFile] = None
+ override def source: Option[AbstractFile] = Some(file)
+}
+
+private[nsc] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepresentation {
+ override def name = FileUtils.stripClassExtension(classFile.name)
+
+ override def binary: Option[AbstractFile] = Some(classFile)
+ override def source: Option[AbstractFile] = Some(srcFile)
+}
+
+private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry
+
+private[nsc] trait NoSourcePaths {
+ def asSourcePathString: String = ""
+ private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty
+}
+
+private[nsc] trait NoClassPaths {
+ def findClassFile(className: String): Option[AbstractFile] = None
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty
+}
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
index 9bf4e3f779..3a29f1ba11 100644
--- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
@@ -3,47 +3,49 @@
*/
package scala.tools.nsc.classpath
-import scala.reflect.io.AbstractFile
+import scala.reflect.io.{AbstractFile, VirtualDirectory}
+import scala.tools.nsc.Settings
+import FileUtils.AbstractFileOps
import scala.tools.nsc.util.ClassPath
/**
- * A trait that contains factory methods for classpath elements of type T.
- *
- * The logic has been abstracted from ClassPath#ClassPathContext so it's possible
- * to have common trait that supports both recursive and flat classpath representations.
- *
- * Therefore, we expect that T will be either ClassPath[U] or FlatClassPath.
+ * Provides factory methods for classpath. When creating classpath instances for a given path,
+ * it uses proper type of classpath depending on a types of particular files containing sources or classes.
*/
-trait ClassPathFactory[T] {
-
+class ClassPathFactory(settings: Settings) {
/**
- * Create a new classpath based on the abstract file.
- */
- def newClassPath(file: AbstractFile): T
+ * Create a new classpath based on the abstract file.
+ */
+ def newClassPath(file: AbstractFile): ClassPath = ClassPathFactory.newClassPath(file, settings)
/**
- * Creators for sub classpaths which preserve this context.
- */
- def sourcesInPath(path: String): List[T]
+ * Creators for sub classpaths which preserve this context.
+ */
+ def sourcesInPath(path: String): List[ClassPath] =
+ for {
+ file <- expandPath(path, expandStar = false)
+ dir <- Option(AbstractFile getDirectory file)
+ } yield createSourcePath(dir)
+
- def expandPath(path: String, expandStar: Boolean = true): List[String] = ClassPath.expandPath(path, expandStar)
+ def expandPath(path: String, expandStar: Boolean = true): List[String] = scala.tools.nsc.util.ClassPath.expandPath(path, expandStar)
- def expandDir(extdir: String): List[String] = ClassPath.expandDir(extdir)
+ def expandDir(extdir: String): List[String] = scala.tools.nsc.util.ClassPath.expandDir(extdir)
- def contentsOfDirsInPath(path: String): List[T] =
+ def contentsOfDirsInPath(path: String): List[ClassPath] =
for {
dir <- expandPath(path, expandStar = false)
name <- expandDir(dir)
entry <- Option(AbstractFile.getDirectory(name))
} yield newClassPath(entry)
- def classesInExpandedPath(path: String): IndexedSeq[T] =
+ def classesInExpandedPath(path: String): IndexedSeq[ClassPath] =
classesInPathImpl(path, expand = true).toIndexedSeq
def classesInPath(path: String) = classesInPathImpl(path, expand = false)
def classesInManifest(useManifestClassPath: Boolean) =
- if (useManifestClassPath) ClassPath.manifests.map(url => newClassPath(AbstractFile getResources url))
+ if (useManifestClassPath) scala.tools.nsc.util.ClassPath.manifests.map(url => newClassPath(AbstractFile getResources url))
else Nil
// Internal
@@ -52,4 +54,25 @@ trait ClassPathFactory[T] {
file <- expandPath(path, expand)
dir <- Option(AbstractFile.getDirectory(file))
} yield newClassPath(dir)
+
+ private def createSourcePath(file: AbstractFile): ClassPath =
+ if (file.isJarOrZip)
+ ZipAndJarSourcePathFactory.create(file, settings)
+ else if (file.isDirectory)
+ new DirectorySourcePath(file.file)
+ else
+ sys.error(s"Unsupported sourcepath element: $file")
+}
+
+object ClassPathFactory {
+ def newClassPath(file: AbstractFile, settings: Settings): ClassPath = file match {
+ case vd: VirtualDirectory => VirtualDirectoryClassPath(vd)
+ case _ =>
+ if (file.isJarOrZip)
+ ZipAndJarClassPathFactory.create(file, settings)
+ else if (file.isDirectory)
+ new DirectoryClassPath(file.file)
+ else
+ sys.error(s"Unsupported classpath element: $file")
+ }
}
diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
index e3964dfa78..aba941e043 100644
--- a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
@@ -5,9 +5,8 @@ package scala.tools.nsc.classpath
import java.io.File
import java.net.URL
-import scala.reflect.io.AbstractFile
-import scala.reflect.io.PlainFile
-import scala.tools.nsc.util.ClassRepresentation
+import scala.reflect.io.{AbstractFile, PlainFile}
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
import FileUtils._
/**
@@ -17,7 +16,7 @@ import FileUtils._
* when we have a name of a package.
* It abstracts over the file representation to work with both JFile and AbstractFile.
*/
-trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
+trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
type F
val dir: F
@@ -33,7 +32,7 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
protected def isMatchingFile(f: F): Boolean
private def getDirectory(forPackage: String): Option[F] = {
- if (forPackage == FlatClassPath.RootPackage) {
+ if (forPackage == ClassPath.RootPackage) {
Some(dir)
} else {
val packageDirName = FileUtils.dirPath(forPackage)
@@ -60,7 +59,7 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
files.map(f => createFileEntry(toAbstractFile(f)))
}
- private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ private[nsc] def list(inPackage: String): ClassPathEntries = {
val dirForPackage = getDirectory(inPackage)
val files: Array[F] = dirForPackage match {
case None => emptyFiles
@@ -75,11 +74,11 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
else if (isMatchingFile(file))
fileBuf += createFileEntry(toAbstractFile(file))
}
- FlatClassPathEntries(packageBuf, fileBuf)
+ ClassPathEntries(packageBuf, fileBuf)
}
}
-trait JFileDirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends DirectoryLookup[FileEntryType] {
+trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends DirectoryLookup[FileEntryType] {
type F = File
protected def emptyFiles: Array[File] = Array.empty
@@ -102,8 +101,8 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends Dire
def asClassPathStrings: Seq[String] = Seq(dir.getPath)
}
-case class DirectoryFlatClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
+case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
def findClassFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
@@ -121,13 +120,13 @@ case class DirectoryFlatClassPath(dir: File) extends JFileDirectoryLookup[ClassF
private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
}
-case class DirectoryFlatSourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
+case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
def asSourcePathString: String = asClassPathString
protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
protected def isMatchingFile(f: File): Boolean = endsScalaOrJava(f.getName)
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findSourceFile(className) map SourceFileEntryImpl
+ override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl
private def findSourceFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
deleted file mode 100644
index e95ffe02e3..0000000000
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.classpath
-
-import scala.reflect.io.AbstractFile
-import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, ClassRepresentation }
-
-/**
- * A base trait for the particular flat classpath representation implementations.
- *
- * We call this variant of a classpath representation flat because it's possible to
- * query the whole classpath using just single instance extending this trait.
- *
- * This is an alternative design compared to scala.tools.nsc.util.ClassPath
- */
-trait FlatClassPath extends ClassFileLookup[AbstractFile] {
- /** Empty string represents root package */
- private[nsc] def packages(inPackage: String): Seq[PackageEntry]
- private[nsc] def classes(inPackage: String): Seq[ClassFileEntry]
- private[nsc] def sources(inPackage: String): Seq[SourceFileEntry]
-
- /** Allows to get entries for packages and classes merged with sources possibly in one pass. */
- private[nsc] def list(inPackage: String): FlatClassPathEntries
-
- // A default implementation which should be overridden, if we can create the more efficient
- // solution for a given type of FlatClassPath
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
- val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
-
- val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
- def findClassInSources = sources(pkg).find(_.name == simpleClassName)
-
- foundClassFromClassFiles orElse findClassInSources
- }
-
- override def asClassPathString: String = ClassPath.join(asClassPathStrings: _*)
- def asClassPathStrings: Seq[String]
-}
-
-object FlatClassPath {
- val RootPackage = ""
-}
-
-case class FlatClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepClassPathEntry])
-
-object FlatClassPathEntries {
- import scala.language.implicitConversions
- // to have working unzip method
- implicit def entry2Tuple(entry: FlatClassPathEntries): (Seq[PackageEntry], Seq[ClassRepClassPathEntry]) = (entry.packages, entry.classesAndSources)
-}
-
-sealed trait ClassRepClassPathEntry extends ClassRepresentation[AbstractFile]
-
-trait ClassFileEntry extends ClassRepClassPathEntry {
- def file: AbstractFile
-}
-
-trait SourceFileEntry extends ClassRepClassPathEntry {
- def file: AbstractFile
-}
-
-trait PackageEntry {
- def name: String
-}
-
-private[nsc] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry {
- override def name = FileUtils.stripClassExtension(file.name) // class name
-
- override def binary: Option[AbstractFile] = Some(file)
- override def source: Option[AbstractFile] = None
-}
-
-private[nsc] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry {
- override def name = FileUtils.stripSourceExtension(file.name)
-
- override def binary: Option[AbstractFile] = None
- override def source: Option[AbstractFile] = Some(file)
-}
-
-private[nsc] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepClassPathEntry {
- override def name = FileUtils.stripClassExtension(classFile.name)
-
- override def binary: Option[AbstractFile] = Some(classFile)
- override def source: Option[AbstractFile] = Some(srcFile)
-}
-
-private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry
-
-private[nsc] trait NoSourcePaths {
- def asSourcePathString: String = ""
- private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty
-}
-
-private[nsc] trait NoClassPaths {
- def findClassFile(className: String): Option[AbstractFile] = None
- private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty
-}
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
deleted file mode 100644
index 463301696e..0000000000
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.classpath
-
-import scala.reflect.io.VirtualDirectory
-import scala.tools.nsc.Settings
-import scala.tools.nsc.io.AbstractFile
-import FileUtils.AbstractFileOps
-
-/**
- * Provides factory methods for flat classpath. When creating classpath instances for a given path,
- * it uses proper type of classpath depending on a types of particular files containing sources or classes.
- */
-class FlatClassPathFactory(settings: Settings) extends ClassPathFactory[FlatClassPath] {
- def newClassPath(file: AbstractFile): FlatClassPath = FlatClassPathFactory.newClassPath(file, settings)
-
- def sourcesInPath(path: String): List[FlatClassPath] =
- for {
- file <- expandPath(path, expandStar = false)
- dir <- Option(AbstractFile getDirectory file)
- } yield createSourcePath(dir)
-
- private def createSourcePath(file: AbstractFile): FlatClassPath =
- if (file.isJarOrZip)
- ZipAndJarFlatSourcePathFactory.create(file, settings)
- else if (file.isDirectory)
- new DirectoryFlatSourcePath(file.file)
- else
- sys.error(s"Unsupported sourcepath element: $file")
-}
-
-object FlatClassPathFactory {
- def newClassPath(file: AbstractFile, settings: Settings): FlatClassPath = file match {
- case vd: VirtualDirectory => VirtualDirectoryFlatClassPath(vd)
- case _ =>
- if (file.isJarOrZip)
- ZipAndJarFlatClassPathFactory.create(file, settings)
- else if (file.isDirectory)
- new DirectoryFlatClassPath(file.file)
- else
- sys.error(s"Unsupported classpath element: $file")
- }
-}
diff --git a/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
index c907d565d2..39b0d78135 100644
--- a/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
+++ b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
@@ -3,7 +3,7 @@
*/
package scala.tools.nsc.classpath
-import scala.tools.nsc.classpath.FlatClassPath.RootPackage
+import scala.tools.nsc.util.ClassPath.RootPackage
/**
* Common methods related to package names represented as String
diff --git a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala
index 06cdab583c..8df0c3743d 100644
--- a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala
@@ -4,8 +4,9 @@ import scala.tools.nsc.util.ClassRepresentation
import scala.reflect.io.{Path, PlainFile, VirtualDirectory, AbstractFile}
import FileUtils._
import java.net.URL
+import scala.tools.nsc.util.ClassPath
-case class VirtualDirectoryFlatClassPath(dir: VirtualDirectory) extends FlatClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
type F = AbstractFile
protected def emptyFiles: Array[AbstractFile] = Array.empty
@@ -23,7 +24,7 @@ case class VirtualDirectoryFlatClassPath(dir: VirtualDirectory) extends FlatClas
def asURLs: Seq[URL] = Seq(new URL(dir.name))
def asClassPathStrings: Seq[String] = Seq(dir.path)
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
def findClassFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
index 6ec3805d8b..fe74e5f874 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
@@ -6,7 +6,8 @@ package scala.tools.nsc.classpath
import java.io.File
import java.net.URL
import scala.annotation.tailrec
-import scala.reflect.io.{ AbstractFile, FileZipArchive, ManifestResources }
+import scala.reflect.io.{AbstractFile, FileZipArchive, ManifestResources}
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.Settings
import FileUtils._
@@ -19,16 +20,16 @@ import FileUtils._
* when there are a lot of projects having a lot of common dependencies.
*/
sealed trait ZipAndJarFileLookupFactory {
- private val cache = collection.mutable.Map.empty[AbstractFile, FlatClassPath]
+ private val cache = collection.mutable.Map.empty[AbstractFile, ClassPath]
- def create(zipFile: AbstractFile, settings: Settings): FlatClassPath = {
+ def create(zipFile: AbstractFile, settings: Settings): ClassPath = {
if (settings.YdisableFlatCpCaching) createForZipFile(zipFile)
else createUsingCache(zipFile, settings)
}
- protected def createForZipFile(zipFile: AbstractFile): FlatClassPath
+ protected def createForZipFile(zipFile: AbstractFile): ClassPath
- private def createUsingCache(zipFile: AbstractFile, settings: Settings): FlatClassPath = cache.synchronized {
+ private def createUsingCache(zipFile: AbstractFile, settings: Settings): ClassPath = cache.synchronized {
def newClassPathInstance = {
if (settings.verbose || settings.Ylogcp)
println(s"$zipFile is not yet in the classpath cache")
@@ -39,11 +40,11 @@ sealed trait ZipAndJarFileLookupFactory {
}
/**
- * Manages creation of flat classpath for class files placed in zip and jar files.
+ * Manages creation of classpath for class files placed in zip and jar files.
* It should be the only way of creating them as it provides caching.
*/
-object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
- private case class ZipArchiveFlatClassPath(zipFile: File)
+object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveClassPath(zipFile: File)
extends ZipArchiveFileLookup[ClassFileEntryImpl]
with NoSourcePaths {
@@ -65,7 +66,7 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
* with a particularly prepared scala-library.jar. It should have all classes listed in the manifest like e.g. this entry:
* Name: scala/Function2$mcFJD$sp.class
*/
- private case class ManifestResourcesFlatClassPath(file: ManifestResources) extends FlatClassPath with NoSourcePaths {
+ private case class ManifestResourcesClassPath(file: ManifestResources) extends ClassPath with NoSourcePaths {
override def findClassFile(className: String): Option[AbstractFile] = {
val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
classes(pkg).find(_.name == simpleClassName).map(_.file)
@@ -75,8 +76,8 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
override def asURLs: Seq[URL] = file.toURLs()
- import ManifestResourcesFlatClassPath.PackageFileInfo
- import ManifestResourcesFlatClassPath.PackageInfo
+ import ManifestResourcesClassPath.PackageFileInfo
+ import ManifestResourcesClassPath.PackageInfo
/**
* A cache mapping package name to abstract file for package directory and subpackages of given package.
@@ -114,8 +115,8 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
}
val subpackages = getSubpackages(file)
- packages.put(FlatClassPath.RootPackage, PackageFileInfo(file, subpackages))
- traverse(FlatClassPath.RootPackage, subpackages, collection.mutable.Queue())
+ packages.put(ClassPath.RootPackage, PackageFileInfo(file, subpackages))
+ traverse(ClassPath.RootPackage, subpackages, collection.mutable.Queue())
packages
}
@@ -132,21 +133,21 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
(for (file <- pkg if file.isClass) yield ClassFileEntryImpl(file))(collection.breakOut)
}
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(packages(inPackage), classes(inPackage))
+ override private[nsc] def list(inPackage: String): ClassPathEntries = ClassPathEntries(packages(inPackage), classes(inPackage))
}
- private object ManifestResourcesFlatClassPath {
+ private object ManifestResourcesClassPath {
case class PackageFileInfo(packageFile: AbstractFile, subpackages: Seq[AbstractFile])
case class PackageInfo(packageName: String, subpackages: List[AbstractFile])
}
- override protected def createForZipFile(zipFile: AbstractFile): FlatClassPath =
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath =
if (zipFile.file == null) createWithoutUnderlyingFile(zipFile)
- else ZipArchiveFlatClassPath(zipFile.file)
+ else ZipArchiveClassPath(zipFile.file)
private def createWithoutUnderlyingFile(zipFile: AbstractFile) = zipFile match {
case manifestRes: ManifestResources =>
- ManifestResourcesFlatClassPath(manifestRes)
+ ManifestResourcesClassPath(manifestRes)
case _ =>
val errorMsg = s"Abstract files which don't have an underlying file and are not ManifestResources are not supported. There was $zipFile"
throw new IllegalArgumentException(errorMsg)
@@ -154,11 +155,11 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
}
/**
- * Manages creation of flat classpath for source files placed in zip and jar files.
+ * Manages creation of classpath for source files placed in zip and jar files.
* It should be the only way of creating them as it provides caching.
*/
-object ZipAndJarFlatSourcePathFactory extends ZipAndJarFileLookupFactory {
- private case class ZipArchiveFlatSourcePath(zipFile: File)
+object ZipAndJarSourcePathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveSourcePath(zipFile: File)
extends ZipArchiveFileLookup[SourceFileEntryImpl]
with NoClassPaths {
@@ -170,5 +171,5 @@ object ZipAndJarFlatSourcePathFactory extends ZipAndJarFileLookupFactory {
override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isScalaOrJavaSource
}
- override protected def createForZipFile(zipFile: AbstractFile): FlatClassPath = ZipArchiveFlatSourcePath(zipFile.file)
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath = ZipArchiveSourcePath(zipFile.file)
}
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
index a24d989306..9c147cf8cc 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
@@ -9,13 +9,14 @@ import scala.collection.Seq
import scala.reflect.io.AbstractFile
import scala.reflect.io.FileZipArchive
import FileUtils.AbstractFileOps
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
/**
* A trait allowing to look for classpath entries of given type in zip and jar files.
* It provides common logic for classes handling class and source files.
* It's aware of things like e.g. META-INF directory which is correctly skipped.
*/
-trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
+trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
val zipFile: File
assert(zipFile != null, "Zip file in ZipArchiveFileLookup cannot be null")
@@ -39,7 +40,7 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends Flat
entry <- dirEntry.iterator if isRequiredFileType(entry)
} yield createFileEntry(entry)
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ override private[nsc] def list(inPackage: String): ClassPathEntries = {
val foundDirEntry = findDirEntry(inPackage)
foundDirEntry map { dirEntry =>
@@ -53,8 +54,8 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends Flat
else if (isRequiredFileType(entry))
fileBuf += createFileEntry(entry)
}
- FlatClassPathEntries(pkgBuf, fileBuf)
- } getOrElse FlatClassPathEntries(Seq.empty, Seq.empty)
+ ClassPathEntries(pkgBuf, fileBuf)
+ } getOrElse ClassPathEntries(Seq.empty, Seq.empty)
}
private def findDirEntry(pkg: String): Option[archive.DirEntry] = {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 7b98011759..9a0d86a94d 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -200,7 +200,6 @@ trait ScalaSettings extends AbsScalaSettings
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overridden methods.")
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
- val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Flat)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
@@ -389,8 +388,3 @@ trait ScalaSettings extends AbsScalaSettings
None
}
}
-
-object ClassPathRepresentationType {
- val Flat = "flat"
- val Recursive = "recursive"
-}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 4f5589fd7c..b36d5d4ef1 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -10,10 +10,8 @@ import classfile.ClassfileParser
import java.io.IOException
import scala.reflect.internal.MissingRequirementError
import scala.reflect.internal.util.Statistics
-import scala.reflect.io.{ AbstractFile, NoAbstractFile }
-import scala.tools.nsc.classpath.FlatClassPath
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.{ ClassPath, ClassRepresentation }
+import scala.reflect.io.{AbstractFile, NoAbstractFile}
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
/** This class ...
*
@@ -154,7 +152,7 @@ abstract class SymbolLoaders {
/** Initialize toplevel class and module symbols in `owner` from class path representation `classRep`
*/
- def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation[AbstractFile]) {
+ def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation) {
((classRep.binary, classRep.source) : @unchecked) match {
case (Some(bin), Some(src))
if platform.needCompile(bin, src) && !binaryOnly(owner, classRep.name) =>
@@ -247,41 +245,11 @@ abstract class SymbolLoaders {
}
/**
- * Load contents of a package
- */
- class PackageLoader(classpath: ClassPath[AbstractFile]) extends SymbolLoader with FlagAgnosticCompleter {
- protected def description = s"package loader ${classpath.name}"
-
- protected def doComplete(root: Symbol) {
- assert(root.isPackageClass, root)
- // Time travel to a phase before refchecks avoids an initialization issue. `openPackageModule`
- // creates a module symbol and invokes invokes `companionModule` while the `infos` field is
- // still null. This calls `isModuleNotMethod`, which forces the `info` if run after refchecks.
- enteringPhase(phaseBeforeRefchecks) {
- root.setInfo(new PackageClassInfoType(newScope, root))
-
- if (!root.isRoot) {
- for (classRep <- classpath.classes) {
- initializeFromClassPath(root, classRep)
- }
- }
- if (!root.isEmptyPackageClass) {
- for (pkg <- classpath.packages) {
- enterPackage(root, pkg.name, new PackageLoader(pkg))
- }
-
- openPackageModule(root)
- }
- }
- }
- }
-
- /**
* Loads contents of a package
*/
- class PackageLoaderUsingFlatClassPath(packageName: String, classPath: FlatClassPath) extends SymbolLoader with FlagAgnosticCompleter {
+ class PackageLoader(packageName: String, classPath: ClassPath) extends SymbolLoader with FlagAgnosticCompleter {
protected def description = {
- val shownPackageName = if (packageName == FlatClassPath.RootPackage) "<root package>" else packageName
+ val shownPackageName = if (packageName == ClassPath.RootPackage) "<root package>" else packageName
s"package loader $shownPackageName"
}
@@ -298,9 +266,9 @@ abstract class SymbolLoaders {
val fullName = pkg.name
val name =
- if (packageName == FlatClassPath.RootPackage) fullName
+ if (packageName == ClassPath.RootPackage) fullName
else fullName.substring(packageName.length + 1)
- val packageLoader = new PackageLoaderUsingFlatClassPath(fullName, classPath)
+ val packageLoader = new PackageLoader(fullName, classPath)
enterPackage(root, name, packageLoader)
}
@@ -329,10 +297,7 @@ abstract class SymbolLoaders {
val loaders = SymbolLoaders.this.asInstanceOf[SymbolLoadersRefined]
- override def classFileLookup: util.ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Recursive => platform.classPath
- case ClassPathRepresentationType.Flat => platform.flatClassPath
- }
+ override def classPath: ClassPath = platform.classPath
}
protected def description = "class file "+ classfile.toString
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index fffd48d145..0533d420cd 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -8,16 +8,16 @@ package tools.nsc
package symtab
package classfile
-import java.io.{ File, IOException }
+import java.io.{File, IOException}
import java.lang.Integer.toHexString
-import scala.collection.{ mutable, immutable }
-import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
+import scala.collection.{immutable, mutable}
+import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.annotation.switch
-import scala.reflect.internal.{ JavaAccFlags }
-import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs}
+import scala.reflect.internal.JavaAccFlags
+import scala.reflect.internal.pickling.{ByteCodecs, PickleBuffer}
import scala.reflect.io.NoAbstractFile
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.ClassFileLookup
/** This abstract class implements a class file parser.
*
@@ -43,8 +43,8 @@ abstract class ClassfileParser {
*/
protected def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol
- /** The way of the class file lookup used by the compiler. */
- def classFileLookup: ClassFileLookup[AbstractFile]
+ /** The compiler classpath. */
+ def classPath: ClassPath
import definitions._
import scala.reflect.internal.ClassfileConstants._
@@ -357,7 +357,7 @@ abstract class ClassfileParser {
}
private def loadClassSymbol(name: Name): Symbol = {
- val file = classFileLookup findClassFile name.toString getOrElse {
+ val file = classPath findClassFile name.toString getOrElse {
// SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
// therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
// that are not in their correct place (see bug for details)
@@ -1079,7 +1079,7 @@ abstract class ClassfileParser {
for (entry <- innerClasses.entries) {
// create a new class member for immediate inner classes
if (entry.outerName == currentClass) {
- val file = classFileLookup.findClassFile(entry.externalName.toString)
+ val file = classPath.findClassFile(entry.externalName.toString)
enterClassAndModule(entry, file.getOrElse(NoAbstractFile))
}
}
diff --git a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala b/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
deleted file mode 100644
index 5d8831a607..0000000000
--- a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.util
-
-import scala.tools.nsc.Settings
-import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath, FlatClassPathFactory}
-import scala.tools.nsc.io.AbstractFile
-import java.net.URL
-
-/**
- * Simple interface that allows us to abstract over how class file lookup is performed
- * in different classpath representations.
- */
-// TODO at the end, after the possible removal of the old classpath representation, this class shouldn't be generic
-// T should be just changed to AbstractFile
-trait ClassFileLookup[T] {
- def findClassFile(name: String): Option[AbstractFile]
-
- /**
- * It returns both classes from class file and source files (as our base ClassRepresentation).
- * So note that it's not so strictly related to findClassFile.
- */
- def findClass(name: String): Option[ClassRepresentation[T]]
-
- /**
- * A sequence of URLs representing this classpath.
- */
- def asURLs: Seq[URL]
-
- /** The whole classpath in the form of one String.
- */
- def asClassPathString: String
-
- // for compatibility purposes
- @deprecated("Use asClassPathString instead of this one", "2.11.5")
- def asClasspathString: String = asClassPathString
-
- /** The whole sourcepath in the form of one String.
- */
- def asSourcePathString: String
-}
-
-object ClassFileLookup {
- def createForFile(f: AbstractFile, current: ClassFileLookup[AbstractFile], settings: Settings): ClassFileLookup[AbstractFile] = current match {
- case cp: ClassPath[_] => cp.context.newClassPath(f)
- case _: FlatClassPath => FlatClassPathFactory.newClassPath(f, settings)
- }
-
- def createAggregate(elems: Iterable[ClassFileLookup[AbstractFile]], current: ClassFileLookup[AbstractFile]): ClassFileLookup[AbstractFile] = {
- assert(elems.nonEmpty)
- if (elems.size == 1) elems.head
- else current match {
- case cp: ClassPath[_] =>
- new MergedClassPath(elems.asInstanceOf[Iterable[ClassPath[AbstractFile]]], cp.context)
-
- case _: FlatClassPath =>
- AggregateFlatClassPath.createAggregate(elems.asInstanceOf[Iterable[FlatClassPath]].toSeq : _*)
- }
- }
-}
-
-/**
- * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader.
- */
-// TODO at the end, after the possible removal of the old classpath implementation, this class shouldn't be generic
-// T should be just changed to AbstractFile
-trait ClassRepresentation[T] {
- def binary: Option[T]
- def source: Option[AbstractFile]
-
- def name: String
-}
-
-object ClassRepresentation {
- def unapply[T](classRep: ClassRepresentation[T]): Option[(Option[T], Option[AbstractFile])] =
- Some((classRep.binary, classRep.source))
-}
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index e5af1edadb..cef2fc4bbf 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -7,28 +7,61 @@
package scala.tools.nsc
package util
-import io.{ AbstractFile, Directory, File, Jar }
+import io.{AbstractFile, Directory, File, Jar}
import java.net.MalformedURLException
import java.net.URL
import java.util.regex.PatternSyntaxException
-import scala.collection.{ mutable, immutable }
-import scala.reflect.internal.util.StringOps.splitWhere
-import scala.tools.nsc.classpath.FileUtils
import File.pathSeparator
-import FileUtils.endsClass
-import FileUtils.endsScalaOrJava
import Jar.isJarOrZip
-/** <p>
- * This module provides star expansion of '-classpath' option arguments, behaves the same as
- * java, see [[http://docs.oracle.com/javase/6/docs/technotes/tools/windows/classpath.html]]
- * </p>
- *
- * @author Stepan Koltsov
- */
+/**
+ * A representation of the compiler's class- or sourcepath.
+ */
+trait ClassPath {
+ import scala.tools.nsc.classpath._
+ def asURLs: Seq[URL]
+
+ /** Empty string represents root package */
+ private[nsc] def packages(inPackage: String): Seq[PackageEntry]
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry]
+ private[nsc] def sources(inPackage: String): Seq[SourceFileEntry]
+
+ /** Allows to get entries for packages and classes merged with sources possibly in one pass. */
+ private[nsc] def list(inPackage: String): ClassPathEntries
+
+ /**
+ * It returns both classes from class file and source files (as our base ClassRepresentation).
+ * So note that it's not so strictly related to findClassFile.
+ */
+ def findClass(className: String): Option[ClassRepresentation] = {
+ // A default implementation which should be overridden, if we can create the more efficient
+ // solution for a given type of ClassPath
+ val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
+
+ val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
+ def findClassInSources = sources(pkg).find(_.name == simpleClassName)
+
+ foundClassFromClassFiles orElse findClassInSources
+ }
+ def findClassFile(className: String): Option[AbstractFile]
+
+ def asClassPathStrings: Seq[String]
+
+ /** The whole classpath in the form of one String.
+ */
+ def asClassPathString: String = ClassPath.join(asClassPathStrings: _*)
+ // for compatibility purposes
+ @deprecated("Use asClassPathString instead of this one", "2.11.5")
+ def asClasspathString: String = asClassPathString
+
+ /** The whole sourcepath in the form of one String.
+ */
+ def asSourcePathString: String
+}
+
object ClassPath {
- import scala.language.postfixOps
+ val RootPackage = ""
/** Expand single path entry */
private def expandS(pattern: String): List[String] = {
@@ -36,14 +69,14 @@ object ClassPath {
/* Get all subdirectories, jars, zips out of a directory. */
def lsDir(dir: Directory, filt: String => Boolean = _ => true) =
- dir.list filter (x => filt(x.name) && (x.isDirectory || isJarOrZip(x))) map (_.path) toList
+ dir.list.filter(x => filt(x.name) && (x.isDirectory || isJarOrZip(x))).map(_.path).toList
if (pattern == "*") lsDir(Directory("."))
else if (pattern endsWith wildSuffix) lsDir(Directory(pattern dropRight 2))
else if (pattern contains '*') {
try {
val regexp = ("^" + pattern.replaceAllLiterally("""\*""", """.*""") + "$").r
- lsDir(Directory(pattern).parent, regexp findFirstIn _ isDefined)
+ lsDir(Directory(pattern).parent, regexp.findFirstIn(_).isDefined)
}
catch { case _: PatternSyntaxException => List(pattern) }
}
@@ -51,7 +84,7 @@ object ClassPath {
}
/** Split classpath using platform-dependent path separator */
- def split(path: String): List[String] = (path split pathSeparator).toList filterNot (_ == "") distinct
+ def split(path: String): List[String] = (path split pathSeparator).toList.filterNot(_ == "").distinct
/** Join classpath using platform-dependent path separator */
def join(paths: String*): String = paths filterNot (_ == "") mkString pathSeparator
@@ -68,9 +101,10 @@ object ClassPath {
def expandDir(extdir: String): List[String] = {
AbstractFile getDirectory extdir match {
case null => Nil
- case dir => dir filter (_.isClassContainer) map (x => new java.io.File(dir.file, x.name) getPath) toList
+ case dir => dir.filter(_.isClassContainer).map(x => new java.io.File(dir.file, x.name).getPath).toList
}
}
+
/** Expand manifest jar classpath entries: these are either urls, or paths
* relative to the location of the jar.
*/
@@ -88,301 +122,30 @@ object ClassPath {
try Some(new URL(spec))
catch { case _: MalformedURLException => None }
- /** A class modeling aspects of a ClassPath which should be
- * propagated to any classpaths it creates.
- */
- abstract class ClassPathContext[T] extends classpath.ClassPathFactory[ClassPath[T]] {
- /** A filter which can be used to exclude entities from the classpath
- * based on their name.
- */
- def isValidName(name: String): Boolean = true
-
- /** Filters for assessing validity of various entities.
- */
- def validClassFile(name: String) = endsClass(name) && isValidName(name)
- def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.')
- def validSourceFile(name: String) = endsScalaOrJava(name)
-
- /** From the representation to its identifier.
- */
- def toBinaryName(rep: T): String
-
- def sourcesInPath(path: String): List[ClassPath[T]] =
- for (file <- expandPath(path, expandStar = false) ; dir <- Option(AbstractFile getDirectory file)) yield
- new SourcePath[T](dir, this)
- }
-
def manifests: List[java.net.URL] = {
import scala.collection.JavaConverters._
val resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF")
resources.asScala.filter(_.getProtocol == "jar").toList
}
- class JavaContext extends ClassPathContext[AbstractFile] {
- def toBinaryName(rep: AbstractFile) = {
- val name = rep.name
- assert(endsClass(name), name)
- FileUtils.stripClassExtension(name)
- }
+ @deprecated("Shim for sbt's compiler interface", since = "2.12")
+ sealed abstract class ClassPathContext
- def newClassPath(dir: AbstractFile) = new DirectoryClassPath(dir, this)
- }
-
- object DefaultJavaContext extends JavaContext
-
- /** From the source file to its identifier.
- */
- def toSourceName(f: AbstractFile): String = FileUtils.stripSourceExtension(f.name)
+ @deprecated("Shim for sbt's compiler interface", since = "2.12")
+ sealed abstract class JavaContext
}
-import ClassPath._
-
-/**
- * Represents a package which contains classes and other packages
- */
-abstract class ClassPath[T] extends ClassFileLookup[T] {
- /**
- * The short name of the package (without prefix)
- */
+trait ClassRepresentation {
def name: String
-
- /**
- * A String representing the origin of this classpath element, if known.
- * For example, the path of the directory or jar.
- */
- def origin: Option[String] = None
-
- /** Info which should be propagated to any sub-classpaths.
- */
- def context: ClassPathContext[T]
-
- /** Lists of entities.
- */
- def classes: IndexedSeq[ClassRepresentation[T]]
- def packages: IndexedSeq[ClassPath[T]]
- def sourcepaths: IndexedSeq[AbstractFile]
-
- /** The entries this classpath is composed of. In class `ClassPath` it's just the singleton list containing `this`.
- * Subclasses such as `MergedClassPath` typically return lists with more elements.
- */
- def entries: IndexedSeq[ClassPath[T]] = IndexedSeq(this)
-
- /** Merge classpath of `platform` and `urls` into merged classpath */
- def mergeUrlsIntoClassPath(urls: URL*): MergedClassPath[T] = {
- // Collect our new jars/directories and add them to the existing set of classpaths
- val allEntries =
- (entries ++
- urls.map(url => context.newClassPath(io.AbstractFile.getURL(url)))
- ).distinct
-
- // Combine all of our classpaths (old and new) into one merged classpath
- new MergedClassPath(allEntries, context)
- }
-
- /**
- * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader.
- */
- case class ClassRep(binary: Option[T], source: Option[AbstractFile]) extends ClassRepresentation[T] {
- def name: String = binary match {
- case Some(x) => context.toBinaryName(x)
- case _ =>
- assert(source.isDefined)
- toSourceName(source.get)
- }
- }
-
- /** Filters for assessing validity of various entities.
- */
- def validClassFile(name: String) = context.validClassFile(name)
- def validPackage(name: String) = context.validPackage(name)
- def validSourceFile(name: String) = context.validSourceFile(name)
-
- /**
- * Find a ClassRep given a class name of the form "package.subpackage.ClassName".
- * Does not support nested classes on .NET
- */
- override def findClass(name: String): Option[ClassRepresentation[T]] =
- splitWhere(name, _ == '.', doDropIndex = true) match {
- case Some((pkg, rest)) =>
- val rep = packages find (_.name == pkg) flatMap (_ findClass rest)
- rep map {
- case x: ClassRepresentation[T] => x
- case x => throw new FatalError("Unexpected ClassRep '%s' found searching for name '%s'".format(x, name))
- }
- case _ =>
- classes find (_.name == name)
- }
-
- override def findClassFile(name: String): Option[AbstractFile] =
- findClass(name) match {
- case Some(ClassRepresentation(Some(x: AbstractFile), _)) => Some(x)
- case _ => None
- }
-
- override def asSourcePathString: String = sourcepaths.mkString(pathSeparator)
-
- def sortString = join(split(asClassPathString).sorted: _*)
- override def equals(that: Any) = that match {
- case x: ClassPath[_] => this.sortString == x.sortString
- case _ => false
- }
- override def hashCode = sortString.hashCode()
-}
-
-/**
- * A Classpath containing source files
- */
-class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends ClassPath[T] {
- import FileUtils.AbstractFileOps
-
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = dir.toURLs()
- def asClassPathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq(dir)
-
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[SourcePath[T]]
- dir foreach { f =>
- if (!f.isDirectory && validSourceFile(f.name))
- classBuf += ClassRep(None, Some(f))
- else if (f.isDirectory && validPackage(f.name))
- packageBuf += new SourcePath[T](f, context)
- }
- (packageBuf.result(), classBuf.result())
- }
-
- lazy val (packages, classes) = traverse()
- override def toString() = "sourcepath: "+ dir.toString()
+ def binary: Option[AbstractFile]
+ def source: Option[AbstractFile]
}
-/**
- * A directory (or a .jar file) containing classfiles and packages
- */
-class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] {
- import FileUtils.AbstractFileOps
-
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = dir.toURLs(default = Seq(new URL(name)))
- def asClassPathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
-
- // calculates (packages, classes) in one traversal.
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[DirectoryClassPath]
- dir foreach {
- f =>
- // Optimization: We assume the file was not changed since `dir` called
- // `Path.apply` and categorized existent files as `Directory`
- // or `File` (avoids IO operation JFile.isDirectory()).
- val isDirectory = f match {
- case pf: io.PlainFile => pf.givenPath match {
- case _: io.Directory => true
- case _: io.File => false
- case _ => f.isDirectory
- }
- case _ =>
- f.isDirectory
- }
- if (!isDirectory && validClassFile(f.name))
- classBuf += ClassRep(Some(f), None)
- else if (isDirectory && validPackage(f.name))
- packageBuf += new DirectoryClassPath(f, context)
- }
- (packageBuf.result(), classBuf.result())
- }
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class DirectoryClassPath
- lazy val (packages, classes) = traverse()
- override def toString() = "directory classpath: "+ origin.getOrElse("?")
-}
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class MergedClassPath
-/**
- * A classpath unifying multiple class- and sourcepath entries.
- */
-class MergedClassPath[T](
- override val entries: IndexedSeq[ClassPath[T]],
- val context: ClassPathContext[T])
-extends ClassPath[T] {
-
- def this(entries: TraversableOnce[ClassPath[T]], context: ClassPathContext[T]) =
- this(entries.toIndexedSeq, context)
-
- def name = entries.head.name
- def asURLs = (entries flatMap (_.asURLs)).toList
- lazy val sourcepaths: IndexedSeq[AbstractFile] = entries flatMap (_.sourcepaths)
-
- override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")"))
- override def asClassPathString: String = join(entries map (_.asClassPathString) : _*)
-
- lazy val classes: IndexedSeq[ClassRepresentation[T]] = {
- var count = 0
- val indices = mutable.HashMap[String, Int]()
- val cls = new mutable.ArrayBuffer[ClassRepresentation[T]](1024)
-
- for (e <- entries; c <- e.classes) {
- val name = c.name
- if (indices contains name) {
- val idx = indices(name)
- val existing = cls(idx)
-
- if (existing.binary.isEmpty && c.binary.isDefined)
- cls(idx) = ClassRep(binary = c.binary, source = existing.source)
- if (existing.source.isEmpty && c.source.isDefined)
- cls(idx) = ClassRep(binary = existing.binary, source = c.source)
- }
- else {
- indices(name) = count
- cls += c
- count += 1
- }
- }
- cls.toIndexedSeq
- }
-
- lazy val packages: IndexedSeq[ClassPath[T]] = {
- var count = 0
- val indices = mutable.HashMap[String, Int]()
- val pkg = new mutable.ArrayBuffer[ClassPath[T]](256)
-
- for (e <- entries; p <- e.packages) {
- val name = p.name
- if (indices contains name) {
- val idx = indices(name)
- pkg(idx) = addPackage(pkg(idx), p)
- }
- else {
- indices(name) = count
- pkg += p
- count += 1
- }
- }
- pkg.toIndexedSeq
- }
-
- private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = {
- val newEntries: IndexedSeq[ClassPath[T]] = to match {
- case cp: MergedClassPath[_] => cp.entries :+ pkg
- case _ => IndexedSeq(to, pkg)
- }
- new MergedClassPath[T](newEntries, context)
- }
-
- def show() {
- println("ClassPath %s has %d entries and results in:\n".format(name, entries.size))
- asClassPathString split ':' foreach (x => println(" " + x))
- }
-
- override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")")
-}
-
-/**
- * The classpath when compiling with target:jvm. Binary files (classfiles) are represented
- * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories.
- */
-class JavaClassPath(
- containers: IndexedSeq[ClassPath[AbstractFile]],
- context: JavaContext)
-extends MergedClassPath[AbstractFile](containers, context) { }
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class JavaClassPath
diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala
index 8d8418945a..7d82910699 100644
--- a/src/compiler/scala/tools/reflect/ReflectMain.scala
+++ b/src/compiler/scala/tools/reflect/ReflectMain.scala
@@ -5,12 +5,12 @@ import scala.reflect.internal.util.ScalaClassLoader
import scala.tools.nsc.Driver
import scala.tools.nsc.Global
import scala.tools.nsc.Settings
-import scala.tools.util.PathResolverFactory
+import scala.tools.util.PathResolver
object ReflectMain extends Driver {
private def classloaderFromSettings(settings: Settings) = {
- val classPathURLs = PathResolverFactory.create(settings).resultAsURLs
+ val classPathURLs = new PathResolver(settings).resultAsURLs
ScalaClassLoader.fromURLs(classPathURLs, getClass.getClassLoader)
}
diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala
index 9decc99c8d..c351b6ace1 100644
--- a/src/compiler/scala/tools/util/PathResolver.scala
+++ b/src/compiler/scala/tools/util/PathResolver.scala
@@ -10,12 +10,10 @@ package util
import java.net.URL
import scala.tools.reflect.WrappedProperties.AccessControl
import scala.tools.nsc.Settings
-import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, JavaClassPath }
-import scala.reflect.io.{ File, Directory, Path, AbstractFile }
-import ClassPath.{ JavaContext, DefaultJavaContext, split }
+import scala.tools.nsc.util.ClassPath
+import scala.reflect.io.{Directory, File, Path}
import PartialFunction.condOpt
-import scala.tools.nsc.classpath.{ AggregateFlatClassPath, ClassPathFactory, FlatClassPath, FlatClassPathFactory }
-import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.nsc.classpath._
// Loosely based on the draft specification at:
// https://wiki.scala-lang.org/display/SIW/Classpath
@@ -40,7 +38,7 @@ object PathResolver {
}
/** pretty print class path */
- def ppcp(s: String) = split(s) match {
+ def ppcp(s: String) = ClassPath.split(s) match {
case Nil => ""
case Seq(x) => x
case xs => xs.mkString(EOL, EOL, "")
@@ -164,13 +162,6 @@ object PathResolver {
|}""".asLines
}
- @deprecated("This method is no longer used be scalap and will be deleted", "2.11.5")
- def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = {
- val s = new Settings()
- s.classpath.value = path
- new PathResolver(s, context).result
- }
-
/** With no arguments, show the interesting values in Environment and Defaults.
* If there are arguments, show those in Calculated as if those options had been
* given to a scala runner.
@@ -182,28 +173,19 @@ object PathResolver {
} else {
val settings = new Settings()
val rest = settings.processArguments(args.toList, processAll = false)._2
- val pr = PathResolverFactory.create(settings)
+ val pr = new PathResolver(settings)
println("COMMAND: 'scala %s'".format(args.mkString(" ")))
println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" ")))
pr.result match {
- case cp: JavaClassPath =>
- cp.show()
- case cp: AggregateFlatClassPath =>
+ case cp: AggregateClassPath =>
println(s"ClassPath has ${cp.aggregates.size} entries and results in:\n${cp.asClassPathStrings}")
}
}
}
-trait PathResolverResult {
- def result: ClassFileLookup[AbstractFile]
-
- def resultAsURLs: Seq[URL] = result.asURLs
-}
-
-abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFile], ResultClassPathType <: BaseClassPathType]
-(settings: Settings, classPathFactory: ClassPathFactory[BaseClassPathType])
- extends PathResolverResult {
+final class PathResolver(settings: Settings) {
+ private val classPathFactory = new ClassPathFactory(settings)
import PathResolver.{ AsLines, Defaults, ppcp }
@@ -251,7 +233,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
import classPathFactory._
// Assemble the elements!
- def basis = List[Traversable[BaseClassPathType]](
+ def basis = List[Traversable[ClassPath]](
classesInPath(javaBootClassPath), // 1. The Java bootstrap class path.
contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path.
classesInExpandedPath(javaUserClassPath), // 3. The Java application class path.
@@ -282,7 +264,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
import PathResolver.MkLines
- def result: ResultClassPathType = {
+ def result: ClassPath = {
val cp = computeResult()
if (settings.Ylogcp) {
Console print f"Classpath built from ${settings.toConciseString} %n"
@@ -295,34 +277,11 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
cp
}
+ def resultAsURLs: Seq[URL] = result.asURLs
+
@deprecated("Use resultAsURLs instead of this one", "2.11.5")
def asURLs: List[URL] = resultAsURLs.toList
- protected def computeResult(): ResultClassPathType
+ private def computeResult(): ClassPath = AggregateClassPath(containers.toIndexedSeq)
}
-class PathResolver(settings: Settings, context: JavaContext)
- extends PathResolverBase[ClassPath[AbstractFile], JavaClassPath](settings, context) {
-
- def this(settings: Settings) = this(settings, DefaultJavaContext)
-
- override protected def computeResult(): JavaClassPath =
- new JavaClassPath(containers.toIndexedSeq, context)
-}
-
-class FlatClassPathResolver(settings: Settings, flatClassPathFactory: ClassPathFactory[FlatClassPath])
- extends PathResolverBase[FlatClassPath, AggregateFlatClassPath](settings, flatClassPathFactory) {
-
- def this(settings: Settings) = this(settings, new FlatClassPathFactory(settings))
-
- override protected def computeResult(): AggregateFlatClassPath = AggregateFlatClassPath(containers.toIndexedSeq)
-}
-
-object PathResolverFactory {
-
- def create(settings: Settings): PathResolverResult =
- settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new FlatClassPathResolver(settings)
- case ClassPathRepresentationType.Recursive => new PathResolver(settings)
- }
-}
diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath
index ab9ede5a19..22afd65d43 100644
--- a/src/eclipse/partest/.classpath
+++ b/src/eclipse/partest/.classpath
@@ -9,6 +9,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.13.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.14.jar"/>
<classpathentry kind="output" path="build-quick-partest-extras"/>
</classpath>
diff --git a/src/eclipse/scaladoc/.classpath b/src/eclipse/scaladoc/.classpath
index 40387983b0..b4450df4ef 100644
--- a/src/eclipse/scaladoc/.classpath
+++ b/src/eclipse/scaladoc/.classpath
@@ -8,6 +8,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
<classpathentry kind="var" path="SCALA_BASEDIR/build/deps/scaladoc/scala-xml_2.12.0-M4-1.0.5.jar"/>
<classpathentry kind="var" path="SCALA_BASEDIR/build/deps/scaladoc/scala-parser-combinators_2.12.0-M4-1.0.4.jar"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.13.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.14.jar"/>
<classpathentry kind="output" path="build-quick-scaladoc"/>
</classpath>
diff --git a/src/library/scala/Product.scala b/src/library/scala/Product.scala
index 9cd38ed148..f3a96fb333 100644
--- a/src/library/scala/Product.scala
+++ b/src/library/scala/Product.scala
@@ -19,7 +19,7 @@ package scala
*/
trait Product extends Any with Equals {
/** The n^th^ element of this product, 0-based. In other words, for a
- * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 < n < k`.
+ * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 <= n < k`.
*
* @param n the index of the element to return
* @throws IndexOutOfBoundsException
diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala
index 6bb1f116fe..ecf3326c7f 100644
--- a/src/library/scala/collection/immutable/BitSet.scala
+++ b/src/library/scala/collection/immutable/BitSet.scala
@@ -68,6 +68,8 @@ object BitSet extends BitSetFactory[BitSet] {
/** The empty bitset */
val empty: BitSet = new BitSet1(0L)
+ private def createSmall(a: Long, b: Long): BitSet = if (b == 0L) new BitSet1(a) else new BitSet2(a, b)
+
/** A builder that takes advantage of mutable BitSets. */
def newBuilder: Builder[Int, BitSet] = new Builder[Int, BitSet] {
private[this] val b = new mutable.BitSet
@@ -84,7 +86,7 @@ object BitSet extends BitSetFactory[BitSet] {
val len = elems.length
if (len == 0) empty
else if (len == 1) new BitSet1(elems(0))
- else if (len == 2) new BitSet2(elems(0), elems(1))
+ else if (len == 2) createSmall(elems(0), elems(1))
else {
val a = new Array[Long](len)
Array.copy(elems, 0, a, 0, len)
@@ -99,7 +101,7 @@ object BitSet extends BitSetFactory[BitSet] {
val len = elems.length
if (len == 0) empty
else if (len == 1) new BitSet1(elems(0))
- else if (len == 2) new BitSet2(elems(0), elems(1))
+ else if (len == 2) createSmall(elems(0), elems(1))
else new BitSetN(elems)
}
@@ -109,7 +111,7 @@ object BitSet extends BitSetFactory[BitSet] {
protected def word(idx: Int) = if (idx == 0) elems else 0L
protected def updateWord(idx: Int, w: Long): BitSet =
if (idx == 0) new BitSet1(w)
- else if (idx == 1) new BitSet2(elems, w)
+ else if (idx == 1) createSmall(elems, w)
else fromBitMaskNoCopy(updateArray(Array(elems), idx, w))
override def head: Int =
if (elems == 0L) throw new NoSuchElementException("Empty BitSet")
@@ -124,7 +126,7 @@ object BitSet extends BitSetFactory[BitSet] {
protected def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L
protected def updateWord(idx: Int, w: Long): BitSet =
if (idx == 0) new BitSet2(w, elems1)
- else if (idx == 1) new BitSet2(elems0, w)
+ else if (idx == 1) createSmall(elems0, w)
else fromBitMaskNoCopy(updateArray(Array(elems0, elems1), idx, w))
override def head: Int =
if (elems0 == 0L) {
@@ -135,7 +137,7 @@ object BitSet extends BitSetFactory[BitSet] {
override def tail: BitSet =
if (elems0 == 0L) {
if (elems1 == 0L) throw new NoSuchElementException("Empty BitSet")
- new BitSet2(elems0, elems1 - java.lang.Long.lowestOneBit(elems1))
+ createSmall(elems0, elems1 - java.lang.Long.lowestOneBit(elems1))
}
else new BitSet2(elems0 - java.lang.Long.lowestOneBit(elems0), elems1)
}
diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala
index b4112c03dd..d5b7673c37 100644
--- a/src/library/scala/collection/mutable/PriorityQueue.scala
+++ b/src/library/scala/collection/mutable/PriorityQueue.scala
@@ -200,9 +200,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
* @return A reversed priority queue.
*/
def reverse = {
- val revq = new PriorityQueue[A]()(new scala.math.Ordering[A] {
- def compare(x: A, y: A) = ord.compare(y, x)
- })
+ val revq = new PriorityQueue[A]()(ord.reverse)
for (i <- 1 until resarr.length) revq += resarr(i)
revq
}
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index b10aad0ecc..d9d3d572e8 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -29,8 +29,8 @@ import scala.reflect.ClassTag
* val f: Future[String] = Future {
* s + " future!"
* }
- * f onSuccess {
- * case msg => println(msg)
+ * f foreach {
+ * msg => println(msg)
* }
* }}}
*
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index 6d3d015b1a..bd55fb5d04 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -182,6 +182,9 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
* val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year"
* }}}
*
+ * Group names supplied to the constructor are preferred to inline group names
+ * when retrieving matched groups by name. Not all platforms support inline names.
+ *
* This constructor does not support options as flags, which must be
* supplied as inline flags in the pattern string: `(?idmsux-idmsux)`.
*
@@ -578,6 +581,9 @@ object Regex {
*/
trait MatchData {
+ /** Basically, wraps a platform Matcher. */
+ protected def matcher: Matcher
+
/** The source from which the match originated */
val source: CharSequence
@@ -650,16 +656,25 @@ object Regex {
private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex
- /** Returns the group with given name.
+ /** Returns the group with the given name.
+ *
+ * Uses explicit group names when supplied; otherwise,
+ * queries the underlying implementation for inline named groups.
+ * Not all platforms support inline group names.
*
* @param id The group name
* @return The requested group
- * @throws NoSuchElementException if the requested group name is not defined
+ * @throws IllegalArgumentException if the requested group name is not defined
*/
- def group(id: String): String = nameToIndex.get(id) match {
- case None => throw new NoSuchElementException("group name "+id+" not defined")
- case Some(index) => group(index)
- }
+ def group(id: String): String = (
+ if (groupNames.isEmpty)
+ matcher group id
+ else
+ nameToIndex.get(id) match {
+ case Some(index) => group(index)
+ case None => matcher group id
+ }
+ )
/** The matched string; equivalent to `matched.toString`. */
override def toString = matched
@@ -667,7 +682,7 @@ object Regex {
/** Provides information about a successful match. */
class Match(val source: CharSequence,
- private[matching] val matcher: Matcher,
+ protected[matching] val matcher: Matcher,
val groupNames: Seq[String]) extends MatchData {
/** The index of the first matched character. */
diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
index 290b7b434e..532dfd2a73 100644
--- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala
+++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
@@ -1,10 +1,10 @@
package scala.tools.partest
-import scala.tools.nsc.util.JavaClassPath
import scala.collection.JavaConverters._
-import scala.tools.asm.{ClassWriter, ClassReader}
+import scala.tools.asm.{ClassReader, ClassWriter}
import scala.tools.asm.tree._
-import java.io.{File => JFile, InputStream}
+import java.io.{InputStream, File => JFile}
+
import AsmNode._
/**
@@ -125,12 +125,16 @@ abstract class BytecodeTest {
cn
}
- protected lazy val classpath: JavaClassPath = {
- import scala.tools.nsc.util.ClassPath.DefaultJavaContext
+ protected lazy val classpath: scala.tools.nsc.util.ClassPath = {
+ import scala.tools.nsc.classpath.AggregateClassPath
+ import scala.tools.nsc.classpath.ClassPathFactory
import scala.tools.util.PathResolver.Defaults
+ import scala.tools.nsc.Settings
// logic inspired by scala.tools.util.PathResolver implementation
- val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath)
- new JavaClassPath(containers, DefaultJavaContext)
+ // `Settings` is used to check YdisableFlatCpCaching in ZipArchiveFlatClassPath
+ val factory = new ClassPathFactory(new Settings())
+ val containers = factory.classesInExpandedPath(Defaults.javaUserClassPath)
+ new AggregateClassPath(containers)
}
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 37b07ce775..9b0d66f41c 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -613,7 +613,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
loadBytes[String]("scala.reflect.ScalaSignature") match {
case Some(ssig) =>
info(s"unpickling Scala $clazz and $module, owner = ${clazz.owner}")
- val bytes = ssig.getBytes
+ val bytes = ssig.getBytes(java.nio.charset.StandardCharsets.UTF_8)
val len = ByteCodecs.decode(bytes)
assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
@@ -622,7 +622,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match {
case Some(slsig) =>
info(s"unpickling Scala $clazz and $module with long Scala signature")
- val encoded = slsig flatMap (_.getBytes)
+ val encoded = slsig flatMap (_.getBytes(java.nio.charset.StandardCharsets.UTF_8))
val len = ByteCodecs.decode(encoded)
val decoded = encoded.take(len)
assignAssociatedFile(clazz, module, jclazz)
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 893bde42ab..8c91242b36 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -11,18 +11,18 @@ import PartialFunction.cond
import scala.language.implicitConversions
import scala.beans.BeanProperty
import scala.collection.mutable
-import scala.concurrent.{ Future, ExecutionContext }
-import scala.reflect.runtime.{ universe => ru }
-import scala.reflect.{ ClassTag, classTag }
-import scala.reflect.internal.util.{ BatchSourceFile, SourceFile }
-import scala.tools.util.PathResolverFactory
+import scala.concurrent.{ExecutionContext, Future}
+import scala.reflect.runtime.{universe => ru}
+import scala.reflect.{ClassTag, classTag}
+import scala.reflect.internal.util.{BatchSourceFile, SourceFile}
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings }
+import scala.tools.nsc.typechecker.{StructuredTypeStrings, TypeStrings}
import scala.tools.nsc.util._
import ScalaClassLoader.URLClassLoader
import scala.tools.nsc.util.Exceptional.unwrap
-import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, CompiledScript, Compilable}
+import javax.script.{AbstractScriptEngine, Bindings, Compilable, CompiledScript, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException}
import java.net.URL
+import scala.tools.util.PathResolver
/** An interpreter for Scala code.
*
@@ -91,7 +91,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def compilerClasspath: Seq[java.net.URL] = (
if (isInitializeComplete) global.classPath.asURLs
- else PathResolverFactory.create(settings).resultAsURLs // the compiler's classpath
+ else new PathResolver(settings).resultAsURLs // the compiler's classpath
)
def settings = initialSettings
// Run the code body with the given boolean settings flipped to true.
diff --git a/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
index e3dc72b717..b9a4054ffc 100644
--- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
+++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
@@ -7,9 +7,7 @@ package scala.tools.nsc.interpreter
import scala.reflect.internal.util.RangePosition
import scala.reflect.io.AbstractFile
import scala.tools.nsc.backend.JavaPlatform
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
-import scala.tools.nsc.util.{ClassPath, MergedClassPath, DirectoryClassPath}
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.{interactive, Settings}
import scala.tools.nsc.reporters.StoreReporter
import scala.tools.nsc.classpath._
@@ -58,12 +56,8 @@ trait PresentationCompilation {
*/
def newPresentationCompiler(): interactive.Global = {
def mergedFlatClasspath = {
- val replOutClasspath = FlatClassPathFactory.newClassPath(replOutput.dir, settings)
- AggregateFlatClassPath(replOutClasspath :: global.platform.flatClassPath :: Nil)
- }
- def mergedRecursiveClasspath = {
- val replOutClasspath: DirectoryClassPath = new DirectoryClassPath(replOutput.dir, DefaultJavaContext)
- new MergedClassPath[AbstractFile](replOutClasspath :: global.platform.classPath :: Nil, DefaultJavaContext)
+ val replOutClasspath = ClassPathFactory.newClassPath(replOutput.dir, settings)
+ AggregateClassPath(replOutClasspath :: global.platform.classPath :: Nil)
}
def copySettings: Settings = {
val s = new Settings(_ => () /* ignores "bad option -nc" errors, etc */)
@@ -74,16 +68,9 @@ trait PresentationCompilation {
val storeReporter: StoreReporter = new StoreReporter
val interactiveGlobal = new interactive.Global(copySettings, storeReporter) { self =>
override lazy val platform: ThisPlatform = {
- if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
- new JavaPlatform {
- val global: self.type = self
- override private[nsc] lazy val flatClassPath: FlatClassPath = mergedFlatClasspath
- }
- } else {
- new JavaPlatform {
- val global: self.type = self
- override def classPath: ClassPath[AbstractFile] = mergedRecursiveClasspath
- }
+ new JavaPlatform {
+ val global: self.type = self
+ override private[nsc] lazy val classPath: ClassPath = mergedFlatClasspath
}
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/package.scala b/src/repl/scala/tools/nsc/interpreter/package.scala
index 56f1e65376..7de1dda15f 100644
--- a/src/repl/scala/tools/nsc/interpreter/package.scala
+++ b/src/repl/scala/tools/nsc/interpreter/package.scala
@@ -88,9 +88,6 @@ package object interpreter extends ReplConfig with ReplStrings {
}
}
- if (filtered.isEmpty)
- return "No implicits have been imported other than those in Predef."
-
filtered foreach {
case (source, syms) =>
p("/* " + syms.size + " implicit members imported from " + source.fullName + " */")
@@ -126,7 +123,14 @@ package object interpreter extends ReplConfig with ReplStrings {
}
p("")
}
- ""
+
+ if (filtered.nonEmpty)
+ "" // side-effects above
+ else if (global.settings.nopredef || global.settings.noimports)
+ "No implicits have been imported."
+ else
+ "No implicits have been imported other than those in Predef."
+
}
def kindCommandInternal(expr: String, verbose: Boolean): Unit = {
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index 3d2bfd7251..6a37bbc270 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -8,17 +8,12 @@
package scala
package tools.scalap
-import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream }
+import java.io.{ByteArrayOutputStream, OutputStreamWriter, PrintStream}
import scala.reflect.NameTransformer
import scala.tools.nsc.Settings
-import scala.tools.nsc.classpath.AggregateFlatClassPath
-import scala.tools.nsc.classpath.FlatClassPathFactory
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassFileLookup
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
-import scala.tools.nsc.util.JavaClassPath
-import scala.tools.util.PathResolverFactory
+import scala.tools.nsc.classpath.{AggregateClassPath, ClassPathFactory}
+import scala.tools.nsc.util.ClassPath
+import scala.tools.util.PathResolver
import scalax.rules.scalasig._
/**The main object used to execute scalap on the command-line.
@@ -101,7 +96,7 @@ class Main {
/** Executes scalap with the given arguments and classpath for the
* class denoted by `classname`.
*/
- def process(args: Arguments, path: ClassFileLookup[AbstractFile])(classname: String): Unit = {
+ def process(args: Arguments, path: ClassPath)(classname: String): Unit = {
// find the classfile
val encName = classname match {
case "scala.AnyRef" => "java.lang.Object"
@@ -145,7 +140,6 @@ object Main extends Main {
val verbose = "-verbose"
val version = "-version"
- val classPathImplType = "-YclasspathImpl"
val disableFlatClassPathCaching = "-YdisableFlatCpCaching"
val logClassPath = "-Ylog-classpath"
}
@@ -183,7 +177,6 @@ object Main extends Main {
val settings = new Settings()
- arguments getArgument opts.classPathImplType foreach settings.YclasspathImpl.tryToSetFromPropertyValue
settings.YdisableFlatCpCaching.value = arguments contains opts.disableFlatClassPathCaching
settings.Ylogcp.value = arguments contains opts.logClassPath
@@ -205,21 +198,16 @@ object Main extends Main {
.withOption(opts.help)
.withOptionalArg(opts.classpath)
.withOptionalArg(opts.cp)
- // TODO three temporary, hidden options to be able to test different classpath representations
- .withOptionalArg(opts.classPathImplType)
+ // TODO two temporary, hidden options to be able to test different classpath representations
.withOption(opts.disableFlatClassPathCaching)
.withOption(opts.logClassPath)
.parse(args)
private def createClassPath(cpArg: Option[String], settings: Settings) = cpArg match {
- case Some(cp) => settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat =>
- AggregateFlatClassPath(new FlatClassPathFactory(settings).classesInExpandedPath(cp))
- case ClassPathRepresentationType.Recursive =>
- new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext)
- }
+ case Some(cp) =>
+ AggregateClassPath(new ClassPathFactory(settings).classesInExpandedPath(cp))
case _ =>
settings.classpath.value = "." // include '.' in the default classpath SI-6669
- PathResolverFactory.create(settings).result
+ new PathResolver(settings).result
}
}
diff --git a/test/files/pos/t9397.scala b/test/files/pos/t9397.scala
new file mode 100644
index 0000000000..3dbc6591d3
--- /dev/null
+++ b/test/files/pos/t9397.scala
@@ -0,0 +1,12 @@
+package foo.scala
+
+import scala.reflect.runtime.universe._
+
+object Foo {
+
+ def bar[T: TypeTag]() {
+ }
+
+ import foo._
+ bar[String]()
+}
diff --git a/test/files/run/reify_printf.scala b/test/files/run/reify_printf.scala
index c4ade79837..099a353e89 100644
--- a/test/files/run/reify_printf.scala
+++ b/test/files/run/reify_printf.scala
@@ -6,7 +6,6 @@ import scala.tools.reflect.ToolBox
import scala.reflect.api._
import scala.reflect.api.Trees
import scala.reflect.internal.Types
-import scala.util.matching.Regex
object Test extends App {
//val output = new ByteArrayOutputStream()
diff --git a/test/files/run/repl-implicits-nopredef.check b/test/files/run/repl-implicits-nopredef.check
new file mode 100644
index 0000000000..a849801bb4
--- /dev/null
+++ b/test/files/run/repl-implicits-nopredef.check
@@ -0,0 +1,5 @@
+
+scala> :implicits
+No implicits have been imported.
+
+scala> :quit \ No newline at end of file
diff --git a/test/files/run/repl-implicits-nopredef.scala b/test/files/run/repl-implicits-nopredef.scala
new file mode 100644
index 0000000000..8a451b0c52
--- /dev/null
+++ b/test/files/run/repl-implicits-nopredef.scala
@@ -0,0 +1,10 @@
+import scala.tools.partest.ReplTest
+import scala.tools.nsc.Settings
+
+object Test extends ReplTest {
+ override def transformSettings(settings: Settings): Settings = {
+ settings.nopredef.value = true
+ settings
+ }
+ def code = ":implicits"
+}
diff --git a/test/files/run/repl-implicits.check b/test/files/run/repl-implicits.check
new file mode 100644
index 0000000000..6e80cc8799
--- /dev/null
+++ b/test/files/run/repl-implicits.check
@@ -0,0 +1,5 @@
+
+scala> :implicits
+No implicits have been imported other than those in Predef.
+
+scala> :quit \ No newline at end of file
diff --git a/test/files/run/repl-implicits.scala b/test/files/run/repl-implicits.scala
new file mode 100644
index 0000000000..ca8e16e683
--- /dev/null
+++ b/test/files/run/repl-implicits.scala
@@ -0,0 +1,5 @@
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ def code = ":implicits"
+}
diff --git a/test/files/run/t6502.scala b/test/files/run/t6502.scala
index dffb0e2f98..cb2b3ff449 100644
--- a/test/files/run/t6502.scala
+++ b/test/files/run/t6502.scala
@@ -1,6 +1,5 @@
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.{ ILoop, replProps }
-import scala.tools.nsc.settings.ClassPathRepresentationType
import scala.tools.partest._
object Test extends StoreReporterDirectTest {
@@ -14,14 +13,6 @@ object Test extends StoreReporterDirectTest {
compileString(newCompiler("-cp", classpath, "-d", s"${testOutput.path}/$jarFileName"))(code)
}
- var classPathKind: String = ""
-
- override def settings = {
- val settings = new Settings
- settings.YclasspathImpl.value = classPathKind
- settings
- }
-
def app1 = """
package test
@@ -155,7 +146,7 @@ object Test extends StoreReporterDirectTest {
assert(output.contains("created test6.Z"), output)
}
- def testAll(): Unit = {
+ def show(): Unit = {
test1()
test2()
test3()
@@ -163,11 +154,4 @@ object Test extends StoreReporterDirectTest {
test5()
test6()
}
-
- def show(): Unit = {
- classPathKind = ClassPathRepresentationType.Flat
- testAll()
- classPathKind = ClassPathRepresentationType.Recursive
- testAll()
- }
}
diff --git a/test/files/run/various-flat-classpath-types.scala b/test/files/run/various-flat-classpath-types.scala
index d39019e885..bc54ffb6cc 100644
--- a/test/files/run/various-flat-classpath-types.scala
+++ b/test/files/run/various-flat-classpath-types.scala
@@ -5,7 +5,7 @@
import java.io.{File => JFile, FileInputStream, FileOutputStream}
import java.util.zip.{ZipEntry, ZipOutputStream}
import scala.reflect.io.{Directory, File}
-import scala.tools.nsc.classpath.FlatClassPath.RootPackage
+import scala.tools.nsc.util.ClassPath.RootPackage
import scala.tools.nsc.classpath.PackageNameUtils
import scala.tools.nsc.io.Jar
@@ -80,7 +80,6 @@ object Test {
private val compiler = new scala.tools.nsc.MainClass
private val appRunner = new scala.tools.nsc.MainGenericRunner
- private val classPathImplFlag = "-YclasspathImpl:flat"
private val javaClassPath = sys.props("java.class.path")
// creates a test dir in a temporary dir containing compiled files of this test
@@ -166,13 +165,13 @@ object Test {
val classPath = mkPath(javaClassPath, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
val sourcePath = mkPath(srcDir.path, zipsDir.path + "/Src.zip", jarsDir.path + "/Src.jar")
- compiler.process(Array(classPathImplFlag, "-cp", classPath, "-sourcepath", sourcePath,
+ compiler.process(Array("-cp", classPath, "-sourcepath", sourcePath,
"-d", outDir.path, s"${srcDir.path}/Main.scala"))
}
private def runApp(): Unit = {
val classPath = mkPath(javaClassPath, outDir.path, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
- appRunner.process(Array(classPathImplFlag, "-cp", classPath, "Main"))
+ appRunner.process(Array("-cp", classPath, "Main"))
}
private def createStandardSrcHierarchy(baseFileName: String): Unit =
@@ -200,7 +199,7 @@ object Test {
private def compileSrc(baseFileName: String, destination: JFile = outDir): Unit = {
val srcDirPath = srcDir.path
- compiler.process(Array(classPathImplFlag, "-cp", javaClassPath, "-d", destination.path,
+ compiler.process(Array("-cp", javaClassPath, "-d", destination.path,
s"$srcDirPath/$baseFileName.scala", s"$srcDirPath/nested/Nested$baseFileName.scala"))
}
diff --git a/test/junit/scala/collection/mutable/PriorityQueueTest.scala b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
index a14f1bf4c8..faedcf11f0 100644
--- a/test/junit/scala/collection/mutable/PriorityQueueTest.scala
+++ b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
@@ -14,6 +14,12 @@ class PriorityQueueTest {
priorityQueue.enqueue(elements :_*)
@Test
+ def orderingReverseReverse() {
+ val pq = new mutable.PriorityQueue[Nothing]()((_,_)=>42)
+ assert(pq.ord eq pq.reverse.reverse.ord)
+ }
+
+ @Test
def canSerialize() {
val outputStream = new ByteArrayOutputStream()
new ObjectOutputStream(outputStream).writeObject(priorityQueue)
@@ -27,6 +33,7 @@ class PriorityQueueTest {
val objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes))
val deserializedPriorityQueue = objectInputStream.readObject().asInstanceOf[PriorityQueue[Int]]
+ //correct sequencing is also tested here:
assert(deserializedPriorityQueue.dequeueAll == elements.sorted.reverse)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
index fe43ed2f6a..389e5b2ead 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
@@ -206,6 +206,12 @@ object CodeGenTools {
assert(actual == expected, s"\nFound : ${quote(actual)}\nExpected: ${quote(expected)}")
}
+ def assertNoIndy(m: Method): Unit = assertNoIndy(m.instructions)
+ def assertNoIndy(l: List[Instruction]) = {
+ val indy = l collect { case i: InvokeDynamic => i }
+ assert(indy.isEmpty, indy)
+ }
+
def getSingleMethod(classNode: ClassNode, name: String): Method =
convertMethod(classNode.methods.asScala.toList.find(_.name == name).get)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
index 5090e9c83b..1597c75a7e 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -103,12 +103,12 @@ class InlineWarningTest extends ClearAfterClass {
val warns = List(
"""failed to determine if bar should be inlined:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin,
+ |Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin,
"""B::flop()I is annotated @inline but could not be inlined:
|Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin)
+ |Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin)
var c = 0
val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)})
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 1765a355fd..e2a495fb2b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -428,7 +428,7 @@ class InlinerTest extends ClearAfterClass {
"""B::flop()I is annotated @inline but could not be inlined:
|Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin
+ |Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin
var c = 0
val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; i.msg contains warn})
@@ -833,7 +833,7 @@ class InlinerTest extends ClearAfterClass {
val warn =
"""failed to determine if <init> should be inlined:
|The method <init>()V could not be found in the class A$Inner or any of its parents.
- |Note that the following parent classes could not be found on the classpath: A$Inner""".stripMargin
+ |Note that the parent class A$Inner could not be found on the classpath.""".stripMargin
var c = 0
@@ -955,18 +955,12 @@ class InlinerTest extends ClearAfterClass {
val List(c, _, _) = compile(code)
val t1 = getSingleMethod(c, "t1")
- assert(t1.instructions forall { // indy is eliminated by push-pop
- case _: InvokeDynamic => false
- case _ => true
- })
+ assertNoIndy(t1)
// the indy call is inlined into t, and the closure elimination rewrites the closure invocation to the body method
assertInvoke(t1, "C", "C$$$anonfun$2")
val t2 = getSingleMethod(c, "t2")
- assert(t2.instructions forall { // indy is eliminated by push-pop
- case _: InvokeDynamic => false
- case _ => true
- })
+ assertNoIndy(t2)
assertInvoke(t2, "M$", "M$$$anonfun$1")
}
@@ -1492,4 +1486,31 @@ class InlinerTest extends ClearAfterClass {
// the forwarder C.f is inlined, so there's no invocation
assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
}
+
+ @Test
+ def sd140(): Unit = {
+ val code =
+ """trait T { @inline def f = 0 }
+ |trait U extends T { @inline override def f = 1 }
+ |trait V extends T { def m = 0 }
+ |final class K extends V with U { override def m = super[V].m }
+ |class C { def t = (new K).f }
+ """.stripMargin
+ val c :: _ = compile(code)
+ assertSameSummary(getSingleMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f)
+ }
+
+ @Test
+ def inlineArrayForeach(): Unit = {
+ val code =
+ """class C {
+ | def consume(x: Int) = ()
+ | def t(a: Array[Int]): Unit = a foreach consume
+ |}
+ """.stripMargin
+ val List(c) = compile(code)
+ val t = getSingleMethod(c, "t")
+ assertNoIndy(t)
+ assertInvoke(t, "C", "C$$$anonfun$1")
+ }
}
diff --git a/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala
index 9a004d5e0e..a7aca31ee3 100644
--- a/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
+++ b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala
@@ -10,6 +10,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import scala.reflect.io.VirtualFile
import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.ClassPath
/**
* Tests whether AggregateFlatClassPath returns correct entries taken from
@@ -17,14 +18,14 @@ import scala.tools.nsc.io.AbstractFile
* (in the case of the repeated entry for a class or a source it returns the first one).
*/
@RunWith(classOf[JUnit4])
-class AggregateFlatClassPathTest {
+class AggregateClassPathTest {
- private class TestFlatClassPath extends FlatClassPath {
+ private abstract class TestClassPathBase extends ClassPath {
override def packages(inPackage: String): Seq[PackageEntry] = unsupported
override def sources(inPackage: String): Seq[SourceFileEntry] = unsupported
override def classes(inPackage: String): Seq[ClassFileEntry] = unsupported
- override def list(inPackage: String): FlatClassPathEntries = unsupported
+ override def list(inPackage: String): ClassPathEntries = unsupported
override def findClassFile(name: String): Option[AbstractFile] = unsupported
override def asClassPathStrings: Seq[String] = unsupported
@@ -32,7 +33,7 @@ class AggregateFlatClassPathTest {
override def asURLs: Seq[URL] = unsupported
}
- private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def classes(inPackage: String): Seq[ClassFileEntry] =
for {
@@ -43,10 +44,10 @@ class AggregateFlatClassPathTest {
override def sources(inPackage: String): Seq[SourceFileEntry] = Nil
// we'll ignore packages
- override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, classes(inPackage))
+ override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, classes(inPackage))
}
- private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def sources(inPackage: String): Seq[SourceFileEntry] =
for {
@@ -57,7 +58,7 @@ class AggregateFlatClassPathTest {
override def classes(inPackage: String): Seq[ClassFileEntry] = Nil
// we'll ignore packages
- override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, sources(inPackage))
+ override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, sources(inPackage))
}
private case class EntryNamesInPackage(inPackage: String)(val names: String*)
@@ -88,7 +89,7 @@ class AggregateFlatClassPathTest {
private def virtualFile(pathPrefix: String, inPackage: String, fileName: String, extension: String) = {
val packageDirs =
- if (inPackage == FlatClassPath.RootPackage) ""
+ if (inPackage == ClassPath.RootPackage) ""
else inPackage.split('.').mkString("/", "/", "")
new VirtualFile(fileName + extension, s"$pathPrefix$packageDirs/$fileName$extension")
}
@@ -101,12 +102,12 @@ class AggregateFlatClassPathTest {
TestSourcePath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
)
- AggregateFlatClassPath(partialClassPaths)
+ AggregateClassPath(partialClassPaths)
}
@Test
def testGettingPackages: Unit = {
- case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def packages(inPackage: String): Seq[PackageEntry] =
packagesInPackage.find(_.inPackage == inPackage).map(_.names).getOrElse(Nil) map PackageEntryImpl
}
@@ -115,7 +116,7 @@ class AggregateFlatClassPathTest {
ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.c", "pkg1.b", "pkg1.a"),
EntryNamesInPackage(pkg2)("pkg2.d", "pkg2.a", "pkg2.e"))
)
- val cp = AggregateFlatClassPath(partialClassPaths)
+ val cp = AggregateClassPath(partialClassPaths)
val packagesInPkg1 = Seq("pkg1.a", "pkg1.d", "pkg1.f", "pkg1.c", "pkg1.b")
assertEquals(packagesInPkg1, cp.packages(pkg1).map(_.name))
@@ -156,7 +157,7 @@ class AggregateFlatClassPathTest {
TestClassPath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I")),
TestClassPath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
)
- val cp = AggregateFlatClassPath(partialClassPaths)
+ val cp = AggregateClassPath(partialClassPaths)
val sourcesInPkg1 = Seq(sourceFileEntry(dir2, pkg1, "C"),
sourceFileEntry(dir2, pkg1, "B"),
@@ -190,7 +191,7 @@ class AggregateFlatClassPathTest {
)
assertEquals(classesAndSourcesInPkg1, cp.list(pkg1).classesAndSources)
- assertEquals(FlatClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
+ assertEquals(ClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
}
@Test
diff --git a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala b/test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala
index 5dee488285..d3d4289d8b 100644
--- a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
+++ b/test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala
@@ -9,20 +9,17 @@ import org.junit._
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import scala.annotation.tailrec
-import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.Settings
-import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
@RunWith(classOf[JUnit4])
-class FlatClassPathResolverTest {
+class PathResolverBaseTest {
val tempDir = new TemporaryFolder()
- private val packagesToTest = List(FlatClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
- private val classFilesToFind = List("scala.tools.util.FlatClassPathResolver",
+ private val packagesToTest = List(ClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
+ private val classFilesToFind = List("scala.tools.util.PathResolver",
"scala.reflect.io.AbstractFile",
"scala.collection.immutable.List",
"scala.Option",
@@ -60,7 +57,7 @@ class FlatClassPathResolverTest {
def deleteTempDir: Unit = tempDir.delete()
private def createFlatClassPath(settings: Settings) =
- new FlatClassPathResolver(settings).result
+ new PathResolver(settings).result
@Test
def testEntriesFromListOperationAgainstSeparateMethods: Unit = {
@@ -70,7 +67,7 @@ class FlatClassPathResolverTest {
val packages = classPath.packages(inPackage)
val classes = classPath.classes(inPackage)
val sources = classPath.sources(inPackage)
- val FlatClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
+ val ClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
val packageNames = packages.map(_.name).sorted
val packageNamesFromList = packagesFromList.map(_.name).sorted
@@ -96,52 +93,6 @@ class FlatClassPathResolverTest {
}
@Test
- def testCreatedEntriesAgainstRecursiveClassPath: Unit = {
- val flatClassPath = createFlatClassPath(settings)
- val recursiveClassPath = new PathResolver(settings).result
-
- def compareEntriesInPackage(inPackage: String): Unit = {
-
- @tailrec
- def traverseToPackage(packageNameParts: Seq[String], cp: ClassPath[AbstractFile]): ClassPath[AbstractFile] = {
- packageNameParts match {
- case Nil => cp
- case h :: t =>
- cp.packages.find(_.name == h) match {
- case Some(nestedCp) => traverseToPackage(t, nestedCp)
- case _ => throw new Exception(s"There's no package $inPackage in recursive classpath - error when searching for '$h'")
- }
- }
- }
-
- val packageNameParts = if (inPackage == FlatClassPath.RootPackage) Nil else inPackage.split('.').toList
- val recursiveClassPathInPackage = traverseToPackage(packageNameParts, recursiveClassPath)
-
- val flatCpPackages = flatClassPath.packages(inPackage).map(_.name)
- val pkgPrefix = PackageNameUtils.packagePrefix(inPackage)
- val recursiveCpPackages = recursiveClassPathInPackage.packages.map(pkgPrefix + _.name)
- assertEquals(s"Packages in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpPackages, flatCpPackages)
-
- val flatCpSources = flatClassPath.sources(inPackage).map(_.name).sorted
- val recursiveCpSources = recursiveClassPathInPackage.classes
- .filter(_.source.nonEmpty)
- .map(_.name).sorted
- assertEquals(s"Source entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpSources, flatCpSources)
-
- val flatCpClasses = flatClassPath.classes(inPackage).map(_.name).sorted
- val recursiveCpClasses = recursiveClassPathInPackage.classes
- .filter(_.binary.nonEmpty)
- .map(_.name).sorted
- assertEquals(s"Class entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpClasses, flatCpClasses)
- }
-
- packagesToTest foreach compareEntriesInPackage
- }
-
- @Test
def testFindClassFile: Unit = {
val classPath = createFlatClassPath(settings)
classFilesToFind foreach { className =>
diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index 812c298c48..8cc7aefdd3 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -3,11 +3,8 @@ package symtab
import scala.reflect.ClassTag
import scala.reflect.internal.{NoPhase, Phase, SomePhase}
-import scala.tools.nsc.classpath.FlatClassPath
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
-import util.{ClassFileLookup, ClassPath}
+import util.ClassPath
import io.AbstractFile
/**
@@ -30,8 +27,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
override def isCompilerUniverse: Boolean = true
- def classPath = platform.classPath
- def flatClassPath: FlatClassPath = platform.flatClassPath
+ def classPath: ClassPath = platform.classPath
object platform extends backend.Platform {
val symbolTable: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
@@ -39,22 +35,12 @@ class SymbolTableForUnitTesting extends SymbolTable {
def platformPhases: List[SubComponent] = Nil
- lazy val classPath: ClassPath[AbstractFile] = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
- "It's not possible to use the recursive classpath representation, when it's not the chosen classpath scanning method")
- new PathResolver(settings).result
- }
-
- private[nsc] lazy val flatClassPath: FlatClassPath = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
- "It's not possible to use the flat classpath representation, when it's not the chosen classpath scanning method")
- new FlatClassPathResolver(settings).result
- }
+ private[nsc] lazy val classPath: ClassPath = new PathResolver(settings).result
def isMaybeBoxed(sym: Symbol): Boolean = ???
def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = ???
def externalEquals: Symbol = ???
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]]): Unit = ???
+ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = ???
}
object loaders extends symtab.SymbolLoaders {
@@ -69,10 +55,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
class GlobalMirror extends Roots(NoSymbol) {
val universe: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
- def rootLoader: LazyType = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
- case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(classPath)
- }
+ def rootLoader: LazyType = new loaders.PackageLoader(ClassPath.RootPackage, classPath)
override def toString = "compiler mirror"
}
diff --git a/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
deleted file mode 100644
index f2926e3e17..0000000000
--- a/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.util
-
-import scala.reflect.io.AbstractFile
-import scala.tools.nsc.Settings
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.util.PathResolverFactory
-
-/**
- * Simple application to compare efficiency of the recursive and the flat classpath representations
- */
-object ClassPathImplComparator {
-
- private class TestSettings extends Settings {
- val checkClasses = PathSetting("-checkClasses", "Specify names of classes which should be found separated with ;", "")
- val requiredIterations = IntSetting("-requiredIterations",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- val cpCreationRepetitions = IntSetting("-cpCreationRepetitions",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- val cpLookupRepetitions = IntSetting("-cpLookupRepetitions",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- }
-
- private class DurationStats(name: String) {
- private var sum = 0L
- private var iterations = 0
-
- def noteMeasuredTime(millis: Long): Unit = {
- sum += millis
- iterations += 1
- }
-
- def printResults(): Unit = {
- val avg = if (iterations == 0) 0 else sum.toDouble / iterations
- println(s"$name - total duration: $sum ms; iterations: $iterations; avg: $avg ms")
- }
- }
-
- private lazy val defaultClassesToFind = List(
- "scala.collection.immutable.List",
- "scala.Option",
- "scala.Int",
- "scala.collection.immutable.Vector",
- "scala.util.hashing.MurmurHash3"
- )
-
- private val oldCpCreationStats = new DurationStats("Old classpath - create")
- private val oldCpSearchingStats = new DurationStats("Old classpath - search")
-
- private val flatCpCreationStats = new DurationStats("Flat classpath - create")
- private val flatCpSearchingStats = new DurationStats("Flat classpath - search")
-
- def main(args: Array[String]): Unit = {
-
- if (args contains "-help")
- usage()
- else {
- val oldCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Recursive)
- val flatCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Flat)
-
- val classesToCheck = oldCpSettings.checkClasses.value
- val classesToFind =
- if (classesToCheck.isEmpty) defaultClassesToFind
- else classesToCheck.split(";").toList
-
- def doTest(classPath: => ClassFileLookup[AbstractFile], cpCreationStats: DurationStats, cpSearchingStats: DurationStats,
- cpCreationRepetitions: Int, cpLookupRepetitions: Int)= {
-
- def createClassPaths() = (1 to cpCreationRepetitions).map(_ => classPath).last
- def testClassLookup(cp: ClassFileLookup[AbstractFile]): Boolean = (1 to cpCreationRepetitions).foldLeft(true) {
- case (a, _) => a && checkExistenceOfClasses(classesToFind)(cp)
- }
-
- val cp = withMeasuredTime("Creating classpath", createClassPaths(), cpCreationStats)
- val result = withMeasuredTime("Searching for specified classes", testClassLookup(cp), cpSearchingStats)
- println(s"The end of the test case. All expected classes found = $result \n")
- }
-
- (1 to oldCpSettings.requiredIterations.value) foreach { iteration =>
- if (oldCpSettings.requiredIterations.value > 1)
- println(s"Iteration no $iteration")
-
- println("Recursive (old) classpath representation:")
- doTest(PathResolverFactory.create(oldCpSettings).result, oldCpCreationStats, oldCpSearchingStats,
- oldCpSettings.cpCreationRepetitions.value, oldCpSettings.cpLookupRepetitions.value)
-
- println("Flat classpath representation:")
- doTest(PathResolverFactory.create(flatCpSettings).result, flatCpCreationStats, flatCpSearchingStats,
- flatCpSettings.cpCreationRepetitions.value, flatCpSettings.cpLookupRepetitions.value)
- }
-
- if (oldCpSettings.requiredIterations.value > 1) {
- println("\nOld classpath - summary")
- oldCpCreationStats.printResults()
- oldCpSearchingStats.printResults()
-
- println("\nFlat classpath - summary")
- flatCpCreationStats.printResults()
- flatCpSearchingStats.printResults()
- }
- }
- }
-
- /**
- * Prints usage information
- */
- private def usage(): Unit =
- println("""Use classpath and sourcepath options like in the case of e.g. 'scala' command.
- | There are also two additional options:
- | -checkClasses <semicolon separated class names> Specify names of classes which should be found
- | -requiredIterations <int value> Repeat tests specified count of times (to check e.g. impact of caches)
- | Note: Option -YclasspathImpl will be set automatically for each case.
- """.stripMargin.trim)
-
- private def loadSettings(args: List[String], implType: String) = {
- val settings = new TestSettings()
- settings.processArguments(args, processAll = true)
- settings.YclasspathImpl.value = implType
- if (settings.classpath.isDefault)
- settings.classpath.value = sys.props("java.class.path")
- settings
- }
-
- private def withMeasuredTime[T](operationName: String, f: => T, durationStats: DurationStats): T = {
- val startTime = System.currentTimeMillis()
- val res = f
- val elapsed = System.currentTimeMillis() - startTime
- durationStats.noteMeasuredTime(elapsed)
- println(s"$operationName - elapsed $elapsed ms")
- res
- }
-
- private def checkExistenceOfClasses(classesToCheck: Seq[String])(classPath: ClassFileLookup[AbstractFile]): Boolean =
- classesToCheck.foldLeft(true) {
- case (res, classToCheck) =>
- val found = classPath.findClass(classToCheck).isDefined
- if (!found)
- println(s"Class $classToCheck not found") // of course in this case the measured time will be affected by IO operation
- found
- }
-}
diff --git a/test/junit/scala/util/matching/RegexTest.scala b/test/junit/scala/util/matching/RegexTest.scala
index 5b13397d6a..06d0445e1c 100644
--- a/test/junit/scala/util/matching/RegexTest.scala
+++ b/test/junit/scala/util/matching/RegexTest.scala
@@ -6,6 +6,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import scala.tools.testing.AssertUtil._
+
@RunWith(classOf[JUnit4])
class RegexTest {
@Test def t8022CharSequence(): Unit = {
@@ -44,4 +46,66 @@ class RegexTest {
}
assertEquals(List((1,2),(3,4),(5,6)), z)
}
+
+ @Test def `SI-9666: use inline group names`(): Unit = {
+ val r = new Regex("a(?<Bee>b*)c")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertFalse(ms.hasNext)
+ }
+
+ @Test def `SI-9666: use explicit group names`(): Unit = {
+ val r = new Regex("a(b*)c", "Bee")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertFalse(ms.hasNext)
+ }
+
+ @Test def `SI-9666: fall back to explicit group names`(): Unit = {
+ val r = new Regex("a(?<Bar>b*)c", "Bee")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertEquals("bbb", ms group "Bar")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertEquals("b", ms group "Bar")
+ assertFalse(ms.hasNext)
+ }
+
+ //type NoGroup = NoSuchElementException
+ type NoGroup = IllegalArgumentException
+
+ @Test def `SI-9666: throw on bad name`(): Unit = {
+ assertThrows[NoGroup] {
+ val r = new Regex("a(?<Bar>b*)c")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ assertThrows[NoGroup] {
+ val r = new Regex("a(?<Bar>b*)c", "Bar")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ assertThrows[NoGroup] {
+ val r = new Regex("a(b*)c", "Bar")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ }
}
diff --git a/versions.properties b/versions.properties
index 2ab66086fb..0d80d5b1cf 100644
--- a/versions.properties
+++ b/versions.properties
@@ -30,7 +30,7 @@ jline.version=2.14.1
scala-asm.version=5.0.4-scala-3
# external modules, used internally (not shipped)
-partest.version.number=1.0.13
+partest.version.number=1.0.14
scalacheck.version.number=1.11.6
# TODO: modularize the compiler