diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core')
3 files changed, 61 insertions, 31 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index a97589d73..eee6ba785 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable } import PartialFunction._ import collection.mutable import util.common.alwaysZero -import typer.Applications object Definitions { @@ -846,6 +845,9 @@ class Definitions { TupleType(elems.size).appliedTo(elems) } + def isProductSubType(tp: Type)(implicit ctx: Context) = + tp.derivesFrom(ProductType.symbol) + /** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN? */ def isFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index e4d2d446f..63c2817a6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -9,7 +9,8 @@ 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} @@ -60,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 @@ -84,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` @@ -126,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) @@ -144,10 +144,10 @@ 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 var enterFlatClasses: Option[Context => Unit] = None @@ -188,23 +188,25 @@ class SymbolLoaders { def isFlatName(name: SimpleTermName) = name.lastIndexOf('$', name.length - 2) >= 0 - def isFlatName(classRep: ClassPath#ClassRep) = { + def isFlatName(classRep: ClassRepresentation) = { val idx = classRep.name.indexOf('$') idx >= 0 && idx < classRep.name.length - 1 } - def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' + def maybeModuleClass(classRep: ClassRepresentation) = classRep.name.last == '$' - private def enterClasses(root: SymDenotation, flat: Boolean)(implicit ctx: Context) = { - def isAbsent(classRep: ClassPath#ClassRep) = + 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) { - for (classRep <- classpath.classes) + 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 <- classpath.classes) + for (classRep <- classReps) if (maybeModuleClass(classRep) && isFlatName(classRep) == flat && isAbsent(classRep)) initializeFromClassPath(root.symbol, classRep) @@ -217,14 +219,24 @@ class SymbolLoaders { root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) sourceModule.completer.complete(sourceModule) + + val packageName = if (root.isEffectiveRoot) "" else root.fullName.toString + enterFlatClasses = Some { ctx => enterFlatClasses = None - enterClasses(root, flat = true)(ctx) + enterClasses(root, packageName, flat = true)(ctx) } - enterClasses(root, flat = false) + 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)) + } } } } @@ -242,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 = { @@ -283,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 { @@ -318,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") } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 27afa4d09..9415c047f 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -7,7 +7,7 @@ import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ -import java.io.{ File, IOException } +import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException } import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } @@ -194,13 +194,21 @@ class ClassfileParser( val name = pool.getName(in.nextChar) val isConstructor = name eq nme.CONSTRUCTOR - /** Strip leading outer param from constructor. - * Todo: Also strip trailing access tag for private inner constructors? + /** Strip leading outer param from constructor and trailing access tag for + * private inner constructors. */ - def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match { + def normalizeConstructorParams() = innerClasses.get(currentClassName) match { case Some(entry) if !isStatic(entry.jflags) => val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info - denot.info = mt.derivedLambdaType(paramNames.tail, paramTypes.tail, resultType) + var normalizedParamNames = paramNames.tail + var normalizedParamTypes = paramTypes.tail + if ((jflags & JAVA_ACC_SYNTHETIC) != 0) { + // SI-7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which + // are added when an inner class needs to access a private constructor. + normalizedParamNames = paramNames.dropRight(1) + normalizedParamTypes = paramTypes.dropRight(1) + } + denot.info = mt.derivedLambdaType(normalizedParamNames, normalizedParamTypes, resultType) case _ => } @@ -216,7 +224,7 @@ class ClassfileParser( denot.info = pool.getType(in.nextChar) if (isEnum) denot.info = ConstantType(Constant(sym)) - if (isConstructor) stripOuterParamFromConstructor() + if (isConstructor) normalizeConstructorParams() setPrivateWithin(denot, jflags) denot.info = translateTempPoly(parseAttributes(sym, denot.info)) if (isConstructor) normalizeConstructorInfo() @@ -227,8 +235,12 @@ class ClassfileParser( // seal java enums if (isEnum) { val enumClass = sym.owner.linkedClass - if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed) - enumClass.addAnnotation(Annotation.makeChild(sym)) + if (!enumClass.exists) + ctx.warning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.") + else { + if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed) + enumClass.addAnnotation(Annotation.makeChild(sym)) + } } } finally { in.bp = oldbp @@ -665,7 +677,7 @@ class ClassfileParser( for (entry <- innerClasses.values) { // create a new class member for immediate inner classes if (entry.outerName == currentClassName) { - val file = ctx.platform.classPath.findBinaryFile(entry.externalName.toString) getOrElse { + val file = ctx.platform.classPath.findClassFile(entry.externalName.toString) getOrElse { throw new AssertionError(entry.externalName) } enterClassAndModule(entry, file, entry.jflags) @@ -923,12 +935,16 @@ class ClassfileParser( case null => val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val name = termName(in.buf, start + 3, in.getChar(start + 1)) + val len = in.getChar(start + 1).toInt + val name = termName(fromMUTF8(in.buf, start + 1, len + 2)) values(index) = name name } } + private def fromMUTF8(bytes: Array[Byte], offset: Int, len: Int): String = + new DataInputStream(new ByteArrayInputStream(bytes, offset, len)).readUTF + /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ def getExternalName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) |