summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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