summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2013-08-06 08:03:17 -0700
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2013-08-06 08:03:17 -0700
commit4c62f7db6f3913eedd92d85daf8f631149cc97b2 (patch)
treec0f8381276e4f7fc1726d1eac3a3838f5c6a95ce /src/compiler
parent46616ea2e94fa6ac7100b1cde66295f68338e18e (diff)
parentd5e0f728c322a3beec5c62a9f4e28b3a3f86e84d (diff)
downloadscala-4c62f7db6f3913eedd92d85daf8f631149cc97b2.tar.gz
scala-4c62f7db6f3913eedd92d85daf8f631149cc97b2.tar.bz2
scala-4c62f7db6f3913eedd92d85daf8f631149cc97b2.zip
Merge pull request #2776 from gkossakowski/symbolTable-refactorings
Refactor the cake so SymbolTable does not depend on Global
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala25
-rw-r--r--src/compiler/scala/tools/nsc/GlobalSymbolLoaders.scala30
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala26
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala21
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala24
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala22
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala55
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala156
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala91
11 files changed, 261 insertions, 201 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 20cb1dab5b..a6c69091c5 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -51,7 +51,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
class GlobalMirror extends Roots(NoSymbol) {
val universe: self.type = self
- def rootLoader: LazyType = platform.rootLoader
+ def rootLoader: LazyType = new loaders.PackageLoader(classPath)
override def toString = "compiler mirror"
}
@@ -83,12 +83,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// platform specific elements
- type ThisPlatform = Platform { val global: Global.this.type }
+ protected class GlobalPlatform extends {
+ val global: Global.this.type = Global.this
+ val settings: Settings = Global.this.settings
+ } with JavaPlatform
- lazy val platform: ThisPlatform =
- new { val global: Global.this.type = Global.this } with JavaPlatform
+ type ThisPlatform = JavaPlatform { val global: Global.this.type }
+ lazy val platform: ThisPlatform = new GlobalPlatform
- type PlatformClassPath = ClassPath[platform.BinaryRepr]
+ type PlatformClassPath = ClassPath[AbstractFile]
type OptClassPath = Option[PlatformClassPath]
def classPath: PlatformClassPath = platform.classPath
@@ -268,12 +271,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
log("!!! " + msg) // such warnings always at least logged
}
- private def elapsedMessage(msg: String, start: Long) =
- msg + " in " + (currentTime - start) + "ms"
-
def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg))
- def informProgress(msg: String) = if (settings.verbose) inform("[" + msg + "]")
- def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start))
def logError(msg: String, t: Throwable): Unit = ()
@@ -357,9 +355,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
getSourceFile(f)
}
- lazy val loaders = new SymbolLoaders {
+ lazy val loaders = new {
val global: Global.this.type = Global.this
- }
+ val platform: Global.this.platform.type = Global.this.platform
+ } with GlobalSymbolLoaders
/** Returns the mirror that loaded given symbol */
def mirrorThatLoaded(sym: Symbol): Mirror = rootMirror
@@ -914,7 +913,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]) {
ifDebug(informProgress(s"syncing $root, $oldEntries -> $newEntries"))
- val getName: ClassPath[platform.BinaryRepr] => String = (_.name)
+ val getName: ClassPath[AbstractFile] => String = (_.name)
def hasClasses(cp: OptClassPath) = cp.isDefined && cp.get.classes.nonEmpty
def invalidateOrRemove(root: ClassSymbol) = {
allEntries match {
diff --git a/src/compiler/scala/tools/nsc/GlobalSymbolLoaders.scala b/src/compiler/scala/tools/nsc/GlobalSymbolLoaders.scala
new file mode 100644
index 0000000000..6921548230
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/GlobalSymbolLoaders.scala
@@ -0,0 +1,30 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala
+package tools
+package nsc
+
+/**
+ * Symbol loaders implementation that wires dependencies using Global.
+ */
+abstract class GlobalSymbolLoaders extends symtab.SymbolLoaders {
+ val global: Global
+ val symbolTable: global.type = global
+ val platform: symbolTable.platform.type
+ import global._
+ def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol = {
+ def lookup = sym.info.member(name)
+ // if loading during initialization of `definitions` typerPhase is not yet set.
+ // in that case we simply load the member at the current phase
+ if (currentRun.typerPhase eq null)
+ lookup
+ else
+ enteringTyper { lookup }
+ }
+
+ protected def compileLate(srcfile: io.AbstractFile): Unit =
+ currentRun.compileLate(srcfile)
+}
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index c5fc12e3ec..32b5a98b98 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -11,33 +11,22 @@ import util.{ClassPath,MergedClassPath,DeltaClassPath}
import scala.tools.util.PathResolver
trait JavaPlatform extends Platform {
+ val global: Global
+ override val symbolTable: global.type = global
import global._
import definitions._
- type BinaryRepr = AbstractFile
+ private var currentClassPath: Option[MergedClassPath[AbstractFile]] = None
- private var currentClassPath: Option[MergedClassPath[BinaryRepr]] = None
-
- def classPath: ClassPath[BinaryRepr] = {
+ def classPath: ClassPath[AbstractFile] = {
if (currentClassPath.isEmpty) currentClassPath = Some(new PathResolver(settings).result)
currentClassPath.get
}
/** Update classpath with a substituted subentry */
- def updateClassPath(subst: Map[ClassPath[BinaryRepr], ClassPath[BinaryRepr]]) =
+ def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]) =
currentClassPath = Some(new DeltaClassPath(currentClassPath.get, subst))
- def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]])
- // [Martin] Why do we need a cast here?
- // The problem is that we cannot specify at this point that global.platform should be of type JavaPlatform.
- // So we cannot infer that global.platform.BinaryRepr is AbstractFile.
- // Ideally, we should be able to write at the top of the JavaPlatform trait:
- // val global: Global { val platform: JavaPlatform }
- // import global._
- // Right now, this does nothing because the concrete definition of platform in Global
- // replaces the tighter abstract definition here. If we had DOT typing rules, the two
- // types would be conjoined and everything would work out. Yet another reason to push for DOT.
-
private def classEmitPhase =
if (settings.isBCodeActive) genBCode
else genASM
@@ -66,10 +55,7 @@ trait JavaPlatform extends Platform {
(sym isNonBottomSubClass BoxedBooleanClass)
}
- def newClassLoader(bin: AbstractFile): loaders.SymbolLoader =
- new loaders.ClassfileLoader(bin)
-
- def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = true
+ def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean = true
def needCompile(bin: AbstractFile, src: AbstractFile) =
src.lastModified >= bin.lastModified
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index e2b22c06d7..3bca16635b 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -12,20 +12,18 @@ import io.AbstractFile
/** The platform dependent pieces of Global.
*/
trait Platform {
- val global: Global
- import global._
+ val symbolTable: symtab.SymbolTable
+ import symbolTable._
/** The binary classfile representation type */
- type BinaryRepr
+ @deprecated("BinaryRepr is not an abstract type anymore. It's an alias that points at AbstractFile. It'll be removed before Scala 2.11 is released.", "2.11.0-M5")
+ type BinaryRepr = AbstractFile
/** The compiler classpath. */
- def classPath: ClassPath[BinaryRepr]
-
- /** The root symbol loader. */
- def rootLoader: LazyType
+ def classPath: ClassPath[AbstractFile]
/** Update classpath with a substitution that maps entries to entries */
- def updateClassPath(subst: Map[ClassPath[BinaryRepr], ClassPath[BinaryRepr]])
+ def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]])
/** Any platform-specific phases. */
def platformPhases: List[SubComponent]
@@ -36,16 +34,13 @@ trait Platform {
/** The various ways a boxed primitive might materialize at runtime. */
def isMaybeBoxed(sym: Symbol): Boolean
- /** Create a new class loader to load class file `bin` */
- def newClassLoader(bin: BinaryRepr): loaders.SymbolLoader
-
/**
* Tells whether a class should be loaded and entered into the package
* scope. On .NET, this method returns `false` for all synthetic classes
* (anonymous classes, implementation classes, module classes), their
* symtab is encoded in the pickle of another class.
*/
- def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean
+ def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean
/**
* Tells whether a class with both a binary and a source representation
@@ -53,6 +48,6 @@ trait Platform {
* on the JVM similar to javac, i.e. if the source file is newer than the classfile,
* a re-compile is triggered. On .NET by contrast classfiles always take precedence.
*/
- def needCompile(bin: BinaryRepr, src: AbstractFile): Boolean
+ def needCompile(bin: AbstractFile, src: AbstractFile): Boolean
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index e6f21fc1e3..410d451316 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1479,26 +1479,18 @@ abstract class GenICode extends SubComponent {
if (mustUseAnyComparator) {
// when -optimise is on we call the @inline-version of equals, found in ScalaRunTime
- val equalsMethod =
+ val equalsMethod: Symbol = {
if (!settings.optimise) {
- def default = platform.externalEquals
- platform match {
- case x: JavaPlatform =>
- import x._
- if (l.tpe <:< BoxedNumberClass.tpe) {
- if (r.tpe <:< BoxedNumberClass.tpe) externalEqualsNumNum
- else if (r.tpe <:< BoxedCharacterClass.tpe) externalEqualsNumChar
- else externalEqualsNumObject
- }
- else default
-
- case _ => default
- }
- }
- else {
+ if (l.tpe <:< BoxedNumberClass.tpe) {
+ if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum
+ else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar
+ else platform.externalEqualsNumObject
+ } else platform.externalEquals
+ } else {
ctx.bb.emit(LOAD_MODULE(ScalaRunTimeModule))
getMember(ScalaRunTimeModule, nme.inlinedEquals)
}
+ }
val ctx1 = genLoad(l, ctx, ObjectReference)
val ctx2 = genLoad(r, ctx1, ObjectReference)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index 3f2141782a..b9eb8f8aac 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -10,6 +10,7 @@ package icode
import java.io.PrintWriter
import analysis.{ Liveness, ReachingDefinitions }
import scala.tools.nsc.symtab.classfile.ICodeReader
+import scala.reflect.io.AbstractFile
/** Glue together ICode parts.
*
@@ -108,6 +109,12 @@ abstract class ICodes extends AnyRef
object icodeReader extends ICodeReader {
lazy val global: ICodes.this.global.type = ICodes.this.global
+ import global._
+ def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol =
+ global.loaders.lookupMemberAtTyperPhaseIfPossible(sym, name)
+ lazy val symbolTable: global.type = global
+ lazy val loaders: global.loaders.type = global.loaders
+ def classPath: util.ClassPath[AbstractFile] = ICodes.this.global.platform.classPath
}
/** A phase which works on icode. */
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index a7f43eefed..683f35e41f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -1187,22 +1187,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
if (mustUseAnyComparator) {
- val equalsMethod = {
-
- def default = platform.externalEquals
-
- platform match {
- case x: JavaPlatform =>
- import x._
- if (l.tpe <:< BoxedNumberClass.tpe) {
- if (r.tpe <:< BoxedNumberClass.tpe) externalEqualsNumNum
- else if (r.tpe <:< BoxedCharacterClass.tpe) externalEqualsNumChar
- else externalEqualsNumObject
- }
- else default
-
- case _ => default
- }
+ val equalsMethod: Symbol = {
+ if (l.tpe <:< BoxedNumberClass.tpe) {
+ if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum
+ else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar
+ else platform.externalEqualsNumObject
+ } else platform.externalEquals
}
genLoad(l, ObjectReference)
genLoad(r, ObjectReference)
diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
index 4e4efef607..4b9e056df3 100644
--- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
@@ -12,9 +12,10 @@ import scala.tools.nsc.io.AbstractFile
* This class should be used whenever file dependencies and recompile sets
* are managed automatically.
*/
-abstract class BrowsingLoaders extends SymbolLoaders {
- import global._
+abstract class BrowsingLoaders extends GlobalSymbolLoaders {
+ val global: Global
+ import global._
import syntaxAnalyzer.{OutlineParser, MalformedInput}
/** In browse mode, it can happen that an encountered symbol is already
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index fd85bbb169..6f27eb8660 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -20,8 +20,23 @@ import scala.reflect.io.{ AbstractFile, NoAbstractFile }
* @version 1.0
*/
abstract class SymbolLoaders {
- val global: Global
- import global._
+ val symbolTable: symtab.SymbolTable {
+ def settings: Settings
+ }
+ val platform: backend.Platform {
+ val symbolTable: SymbolLoaders.this.symbolTable.type
+ }
+ import symbolTable._
+ /**
+ * Required by ClassfileParser. Check documentation in that class for details.
+ */
+ def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol
+ /**
+ * Should forward to `Run.compileLate`. The more principled fix would be to
+ * determine why this functionality is needed and extract it into a separate
+ * interface.
+ */
+ protected def compileLate(srcfile: AbstractFile): Unit
import SymbolLoadersStats._
protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
@@ -75,14 +90,14 @@ abstract class SymbolLoaders {
name+"\none of them needs to be removed from classpath"
)
else if (settings.termConflict.value == "package") {
- global.warning(
+ warning(
"Resolving package/object name conflict in favor of package " +
preExisting.fullName + ". The object will be inaccessible."
)
root.info.decls.unlink(preExisting)
}
else {
- global.warning(
+ warning(
"Resolving package/object name conflict in favor of object " +
preExisting.fullName + ". The package will be inaccessible."
)
@@ -139,17 +154,17 @@ abstract class SymbolLoaders {
/** Initialize toplevel class and module symbols in `owner` from class path representation `classRep`
*/
- def initializeFromClassPath(owner: Symbol, classRep: ClassPath[platform.BinaryRepr]#ClassRep) {
+ def initializeFromClassPath(owner: Symbol, classRep: ClassPath[AbstractFile]#ClassRep) {
((classRep.binary, classRep.source) : @unchecked) match {
case (Some(bin), Some(src))
if platform.needCompile(bin, src) && !binaryOnly(owner, classRep.name) =>
if (settings.verbose) inform("[symloader] picked up newer source file for " + src.path)
- global.loaders.enterToplevelsFromSource(owner, classRep.name, src)
+ enterToplevelsFromSource(owner, classRep.name, src)
case (None, Some(src)) =>
if (settings.verbose) inform("[symloader] no class, picked up source file for " + src.path)
- global.loaders.enterToplevelsFromSource(owner, classRep.name, src)
+ enterToplevelsFromSource(owner, classRep.name, src)
case (Some(bin), _) =>
- global.loaders.enterClassAndModule(owner, classRep.name, platform.newClassLoader(bin))
+ enterClassAndModule(owner, classRep.name, new ClassfileLoader(bin))
}
}
@@ -221,7 +236,7 @@ abstract class SymbolLoaders {
/**
* Load contents of a package
*/
- class PackageLoader(classpath: ClassPath[platform.BinaryRepr]) extends SymbolLoader with FlagAgnosticCompleter {
+ class PackageLoader(classpath: ClassPath[AbstractFile]) extends SymbolLoader with FlagAgnosticCompleter {
protected def description = "package loader "+ classpath.name
protected def doComplete(root: Symbol) {
@@ -245,8 +260,24 @@ abstract class SymbolLoaders {
class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader with FlagAssigningCompleter {
private object classfileParser extends {
- val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global
- } with ClassfileParser
+ val symbolTable: SymbolLoaders.this.symbolTable.type = SymbolLoaders.this.symbolTable
+ } with ClassfileParser {
+ override protected type ThisConstantPool = ConstantPool
+ override protected def newConstantPool: ThisConstantPool = new ConstantPool
+ override protected def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol =
+ SymbolLoaders.this.lookupMemberAtTyperPhaseIfPossible(sym, name)
+ /*
+ * The type alias and the cast (where the alias is used) is needed due to problem described
+ * in SI-7585. In this particular case, the problem is that we need to make sure that symbol
+ * table used by symbol loaders is exactly the same as they one used by classfileParser.
+ * If you look at the path-dependent types we have here everything should work out ok but
+ * due to issue described in SI-7585 type-checker cannot tie the knot here.
+ *
+ */
+ private type SymbolLoadersRefined = SymbolLoaders { val symbolTable: classfileParser.symbolTable.type }
+ val loaders = SymbolLoaders.this.asInstanceOf[SymbolLoadersRefined]
+ val classPath = platform.classPath
+ }
protected def description = "class file "+ classfile.toString
@@ -272,7 +303,7 @@ abstract class SymbolLoaders {
protected def description = "source file "+ srcfile.toString
override def fromSource = true
override def sourcefile = Some(srcfile)
- protected def doComplete(root: Symbol): Unit = global.currentRun.compileLate(srcfile)
+ protected def doComplete(root: Symbol): Unit = compileLate(srcfile)
}
object moduleClassLoader extends SymbolLoader with FlagAssigningCompleter {
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index e4e3862bcd..c6ea6b23e5 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -17,6 +17,7 @@ import scala.reflect.internal.{ JavaAccFlags }
import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs}
import scala.tools.nsc.io.AbstractFile
+import util.ClassPath
/** This abstract class implements a class file parser.
*
@@ -24,18 +25,40 @@ import scala.tools.nsc.io.AbstractFile
* @version 1.0
*/
abstract class ClassfileParser {
- val global: Global
- import global._
+ val symbolTable: SymbolTable {
+ def settings: Settings
+ }
+ val loaders: SymbolLoaders {
+ val symbolTable: ClassfileParser.this.symbolTable.type
+ }
+
+ import symbolTable._
+ /**
+ * If typer phase is defined then perform member lookup of a symbol
+ * `sym` at typer phase. This method results from refactoring. The
+ * original author of the logic that uses typer phase didn't explain
+ * why we need to force infos at that phase specifically. It only mentioned
+ * that ClassfileParse can be called late (e.g. at flatten phase) and
+ * we make to make sure we handle such situation properly.
+ */
+ protected def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol
+
+ /** The compiler classpath. */
+ def classPath: ClassPath[AbstractFile]
+
import definitions._
import scala.reflect.internal.ClassfileConstants._
import Flags._
+ protected type ThisConstantPool <: ConstantPool
+ protected def newConstantPool: ThisConstantPool
+
protected var in: AbstractFileReader = _ // the class file reader
protected var clazz: Symbol = _ // the class symbol containing dynamic members
protected var staticModule: Symbol = _ // the module symbol containing static members
protected var instanceScope: Scope = _ // the scope of all instance definitions
protected var staticScope: Scope = _ // the scope of all static definitions
- protected var pool: ConstantPool = _ // the classfile's constant pool
+ protected var pool: ThisConstantPool = _ // the classfile's constant pool
protected var isScala: Boolean = _ // does class file describe a scala class?
protected var isScalaAnnot: Boolean = _ // does class file describe a scala class with its pickled info in an annotation?
protected var isScalaRaw: Boolean = _ // this class file is a scala class with no pickled info
@@ -50,7 +73,7 @@ abstract class ClassfileParser {
def srcfile = srcfile0
- private def optimized = global.settings.optimise.value
+ private def optimized = settings.optimise.value
private def currentIsTopLevel = !(currentClass.decodedName containsChar '$')
// u1, u2, and u4 are what these data types are called in the JVM spec.
@@ -70,7 +93,7 @@ abstract class ClassfileParser {
private def readType() = pool getType u2
private object unpickler extends scala.reflect.internal.pickling.UnPickler {
- val global: ClassfileParser.this.global.type = ClassfileParser.this.global
+ val symbolTable: ClassfileParser.this.symbolTable.type = ClassfileParser.this.symbolTable
}
private def handleMissing(e: MissingRequirementError) = {
@@ -119,7 +142,7 @@ abstract class ClassfileParser {
this.isScala = false
parseHeader()
- this.pool = new ConstantPool
+ this.pool = newConstantPool
parseClass()
}
}
@@ -134,11 +157,14 @@ abstract class ClassfileParser {
abort(s"class file ${in.file} has unknown version $major.$minor, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION")
}
- class ConstantPool {
- private val len = u2
- private val starts = new Array[Int](len)
- private val values = new Array[AnyRef](len)
- private val internalized = new Array[Name](len)
+ /**
+ * Constructor of this class should not be called directly, use `newConstantPool` instead.
+ */
+ protected class ConstantPool {
+ protected val len = u2
+ protected val starts = new Array[Int](len)
+ protected val values = new Array[AnyRef](len)
+ protected val internalized = new Array[Name](len)
{ var i = 1
while (i < starts.length) {
@@ -212,76 +238,13 @@ abstract class ClassfileParser {
getExternalName((in getChar start).toInt)
}
- /** Return the symbol of the class member at `index`.
- * The following special cases exist:
- * - If the member refers to special `MODULE$` static field, return
- * the symbol of the corresponding module.
- * - If the member is a field, and is not found with the given name,
- * another try is made by appending `nme.LOCAL_SUFFIX_STRING`
- * - If no symbol is found in the right tpe, a new try is made in the
- * companion class, in case the owner is an implementation class.
- */
- def getMemberSymbol(index: Int, static: Boolean): Symbol = {
- if (index <= 0 || len <= index) errorBadIndex(index)
- var f = values(index).asInstanceOf[Symbol]
- if (f eq null) {
- val start = starts(index)
- val first = in.buf(start).toInt
- if (first != CONSTANT_FIELDREF &&
- first != CONSTANT_METHODREF &&
- first != CONSTANT_INTFMETHODREF) errorBadTag(start)
- val ownerTpe = getClassOrArrayType(in.getChar(start + 1).toInt)
- debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.originalName)
- val (name0, tpe0) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
- debuglog("getMemberSymbol: name and tpe: " + name0 + ": " + tpe0)
-
- forceMangledName(tpe0.typeSymbol.name, module = false)
- val (name, tpe) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
- if (name == nme.MODULE_INSTANCE_FIELD) {
- val index = in.getChar(start + 1).toInt
- val name = getExternalName(in.getChar(starts(index).toInt + 1).toInt)
- //assert(name.endsWith("$"), "Not a module class: " + name)
- f = forceMangledName(name dropRight 1, module = true)
- if (f == NoSymbol)
- f = rootMirror.getModuleByName(name dropRight 1)
- } else {
- val origName = nme.unexpandedName(name)
- val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
- f = owner.info.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe.widen =:= tpe)
- if (f == NoSymbol)
- f = owner.info.findMember(newTermName(origName + nme.LOCAL_SUFFIX_STRING), 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
- if (f == NoSymbol) {
- // if it's an impl class, try to find it's static member inside the class
- if (ownerTpe.typeSymbol.isImplClass) {
- f = ownerTpe.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
- } else {
- log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe)
- f = tpe match {
- case MethodType(_, _) => owner.newMethod(name.toTermName, owner.pos)
- case _ => owner.newVariable(name.toTermName, owner.pos)
- }
- f setInfo tpe
- log("created fake member " + f.fullName)
- }
- }
- }
- assert(f != NoSymbol,
- s"could not find $name: $tpe in $ownerTpe" + (
- if (settings.debug.value) ownerTpe.members.mkString(", members are:\n ", "\n ", "") else ""
- )
- )
- values(index) = f
- }
- f
- }
-
/** Return a name and a type at the given index. If the type is a method
* type, a dummy symbol is created in `ownerTpe`, which is used as the
* owner of its value parameters. This might lead to inconsistencies,
* if a symbol of the given name already exists, and has a different
* type.
*/
- private def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = {
+ protected def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = {
if (index <= 0 || len <= index) errorBadIndex(index)
values(index) match {
case p: ((Name @unchecked, Type @unchecked)) => p
@@ -381,37 +344,16 @@ abstract class ClassfileParser {
}
/** Throws an exception signaling a bad constant index. */
- private def errorBadIndex(index: Int) =
+ protected def errorBadIndex(index: Int) =
abort(s"bad constant pool index: $index at pos: ${in.bp}")
/** Throws an exception signaling a bad tag at given address. */
- private def errorBadTag(start: Int) =
+ protected def errorBadTag(start: Int) =
abort("bad constant pool tag ${in.buf(start)} at byte $start")
}
- /** Try to force the chain of enclosing classes for the given name. Otherwise
- * flatten would not lift classes that were not referenced in the source code.
- */
- def forceMangledName(name: Name, module: Boolean): Symbol = {
- val parts = name.decode.toString.split(Array('.', '$'))
- var sym: Symbol = rootMirror.RootClass
-
- // was "at flatten.prev"
- enteringFlatten {
- for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) {
- val sym1 = enteringIcode {
- sym.linkedClassOfClass.info
- sym.info.decl(part.encode)
- }//.suchThat(module == _.isModule)
-
- sym = sym1 orElse sym.info.decl(part.encode.toTypeName)
- }
- }
- sym
- }
-
private def loadClassSymbol(name: Name): Symbol = {
- val file = global.classPath findSourceFile ("" +name) getOrElse {
+ val file = classPath findSourceFile ("" +name) 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)
@@ -419,7 +361,7 @@ abstract class ClassfileParser {
warning(s"Class $name not found - continuing with a stub.")
return NoSymbol.newClass(name.toTypeName)
}
- val completer = new global.loaders.ClassfileLoader(file)
+ val completer = new loaders.ClassfileLoader(file)
var owner: Symbol = rootMirror.RootClass
var sym: Symbol = NoSymbol
var ss: Name = null
@@ -1065,7 +1007,7 @@ abstract class ClassfileParser {
def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile) {
def jflags = entry.jflags
- val completer = new global.loaders.ClassfileLoader(file)
+ val completer = new loaders.ClassfileLoader(file)
val name = entry.originalName
val sflags = jflags.toScalaFlags
val owner = ownerForFlags(jflags)
@@ -1073,7 +1015,7 @@ abstract class ClassfileParser {
val innerClass = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer
val innerModule = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer
- innerModule.moduleClass setInfo global.loaders.moduleClassLoader
+ innerModule.moduleClass setInfo loaders.moduleClassLoader
List(innerClass, innerModule.moduleClass) foreach (_.associatedFile = file)
scope enter innerClass
@@ -1094,7 +1036,7 @@ abstract class ClassfileParser {
for (entry <- innerClasses.entries) {
// create a new class member for immediate inner classes
if (entry.outerName == currentClass) {
- val file = global.classPath.findSourceFile(entry.externalName.toString) getOrElse {
+ val file = classPath.findSourceFile(entry.externalName.toString) getOrElse {
throw new AssertionError(entry.externalName)
}
enterClassAndModule(entry, file)
@@ -1179,19 +1121,15 @@ abstract class ClassfileParser {
case Some(entry) => innerSymbol(entry)
case _ => NoSymbol
}
- // if loading during initialization of `definitions` typerPhase is not yet set.
- // in that case we simply load the member at the current phase
- @inline private def enteringTyperIfPossible(body: => Symbol): Symbol =
- if (currentRun.typerPhase eq null) body else enteringTyper(body)
private def innerSymbol(entry: InnerClassEntry): Symbol = {
val name = entry.originalName.toTypeName
val enclosing = entry.enclosing
def getMember = (
if (enclosing == clazz) entry.scope lookup name
- else enclosing.info member name
+ else lookupMemberAtTyperPhaseIfPossible(enclosing, name)
)
- enteringTyperIfPossible(getMember)
+ getMember
/* There used to be an assertion that this result is not NoSymbol; changing it to an error
* revealed it had been going off all the time, but has been swallowed by a catch t: Throwable
* in Repository.scala. Since it has been accomplishing nothing except misleading anyone who
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 01a117895f..f704d8ac89 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -20,6 +20,8 @@ import scala.reflect.internal.JavaAccFlags
*/
abstract class ICodeReader extends ClassfileParser {
val global: Global
+ val symbolTable: global.type
+ val loaders: global.loaders.type
import global._
import icodes._
@@ -28,6 +30,95 @@ abstract class ICodeReader extends ClassfileParser {
var method: IMethod = NoIMethod // the current IMethod
var isScalaModule = false
+ override protected type ThisConstantPool = ICodeConstantPool
+ override protected def newConstantPool = new ICodeConstantPool
+
+ /** Try to force the chain of enclosing classes for the given name. Otherwise
+ * flatten would not lift classes that were not referenced in the source code.
+ */
+ def forceMangledName(name: Name, module: Boolean): Symbol = {
+ val parts = name.decode.toString.split(Array('.', '$'))
+ var sym: Symbol = rootMirror.RootClass
+
+ // was "at flatten.prev"
+ enteringFlatten {
+ for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) {
+ val sym1 = enteringIcode {
+ sym.linkedClassOfClass.info
+ sym.info.decl(part.encode)
+ }//.suchThat(module == _.isModule)
+
+ sym = sym1 orElse sym.info.decl(part.encode.toTypeName)
+ }
+ }
+ sym
+ }
+
+ protected class ICodeConstantPool extends ConstantPool {
+ /** Return the symbol of the class member at `index`.
+ * The following special cases exist:
+ * - If the member refers to special `MODULE$` static field, return
+ * the symbol of the corresponding module.
+ * - If the member is a field, and is not found with the given name,
+ * another try is made by appending `nme.LOCAL_SUFFIX_STRING`
+ * - If no symbol is found in the right tpe, a new try is made in the
+ * companion class, in case the owner is an implementation class.
+ */
+ def getMemberSymbol(index: Int, static: Boolean): Symbol = {
+ if (index <= 0 || len <= index) errorBadIndex(index)
+ var f = values(index).asInstanceOf[Symbol]
+ if (f eq null) {
+ val start = starts(index)
+ val first = in.buf(start).toInt
+ if (first != CONSTANT_FIELDREF &&
+ first != CONSTANT_METHODREF &&
+ first != CONSTANT_INTFMETHODREF) errorBadTag(start)
+ val ownerTpe = getClassOrArrayType(in.getChar(start + 1).toInt)
+ debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.originalName)
+ val (name0, tpe0) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
+ debuglog("getMemberSymbol: name and tpe: " + name0 + ": " + tpe0)
+
+ forceMangledName(tpe0.typeSymbol.name, module = false)
+ val (name, tpe) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
+ if (name == nme.MODULE_INSTANCE_FIELD) {
+ val index = in.getChar(start + 1).toInt
+ val name = getExternalName(in.getChar(starts(index).toInt + 1).toInt)
+ //assert(name.endsWith("$"), "Not a module class: " + name)
+ f = forceMangledName(name dropRight 1, module = true)
+ if (f == NoSymbol)
+ f = rootMirror.getModuleByName(name dropRight 1)
+ } else {
+ val origName = nme.unexpandedName(name)
+ val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
+ f = owner.info.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe.widen =:= tpe)
+ if (f == NoSymbol)
+ f = owner.info.findMember(newTermName(origName + nme.LOCAL_SUFFIX_STRING), 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
+ if (f == NoSymbol) {
+ // if it's an impl class, try to find it's static member inside the class
+ if (ownerTpe.typeSymbol.isImplClass) {
+ f = ownerTpe.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
+ } else {
+ log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe)
+ f = tpe match {
+ case MethodType(_, _) => owner.newMethod(name.toTermName, owner.pos)
+ case _ => owner.newVariable(name.toTermName, owner.pos)
+ }
+ f setInfo tpe
+ log("created fake member " + f.fullName)
+ }
+ }
+ }
+ assert(f != NoSymbol,
+ s"could not find $name: $tpe in $ownerTpe" + (
+ if (settings.debug.value) ownerTpe.members.mkString(", members are:\n ", "\n ", "") else ""
+ )
+ )
+ values(index) = f
+ }
+ f
+ }
+ }
+
/** Read back bytecode for the given class symbol. It returns
* two IClass objects, one for static members and one
* for non-static members.