summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-11-08 18:18:19 +0000
committerMartin Odersky <odersky@gmail.com>2011-11-08 18:18:19 +0000
commit27c8266eb62bcf4a3a3c4dae54ae13cb3d017b31 (patch)
tree5bbd8532138a34c35be83f91094375ad98606a95
parent5cc3dad991cde9c55c49c451a93a496a16b3afe1 (diff)
downloadscala-27c8266eb62bcf4a3a3c4dae54ae13cb3d017b31.tar.gz
scala-27c8266eb62bcf4a3a3c4dae54ae13cb3d017b31.tar.bz2
scala-27c8266eb62bcf4a3a3c4dae54ae13cb3d017b31.zip
Distentangled platform specific code from loade...
Distentangled platform specific code from loaders so that it becomes possible to reset class symbols to their initial loader wihtout going through an all-or-nothing recursive buildups of package scopes,.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala25
-rw-r--r--src/compiler/scala/tools/nsc/backend/MSILPlatform.scala38
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala27
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala90
6 files changed, 105 insertions, 84 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 602ff6bf0e..2bbf2f9ac7 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -62,13 +62,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
// platform specific elements
- type ThisPlatform = Platform[_] { val global: Global.this.type }
+ type ThisPlatform = Platform { val global: Global.this.type }
lazy val platform: ThisPlatform =
if (forMSIL) new { val global: Global.this.type = Global.this } with MSILPlatform
else new { val global: Global.this.type = Global.this } with JavaPlatform
- def classPath: ClassPath[_] = platform.classPath
+ def classPath: ClassPath[platform.BinaryRepr] = platform.classPath
def rootLoader: LazyType = platform.rootLoader
// sub-components --------------------------------------------------
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 9e83f2fbd7..d80a1c4f34 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -7,16 +7,27 @@ package scala.tools.nsc
package backend
import io.AbstractFile
-import util.JavaClassPath
+import util.{ClassPath,JavaClassPath}
import util.ClassPath.{ JavaContext, DefaultJavaContext }
import scala.tools.util.PathResolver
-trait JavaPlatform extends Platform[AbstractFile] {
+trait JavaPlatform extends Platform {
import global._
import definitions._
+ type BinaryRepr = AbstractFile
+
lazy val classPath = new PathResolver(settings).result
- def rootLoader = new loaders.JavaPackageLoader(classPath)
+ 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 depAnalysisPhase =
if (settings.make.isDefault) Nil
@@ -45,4 +56,12 @@ trait JavaPlatform extends Platform[AbstractFile] {
(sym isNonBottomSubClass BoxedCharacterClass) ||
(sym isNonBottomSubClass BoxedBooleanClass)
}
+
+ def newClassLoader(bin: AbstractFile): loaders.SymbolLoader =
+ new loaders.ClassfileLoader(bin)
+
+ def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = true
+
+ def needCompile(bin: AbstractFile, src: AbstractFile) =
+ src.lastModified >= bin.lastModified
}
diff --git a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
index 9781111004..b1daee1f10 100644
--- a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
@@ -6,14 +6,17 @@
package scala.tools.nsc
package backend
-import ch.epfl.lamp.compiler.msil.{ Type => MSILType }
-import util.MsilClassPath
+import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Attribute => MSILAttribute }
+import util.{ClassPath, MsilClassPath}
import msil.GenMSIL
+import io.AbstractFile
-trait MSILPlatform extends Platform[MSILType] {
+trait MSILPlatform extends Platform {
import global._
import definitions.{ ComparatorClass, BoxedNumberClass, getMember }
+ type BinaryRepr = MSILType
+
if (settings.verbose.value)
inform("[AssemRefs = " + settings.assemrefs.value + "]")
@@ -25,7 +28,8 @@ trait MSILPlatform extends Platform[MSILType] {
} with GenMSIL
lazy val classPath = MsilClassPath.fromSettings(settings)
- def rootLoader = new loaders.NamespaceLoader(classPath)
+ def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]])
+ // See discussion in JavaPlatForm for why we need a cast here.
def platformPhases = List(
genMSIL // generate .msil files
@@ -33,4 +37,30 @@ trait MSILPlatform extends Platform[MSILType] {
lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_)
def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass
+
+ def newClassLoader(bin: MSILType): loaders.SymbolLoader =
+ new loaders.MSILTypeLoader(bin)
+
+ /**
+ * 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 = {
+ if (cls.binary.isDefined) {
+ val typ = cls.binary.get
+ if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) {
+ val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)
+ assert(attrs.length == 1, attrs.length)
+ val a = attrs(0).asInstanceOf[MSILAttribute]
+ // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle.
+ // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic.
+ a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR
+ } else true // always load non-scala types
+ } else true // always load source
+ }
+
+ def needCompile(bin: MSILType, src: AbstractFile) =
+ false // always use compiled file on .net
}
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index de271856b7..23592eeb61 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -7,15 +7,19 @@ package scala.tools.nsc
package backend
import util.ClassPath
+import io.AbstractFile
/** The platform dependent pieces of Global.
*/
-trait Platform[T] {
+trait Platform {
val global: Global
import global._
+ /** The binary classfile representation type */
+ type BinaryRepr
+
/** The compiler classpath. */
- def classPath: ClassPath[T]
+ def classPath: ClassPath[BinaryRepr]
/** The root symbol loader. */
def rootLoader: LazyType
@@ -28,5 +32,24 @@ trait Platform[T] {
/** 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
+
+ /**
+ * Tells whether a class with both a binary and a source representation
+ * (found in classpath and in sourcepath) should be re-compiled. Behaves
+ * 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
}
diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
index 24e0dba271..14cbdf2f3b 100644
--- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
@@ -33,8 +33,9 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
super.computeInternalPhases
phasesSet += dependencyAnalysis
}
- lazy val _classpath: ClassPath[_] = new NoSourcePathPathResolver(settings).result
- override def classPath: ClassPath[_] = _classpath
+ lazy val _classpath = new NoSourcePathPathResolver(settings).result
+ override def classPath = _classpath.asInstanceOf[ClassPath[platform.BinaryRepr]]
+ // See discussion in JavaPlatForm for why we need a cast here.
def newRun() = new Run()
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 58d8003f06..7909b5e7a8 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -79,6 +79,21 @@ abstract class SymbolLoaders {
enterClassAndModule(root, name, new SourcefileLoader(src))
}
+ /** Initialize symbol `root` from class path representation `classRep`
+ */
+ def initializeFromClassPath(root: Symbol, classRep: ClassPath[platform.BinaryRepr]#ClassRep) {
+ ((classRep.binary, classRep.source) : @unchecked) match {
+ case (Some(bin), Some(src)) if platform.needCompile(bin, src) =>
+ if (settings.verbose.value) inform("[symloader] picked up newer source file for " + src.path)
+ global.loaders.enterToplevelsFromSource(root, classRep.name, src)
+ case (None, Some(src)) =>
+ if (settings.verbose.value) inform("[symloader] no class, picked up source file for " + src.path)
+ global.loaders.enterToplevelsFromSource(root, classRep.name, src)
+ case (Some(bin), _) =>
+ global.loaders.enterClassAndModule(root, classRep.name, platform.newClassLoader(bin))
+ }
+ }
+
/**
* A lazy type that completes itself by calling parameter doComplete.
* Any linked modules/classes or module classes are also initialized.
@@ -155,7 +170,7 @@ abstract class SymbolLoaders {
/**
* Load contents of a package
*/
- abstract class PackageLoader[T](classpath: ClassPath[T]) extends SymbolLoader {
+ class PackageLoader(classpath: ClassPath[platform.BinaryRepr]) extends SymbolLoader {
protected def description = "package loader "+ classpath.name
def enterPackage(root: Symbol, name: String, completer: SymbolLoader) {
@@ -192,90 +207,23 @@ abstract class SymbolLoaders {
root.info.decls.enter(pkg)
}
- /**
- * Tells whether a class with both a binary and a source representation
- * (found in classpath and in sourcepath) should be re-compiled. Behaves
- * similar to javac, i.e. if the source file is newer than the classfile,
- * a re-compile is triggered.
- */
- protected def needCompile(bin: T, src: AbstractFile): Boolean
-
- /**
- * 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.
- */
- protected def doLoad(cls: classpath.AnyClassRep): Boolean
-
- protected def newClassLoader(bin: T): SymbolLoader
-
- protected def newPackageLoader(pkg: ClassPath[T]): SymbolLoader
-
protected def doComplete(root: Symbol) {
assert(root.isPackageClass, root)
root.setInfo(new PackageClassInfoType(new Scope(), root))
val sourcepaths = classpath.sourcepaths
- for (classRep <- classpath.classes if doLoad(classRep)) {
- ((classRep.binary, classRep.source) : @unchecked) match {
- case (Some(bin), Some(src)) if needCompile(bin, src) =>
- if (settings.verbose.value) inform("[symloader] picked up newer source file for " + src.path)
- enterToplevelsFromSource(root, classRep.name, src)
- case (None, Some(src)) =>
- if (settings.verbose.value) inform("[symloader] no class, picked up source file for " + src.path)
- enterToplevelsFromSource(root, classRep.name, src)
- case (Some(bin), _) =>
- enterClassAndModule(root, classRep.name, newClassLoader(bin))
- }
+ for (classRep <- classpath.classes if platform.doLoad(classRep)) {
+ initializeFromClassPath(root, classRep)
}
for (pkg <- classpath.packages) {
- enterPackage(root, pkg.name, newPackageLoader(pkg))
+ enterPackage(root, pkg.name, new PackageLoader(pkg))
}
openPackageModule(root)
}
}
- class JavaPackageLoader(classpath: ClassPath[AbstractFile]) extends PackageLoader(classpath) {
- protected def needCompile(bin: AbstractFile, src: AbstractFile) =
- (src.lastModified >= bin.lastModified)
-
- protected def doLoad(cls: classpath.AnyClassRep) = true
-
- protected def newClassLoader(bin: AbstractFile) =
- new ClassfileLoader(bin)
-
- protected def newPackageLoader(pkg: ClassPath[AbstractFile]) =
- new JavaPackageLoader(pkg)
- }
-
- class NamespaceLoader(classpath: ClassPath[MSILType]) extends PackageLoader(classpath) {
- protected def needCompile(bin: MSILType, src: AbstractFile) =
- false // always use compiled file on .net
-
- protected def doLoad(cls: classpath.AnyClassRep) = {
- if (cls.binary.isDefined) {
- val typ = cls.binary.get
- if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {
- val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false)
- assert (attrs.length == 1, attrs.length)
- val a = attrs(0).asInstanceOf[MSILAttribute]
- // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle.
- // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic.
- a.getConstructor() == clrTypes.SYMTAB_CONSTR
- } else true // always load non-scala types
- } else true // always load source
- }
-
- protected def newClassLoader(bin: MSILType) =
- new MSILTypeLoader(bin)
-
- protected def newPackageLoader(pkg: ClassPath[MSILType]) =
- new NamespaceLoader(pkg)
- }
-
class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
private object classfileParser extends ClassfileParser {
val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global