diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala | 111 |
1 files changed, 90 insertions, 21 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 79f8a6a45..63c2817a6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -9,11 +9,13 @@ package core import java.io.IOException import scala.compat.Platform.currentTime -import dotty.tools.io.{ ClassPath, AbstractFile } +import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile } +import classpath._ import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util.Positions._, Names._ import StdNames._, NameOps._ import Decorators.{PreNamedString, StringInterpolators} import classfile.ClassfileParser +import util.Stats import scala.util.control.NonFatal object SymbolLoaders { @@ -59,8 +61,7 @@ class SymbolLoaders { /** Enter package with given `name` into scope of `owner` * and give them `completer` as type. */ - def enterPackage(owner: Symbol, pkg: ClassPath)(implicit ctx: Context): Symbol = { - val pname = pkg.name.toTermName + def enterPackage(owner: Symbol, pname: TermName, completer: (TermSymbol, ClassSymbol) => PackageLoader)(implicit ctx: Context): Symbol = { val preExisting = owner.info.decls lookup pname if (preExisting != NoSymbol) { // Some jars (often, obfuscated ones) include a package and @@ -83,7 +84,7 @@ class SymbolLoaders { } } ctx.newModuleSymbol(owner, pname, PackageCreationFlags, PackageCreationFlags, - (module, modcls) => new PackageLoader(module, pkg)).entered + completer).entered } /** Enter class and module with given `name` into scope of `owner` @@ -125,7 +126,7 @@ class SymbolLoaders { /** Initialize toplevel class and module symbols in `owner` from class path representation `classRep` */ - def initializeFromClassPath(owner: Symbol, classRep: ClassPath#ClassRep)(implicit ctx: Context): Unit = { + def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation)(implicit ctx: Context): Unit = { ((classRep.binary, classRep.source): @unchecked) match { case (Some(bin), Some(src)) if needCompile(bin, src) && !binaryOnly(owner, classRep.name) => if (ctx.settings.verbose.value) ctx.inform("[symloader] picked up newer source file for " + src.path) @@ -143,31 +144,99 @@ class SymbolLoaders { /** Load contents of a package */ - class PackageLoader(_sourceModule: TermSymbol, classpath: ClassPath) + class PackageLoader(_sourceModule: TermSymbol, classPath: ClassPath) extends SymbolLoader { override def sourceModule(implicit ctx: Context) = _sourceModule - def description = "package loader " + classpath.name + def description(implicit ctx: Context) = "package loader " + sourceModule.fullName - private[core] val currentDecls: MutableScope = newScope + private var enterFlatClasses: Option[Context => Unit] = None + + Stats.record("package scopes") + + /** The scope of a package. This is different from a normal scope + * in three aspects: + * + * 1. Names of scope entries are kept in mangled form. + * 2. Some function types in the `scala` package are synthesized. + */ + final class PackageScope extends MutableScope { + override def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = + super.newScopeEntry(name.mangled, sym) + + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + val mangled = name.mangled + val e = super.lookupEntry(mangled) + if (e != null) e + else if (_sourceModule.initialDenot.name == nme.scala_ && _sourceModule == defn.ScalaPackageVal && + name.isTypeName && name.isSyntheticFunction) + newScopeEntry(defn.newFunctionNTrait(name.asTypeName)) + else if (isFlatName(mangled.toSimpleName) && enterFlatClasses.isDefined) { + Stats.record("package scopes with flatnames entered") + enterFlatClasses.get(ctx) + lookupEntry(name) + } + else e + } + + override def ensureComplete()(implicit ctx: Context) = + for (enter <- enterFlatClasses) enter(ctx) + + override def newScopeLikeThis() = new PackageScope + } + + private[core] val currentDecls: MutableScope = new PackageScope() + + def isFlatName(name: SimpleTermName) = name.lastIndexOf('$', name.length - 2) >= 0 + + def isFlatName(classRep: ClassRepresentation) = { + val idx = classRep.name.indexOf('$') + idx >= 0 && idx < classRep.name.length - 1 + } + + def maybeModuleClass(classRep: ClassRepresentation) = classRep.name.last == '$' + + private def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(implicit ctx: Context) = { + def isAbsent(classRep: ClassRepresentation) = + !root.unforcedDecls.lookup(classRep.name.toTypeName).exists + + if (!root.isRoot) { + val classReps = classPath.classes(packageName) + + for (classRep <- classReps) + if (!maybeModuleClass(classRep) && isFlatName(classRep) == flat && + (!flat || isAbsent(classRep))) // on 2nd enter of flat names, check that the name has not been entered before + initializeFromClassPath(root.symbol, classRep) + for (classRep <- classReps) + if (maybeModuleClass(classRep) && isFlatName(classRep) == flat && + isAbsent(classRep)) + initializeFromClassPath(root.symbol, classRep) + } + } def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) - def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) sourceModule.completer.complete(sourceModule) - if (!root.isRoot) { - for (classRep <- classpath.classes) - if (!maybeModuleClass(classRep)) - initializeFromClassPath(root.symbol, classRep) - for (classRep <- classpath.classes) - if (maybeModuleClass(classRep) && !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) - initializeFromClassPath(root.symbol, classRep) + + val packageName = if (root.isEffectiveRoot) "" else root.fullName.toString + + enterFlatClasses = Some { ctx => + enterFlatClasses = None + enterClasses(root, packageName, flat = true)(ctx) } + enterClasses(root, packageName, flat = false) if (!root.isEmptyPackage) - for (pkg <- classpath.packages) - enterPackage(root.symbol, pkg) + for (pkg <- classPath.packages(packageName)) { + val fullName = pkg.name + val name = + if (packageName.isEmpty) fullName + else fullName.substring(packageName.length + 1) + + enterPackage(root.symbol, name.toTermName, + (module, modcls) => new PackageLoader(module, classPath)) + } } } } @@ -185,7 +254,7 @@ abstract class SymbolLoader extends LazyType { /** Description of the resource (ClassPath, AbstractFile) * being processed by this loader */ - def description: String + def description(implicit ctx: Context): String override def complete(root: SymDenotation)(implicit ctx: Context): Unit = { def signalError(ex: Exception): Unit = { @@ -226,7 +295,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { override def sourceFileOrNull: AbstractFile = classfile - def description = "class file " + classfile.toString + def description(implicit ctx: Context) = "class file " + classfile.toString def rootDenots(rootDenot: ClassDenotation)(implicit ctx: Context): (ClassDenotation, ClassDenotation) = { val linkedDenot = rootDenot.scalacLinkedClass.denot match { @@ -261,7 +330,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { } class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader { - def description = "source file " + srcfile.toString + def description(implicit ctx: Context) = "source file " + srcfile.toString override def sourceFileOrNull = srcfile def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = unsupported("doComplete") } |