diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 9952961ea971..3deaa5c7f855 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -5,6 +5,9 @@ import Keys._ import java.util.{Date, Locale, Properties, TimeZone} import java.io.{File, FileInputStream} import java.text.SimpleDateFormat +import java.time.Instant +import java.time.format.DateTimeFormatter +import java.time.temporal.{TemporalAccessor, TemporalQueries, TemporalQuery} import scala.collection.JavaConverters._ import BuildSettings.autoImport._ @@ -71,8 +74,21 @@ object VersionUtil { val db = new FileRepositoryBuilder().findGitDir.build val head = db.resolve("HEAD") if (head eq null) { - log.info("No git HEAD commit found -- Using current date and 'unknown' SHA") - (new Date, "unknown") + import scala.sys.process._ + try { + // Workaround lack of git worktree support in JGit https://bugs.eclipse.org/bugs/show_bug.cgi?id=477475 + val sha = List("git", "rev-parse", "HEAD").!!.trim + val commitDateIso = List("git", "log", "-1", "--format=%cI", "HEAD").!!.trim + val date = java.util.Date.from(DateTimeFormatter.ISO_DATE_TIME.parse(commitDateIso, new TemporalQuery[Instant] { + override def queryFrom(temporal: TemporalAccessor): Instant = Instant.from(temporal) + })) + (date, sha.substring(0, 7)) + } catch { + case ex: Exception => + ex.printStackTrace() + log.info("No git HEAD commit found -- Using current date and 'unknown' SHA") + (new Date, "unknown") + } } else { val commit = new RevWalk(db).parseCommit(head) (new Date(commit.getCommitTime.toLong * 1000L), commit.getName.substring(0, 7)) diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index 66eb574d97d8..86f9e0aa6c1e 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -12,6 +12,8 @@ package scala.tools.nsc +import java.nio.file.Files + import io.File /** A class representing command line info for scalac */ @@ -119,11 +121,12 @@ class CompilerCommand(arguments: List[String], val settings: Settings) { */ def expandArg(arg: String): List[String] = { def stripComment(s: String) = s takeWhile (_ != '#') - val file = File(arg stripPrefix "@") - if (!file.exists) - throw new java.io.FileNotFoundException("argument file %s could not be found" format file.name) - - settings splitParams (file.lines() map stripComment mkString " ") + import java.nio.file._ + import collection.JavaConverters._ + val file = Paths.get(arg stripPrefix "@") + if (!Files.exists(file)) + throw new java.io.FileNotFoundException("argument file %s could not be found" format file) + settings splitParams (Files.readAllLines(file).asScala map stripComment mkString " ") } // override this if you don't want arguments processed here diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index eaaba1e99b2e..9bf44d789767 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1548,6 +1548,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter) reporting.summarizeErrors() + // val allNamesArray: Array[String] = allNames().map(_.toString).toArray.sorted + // allNamesArray.foreach(println(_)) + if (traceSymbolActivity) units map (_.body) foreach (traceSymbols recordSymbolsInTree _) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 5fe51011b856..df9aa82a6792 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -415,7 +415,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic { */ def getAnnotPickle(jclassName: String, sym: Symbol): Option[AnnotationInfo] = { currentRun.symData get sym match { - case Some(pickle) if !sym.isModuleClass => + case Some(pickle) if !sym.isModuleClass => // pickles for module classes are in the companion / mirror class val scalaAnnot = { val sigBytes = ScalaSigBytes(pickle.bytes.take(pickle.writeIndex)) AnnotationInfo(sigBytes.sigAnnot, Nil, (nme.bytes, sigBytes) :: Nil) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 2ad68f4d6203..847b1837bbe7 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -13,13 +13,13 @@ package scala.tools.nsc package symtab -import classfile.ClassfileParser +import classfile.{ClassfileParser, ReusableDataReader} import java.io.IOException import scala.reflect.internal.MissingRequirementError import scala.reflect.io.{AbstractFile, NoAbstractFile} import scala.tools.nsc.util.{ClassPath, ClassRepresentation} import scala.reflect.internal.TypesStats -import scala.reflect.internal.util.StatisticsStatics +import scala.reflect.internal.util.{ReusableInstance, StatisticsStatics} /** This class ... * @@ -301,13 +301,11 @@ abstract class SymbolLoaders { } } } - + private val classFileDataReader: ReusableInstance[ReusableDataReader] = new ReusableInstance[ReusableDataReader](() => new ReusableDataReader()) class ClassfileLoader(val classfile: AbstractFile, clazz: ClassSymbol, module: ModuleSymbol) extends SymbolLoader with FlagAssigningCompleter { private object classfileParser extends { val symbolTable: SymbolLoaders.this.symbolTable.type = SymbolLoaders.this.symbolTable - } with ClassfileParser { - override protected type ThisConstantPool = ConstantPool - override protected def newConstantPool: ThisConstantPool = new ConstantPool + } with ClassfileParser(classFileDataReader) { override protected def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol = SymbolLoaders.this.lookupMemberAtTyperPhaseIfPossible(sym, name) /* diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala index 19be00dd686a..17d70998f3d9 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala @@ -14,8 +14,10 @@ package scala.tools.nsc package symtab package classfile -import java.lang.Float.intBitsToFloat +import java.io.{ByteArrayInputStream, DataInputStream} import java.lang.Double.longBitsToDouble +import java.lang.Float.intBitsToFloat +import java.util import scala.tools.nsc.io.AbstractFile @@ -25,8 +27,11 @@ import scala.tools.nsc.io.AbstractFile * @author Philippe Altherr * @version 1.0, 23/03/2004 */ -class AbstractFileReader(val file: AbstractFile, val buf: Array[Byte]) { - def this(file: AbstractFile) = this(file, file.toByteArray) +final class AbstractFileReader(val buf: Array[Byte]) extends DataReader { + @deprecated("Use other constructor", "2.13.0") + def this(file: AbstractFile) { + this(file.toByteArray) + } /** the current input pointer */ @@ -59,17 +64,25 @@ class AbstractFileReader(val file: AbstractFile, val buf: Array[Byte]) { ((nextByte & 0xff) << 24) + ((nextByte & 0xff) << 16) + ((nextByte & 0xff) << 8) + (nextByte & 0xff) + /** extract a byte at position bp from buf + */ + def getByte(mybp: Int): Byte = + buf(mybp) + + def getBytes(mybp: Int, bytes: Array[Byte]): Unit = { + System.arraycopy(buf, mybp, bytes, 0, bytes.length) + } /** extract a character at position bp from buf */ def getChar(mybp: Int): Char = - (((buf(mybp) & 0xff) << 8) + (buf(mybp+1) & 0xff)).toChar + (((getByte(mybp) & 0xff) << 8) + (getByte(mybp+1) & 0xff)).toChar /** extract an integer at position bp from buf */ def getInt(mybp: Int): Int = - ((buf(mybp ) & 0xff) << 24) + ((buf(mybp+1) & 0xff) << 16) + - ((buf(mybp+2) & 0xff) << 8) + (buf(mybp+3) & 0xff) + ((getByte(mybp) & 0xff) << 24) + ((getByte(mybp + 1) & 0xff) << 16) + + ((getByte(mybp + 2) & 0xff) << 8) + (getByte(mybp + 3) & 0xff) /** extract a long integer at position bp from buf */ @@ -84,8 +97,11 @@ class AbstractFileReader(val file: AbstractFile, val buf: Array[Byte]) { */ def getDouble(mybp: Int): Double = longBitsToDouble(getLong(mybp)) + def getUTF(mybp: Int, len: Int): String = { + new DataInputStream(new ByteArrayInputStream(buf, mybp, len)).readUTF + } + /** skip next 'n' bytes */ - def skip(n: Int) { bp += n } - + def skip(n: Int): Unit = { bp += n } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index c855f1c11bb6..f637f28d4ecf 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -17,13 +17,15 @@ package classfile import java.io.{ByteArrayInputStream, DataInputStream, File, IOException} import java.lang.Integer.toHexString +import java.nio.ByteBuffer import scala.collection.{immutable, mutable} import scala.collection.mutable.{ArrayBuffer, ListBuffer} import scala.annotation.switch import scala.reflect.internal.JavaAccFlags -import scala.reflect.internal.pickling.{ByteCodecs, PickleBuffer} -import scala.reflect.io.NoAbstractFile +import scala.reflect.internal.pickling.ByteCodecs +import scala.reflect.internal.util.ReusableInstance +import scala.reflect.io.{NoAbstractFile, VirtualFile} import scala.reflect.internal.util.Collections._ import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io.AbstractFile @@ -34,7 +36,7 @@ import scala.util.control.NonFatal * @author Martin Odersky * @version 1.0 */ -abstract class ClassfileParser { +abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) { val symbolTable: SymbolTable { def settings: Settings } @@ -60,21 +62,17 @@ abstract class ClassfileParser { import scala.reflect.internal.ClassfileConstants._ import Flags._ - protected type ThisConstantPool <: ConstantPool - protected def newConstantPool: ThisConstantPool - - protected var file: AbstractFile = _ // the class file - protected var in: AbstractFileReader = _ // the class file reader + protected var file: AbstractFile = _ // the class file + protected var in: DataReader = _ // the class file reader protected var clazz: ClassSymbol = _ // the class symbol containing dynamic members protected var staticModule: ModuleSymbol = _ // 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: ThisConstantPool = _ // the classfile's constant pool + protected var pool: ConstantPool = _ // 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 protected var busy: Symbol = _ // lock to detect recursive reads - protected var currentClass: Name = _ // JVM name of the current class + protected var currentClass: String = _ // JVM name of the current class protected var classTParams = Map[Name,Symbol]() protected var srcfile0 : Option[AbstractFile] = None protected def moduleClass: Symbol = staticModule.moduleClass @@ -100,7 +98,7 @@ abstract class ClassfileParser { private def readMethodFlags() = JavaAccFlags methodFlags u2 private def readFieldFlags() = JavaAccFlags fieldFlags u2 private def readTypeName() = readName().toTypeName - private def readName() = pool getName u2 + private def readName() = pool.getName(u2).name private def readType() = pool getType u2 private object unpickler extends scala.reflect.internal.pickling.UnPickler { @@ -134,11 +132,6 @@ abstract class ClassfileParser { catch parseErrorHandler finally busy = NoSymbol } - @inline private def raiseLoaderLevel[T](body: => T): T = { - loaders.parentsLevel += 1 - try body - finally loaders.parentsLevel -= 1 - } /** * `clazz` and `module` are the class and module symbols corresponding to the classfile being @@ -152,20 +145,23 @@ abstract class ClassfileParser { def parse(file: AbstractFile, clazz: ClassSymbol, module: ModuleSymbol): Unit = { this.file = file pushBusy(clazz) { - this.clazz = clazz - this.staticModule = module - this.isScala = false - - this.in = new AbstractFileReader(file) - val magic = in.getInt(in.bp) - if (magic != JAVA_MAGIC && file.name.endsWith(".sig")) { - currentClass = TermName(clazz.javaClassName) - isScala = true - unpickler.unpickle(in.buf, 0, clazz, staticModule, file.name) - } else { - parseHeader() - this.pool = newConstantPool - parseClass() + reader.using { reader => + this.clazz = clazz + this.staticModule = module + this.isScala = false + + val fileContents = file.toByteArray + this.in = new AbstractFileReader(fileContents) + val magic = in.getInt(in.bp) + if (magic != JAVA_MAGIC && file.name.endsWith(".sig")) { + currentClass = clazz.javaClassName + isScala = true + unpickler.unpickle(fileContents, 0, clazz, staticModule, file.name) + } else { + parseHeader() + this.pool = new ConstantPool + parseClass() + } } } } @@ -173,11 +169,26 @@ abstract class ClassfileParser { private def parseHeader() { val magic = u4 if (magic != JAVA_MAGIC) - abort(s"class file ${in.file} has wrong magic number 0x${toHexString(magic)}") + abort(s"class file ${file} has wrong magic number 0x${toHexString(magic)}") val minor, major = u2 if (major < JAVA_MAJOR_VERSION || major == JAVA_MAJOR_VERSION && minor < JAVA_MINOR_VERSION) - abort(s"class file ${in.file} has unknown version $major.$minor, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION") + abort(s"class file ${file} has unknown version $major.$minor, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION") + } + + protected class NameOrString(val value: String) { + private var _name: Name = null + def name: Name = { + if (_name eq null) _name = TermName(value) + _name + } + } + + def getClassSymbol(name: String): Symbol = { + name match { + case name if name.endsWith(nme.MODULE_SUFFIX_STRING) => rootMirror getModuleByName newTermName(name).dropModule + case name => classNameToSymbol(name) + } } /** @@ -187,7 +198,9 @@ abstract class ClassfileParser { 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) + protected val internalized = new Array[NameOrString](len) + + val initBp = in.bp { var i = 1 while (i < starts.length) { @@ -205,7 +218,7 @@ abstract class ClassfileParser { } } } - + val endBp = in.bp def recordAtIndex[T <: AnyRef](value: T, idx: Int): T = { values(idx) = value value @@ -213,33 +226,30 @@ abstract class ClassfileParser { def firstExpecting(index: Int, expected: Int): Int = { val start = starts(index) - val first = in.buf(start).toInt + val first = in.getByte(start).toInt if (first == expected) start + 1 else this errorBadTag start } /** Return the name found at given index. */ - def getName(index: Int): Name = ( + def getName(index: Int): NameOrString = ( if (index <= 0 || len <= index) errorBadIndex(index) else values(index) match { - case name: Name => name + case name: NameOrString => name case _ => val start = firstExpecting(index, CONSTANT_UTF8) val len = in.getChar(start).toInt - recordAtIndex(TermName(fromMUTF8(in.buf, start, len + 2)), index) + recordAtIndex(new NameOrString(in.getUTF(start, len + 2)), index) } ) - 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): Name = { + def getExternalName(index: Int): NameOrString = { if (index <= 0 || len <= index) errorBadIndex(index) if (internalized(index) == null) - internalized(index) = getName(index).replace('/', '.') + internalized(index) = new NameOrString(getName(index).value.replace('/', '.')) internalized(index) } @@ -249,10 +259,7 @@ abstract class ClassfileParser { values(index) match { case sym: Symbol => sym case _ => - val result = getClassName(index) match { - case name if nme.isModuleName(name) => rootMirror getModuleByName name.dropModule - case name => classNameToSymbol(name) - } + val result = ClassfileParser.this.getClassSymbol(getClassName(index).value) recordAtIndex(result, index) } } @@ -260,9 +267,9 @@ abstract class ClassfileParser { /** Return the external name of the class info structure found at 'index'. * Use 'getClassSymbol' if the class is sure to be a top-level class. */ - def getClassName(index: Int): Name = { + def getClassName(index: Int): NameOrString = { val start = firstExpecting(index, CONSTANT_CLASS) - getExternalName((in getChar start).toInt) + getExternalName((in.getChar(start)).toInt) } /** Return a name and a type at the given index. If the type is a method @@ -279,14 +286,14 @@ abstract class ClassfileParser { val start = firstExpecting(index, CONSTANT_NAMEANDTYPE) val name = getName(in.getChar(start).toInt) // create a dummy symbol for method types - val dummy = ownerTpe.typeSymbol.newMethod(name.toTermName, ownerTpe.typeSymbol.pos) + val dummy = ownerTpe.typeSymbol.newMethod(name.name.toTermName, ownerTpe.typeSymbol.pos) val tpe = getType(dummy, in.getChar(start + 2).toInt) // fix the return type, which is blindly set to the class currently parsed val restpe = tpe match { - case MethodType(formals, _) if name == nme.CONSTRUCTOR => MethodType(formals, ownerTpe) - case _ => tpe + case MethodType(formals, _) if name.name == nme.CONSTRUCTOR => MethodType(formals, ownerTpe) + case _ => tpe } - ((name, restpe)) + ((name.name, restpe)) } } @@ -301,21 +308,21 @@ abstract class ClassfileParser { case cls: Symbol => cls.tpe_* case _ => val name = getClassName(index) - name charAt 0 match { - case ARRAY_TAG => recordAtIndex(sigToType(null, name), index) - case _ => recordAtIndex(classNameToSymbol(name), index).tpe_* + name.value.charAt(0) match { + case ARRAY_TAG => recordAtIndex(sigToType(null, name.value), index) + case _ => recordAtIndex(classNameToSymbol(name.value), index).tpe_* } } } def getType(index: Int): Type = getType(null, index) - def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index)) - def getSuperClass(index: Int): Symbol = if (index == 0) AnyClass else getClassSymbol(index) // the only classfile that is allowed to have `0` in the super_class is java/lang/Object (see jvm spec) + def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index).value) + def getSuperClassName(index: Int): NameOrString = if (index == 0) null else getClassName(index) // the only classfile that is allowed to have `0` in the super_class is java/lang/Object (see jvm spec) private def createConstant(index: Int): Constant = { val start = starts(index) - Constant((in.buf(start).toInt: @switch) match { - case CONSTANT_STRING => getName(in.getChar(start + 1).toInt).toString + Constant((in.getByte(start).toInt: @switch) match { + case CONSTANT_STRING => getName(in.getChar(start + 1).toInt).value case CONSTANT_INTEGER => in.getInt(start + 1) case CONSTANT_FLOAT => in.getFloat(start + 1) case CONSTANT_LONG => in.getLong(start + 1) @@ -350,7 +357,7 @@ abstract class ClassfileParser { val start = firstExpecting(index, CONSTANT_UTF8) val len = (in getChar start).toInt val bytes = new Array[Byte](len) - System.arraycopy(in.buf, start + 2, bytes, 0, len) + in.getBytes(start + 2, bytes) recordAtIndex(getSubArray(bytes), index) } ) @@ -364,7 +371,10 @@ abstract class ClassfileParser { if (index <= 0 || ConstantPool.this.len <= index) errorBadIndex(index) val start = firstExpecting(index, CONSTANT_UTF8) val len = (in getChar start).toInt - in.buf drop start + 2 take len + val s = start + 2 + val result = new Array[Byte](len) + in.getBytes(s, result) + result } recordAtIndex(getSubArray(arr), head) } @@ -376,7 +386,7 @@ abstract class ClassfileParser { /** Throws an exception signaling a bad tag at given address. */ protected def errorBadTag(start: Int) = - abort(s"bad constant pool tag ${in.buf(start)} at byte $start") + abort(s"bad constant pool tag ${in.getByte(start)} at byte $start") } def stubClassSymbol(name: Name): Symbol = { @@ -392,13 +402,13 @@ abstract class ClassfileParser { NoSymbol.newStubSymbol(name.toTypeName, msg) } - private def lookupClass(name: Name) = try { + private def lookupClass(name: String) = try { def lookupTopLevel = { - if (name containsChar '.') + if (name contains '.') rootMirror getClassByName name else // FIXME - we shouldn't be doing ad hoc lookups in the empty package, getClassByName should return the class - definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName) + definitions.getMember(rootMirror.EmptyPackageClass, newTypeName(name)) } // For inner classes we usually don't get here: `classNameToSymbol` already returns the symbol @@ -409,21 +419,23 @@ abstract class ClassfileParser { // what the logic below is for (see PR #5822 / scala/bug#9937). val split = if (isScalaRaw) -1 else name.lastIndexOf('$') if (split > 0 && split < name.length) { - val outerName = name.subName(0, split) - val innerName = name.subName(split + 1, name.length).toTypeName + val outerName = name.substring(0, split) + val innerName = name.substring(split + 1, name.length) val outerSym = classNameToSymbol(outerName) // If the outer class C cannot be found, look for a top-level class C$D if (outerSym.isInstanceOf[StubSymbol]) lookupTopLevel else { + val innerNameAsName = newTypeName(innerName) + // We have a java-defined class name C$D and look for a member D of C. But we don't know if // D is declared static or not, so we have to search both in class C and its companion. val r = if (outerSym == clazz) - staticScope.lookup(innerName) orElse - instanceScope.lookup(innerName) + staticScope.lookup(innerNameAsName) orElse + instanceScope.lookup(innerNameAsName) else - lookupMemberAtTyperPhaseIfPossible(outerSym, innerName) orElse - lookupMemberAtTyperPhaseIfPossible(outerSym.companionModule, innerName) + lookupMemberAtTyperPhaseIfPossible(outerSym, innerNameAsName) orElse + lookupMemberAtTyperPhaseIfPossible(outerSym.companionModule, innerNameAsName) r orElse lookupTopLevel } } else @@ -434,14 +446,16 @@ abstract class ClassfileParser { // - was referenced in the bugfix commit for scala/bug#3756 (4fb0d53), not sure why // - covers the case when a type alias in a package object shadows a class symbol, // getClassByName throws a MissingRequirementError (scala-dev#248) - case _: FatalError => + case ex: FatalError => // getClassByName can throw a MissingRequirementError (which extends FatalError) // definitions.getMember can throw a FatalError, for example in pos/t5165b - stubClassSymbol(name) + if (settings.debug) + ex.printStackTrace() + stubClassSymbol(newTypeName(name)) } /** Return the class symbol of the given name. */ - def classNameToSymbol(name: Name): Symbol = { + def classNameToSymbol(name: String): Symbol = { if (innerClasses contains name) innerClasses innerSymbol name else @@ -449,87 +463,90 @@ abstract class ClassfileParser { } def parseClass() { - val jflags = readClassFlags() - val sflags = jflags.toScalaFlags - val nameIdx = u2 - currentClass = pool.getClassName(nameIdx) - - /* Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled. - * Updates the read pointer of 'in'. */ - def parseParents: List[Type] = { - if (isScala) { - u2 // skip superclass - val ifaces = u2 - in.bp += ifaces * 2 // .. and iface count interfaces - List(AnyRefTpe) // dummy superclass, will be replaced by pickled information - } - else raiseLoaderLevel { - val superType = if (jflags.isAnnotation) { u2; AnnotationClass.tpe } - else pool.getSuperClass(u2).tpe_* - val ifaceCount = u2 - var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(u2).tpe_* - if (jflags.isAnnotation) ifaces ::= ClassfileAnnotationClass.tpe - superType :: ifaces - } - } + unpickleOrParseInnerClasses() - val isTopLevel = !(currentClass containsChar '$') // Java class name; *don't* try to to use Scala name decoding (scala/bug#7532) + val jflags = readClassFlags() + val classNameIndex = u2 + currentClass = pool.getClassName(classNameIndex).value + + // Ensure that (top-level) classfiles are in the correct directory + val isTopLevel = !(currentClass contains '$') // Java class name; *don't* try to to use Scala name decoding (scala/bug#7532) if (isTopLevel) { - val c = pool.getClassSymbol(nameIdx) + val c = pool.getClassSymbol(classNameIndex) // scala-dev#248: when a type alias (in a package object) shadows a class symbol, getClassSymbol returns a stub + // TODO: this also prevents the error when it would be useful (`mv a/C.class .`) if (!c.isInstanceOf[StubSymbol] && c != clazz) mismatchError(c) } - addEnclosingTParams(clazz) - parseInnerClasses() // also sets the isScala / isScalaRaw flags, see r15956 - // get the class file parser to reuse scopes. - instanceScope = newScope - staticScope = newScope + // TODO: remove after the next 2.13 milestone + // A bug in the backend caused classes ending in `$` do get only a Scala marker attribute + // instead of a ScalaSig and a Signature annotaiton. This went unnoticed because isScalaRaw + // classes were parsed like Java classes. The below covers the cases in the std lib. + def isNothingOrNull = { + val n = clazz.fullName.toString + n == "scala.runtime.Nothing$" || n == "scala.runtime.Null$" + } + + if (isScala) { + () // We're done + } else if (isScalaRaw && !isNothingOrNull) { + val decls = clazz.enclosingPackage.info.decls + for (c <- List(clazz, staticModule, staticModule.moduleClass)) { + c.setInfo(NoType) + decls.unlink(c) + } + } else { + val sflags = jflags.toScalaFlags // includes JAVA + + addEnclosingTParams(clazz) - val classInfo = ClassInfoType(parseParents, instanceScope, clazz) - val staticInfo = ClassInfoType(List(), staticScope, moduleClass) + // Create scopes before calling `enterOwnInnerClasses` + instanceScope = newScope + staticScope = newScope + val staticInfo = ClassInfoType(List(), staticScope, moduleClass) + + val parentIndex = u2 + val parentName = if (parentIndex == 0) null else pool.getClassName(parentIndex) + val ifaceCount = u2 + val ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClassName(u2) + val completer = new ClassTypeCompleter(clazz.name, jflags, parentName, ifaces) - if (!isScala && !isScalaRaw) enterOwnInnerClasses() - val curbp = in.bp - skipMembers() // fields - skipMembers() // methods - if (!isScala) { + clazz setInfo completer clazz setFlag sflags - propagatePackageBoundary(jflags, clazz, staticModule, staticModule.moduleClass) - clazz setInfo classInfo moduleClass setInfo staticInfo + moduleClass setFlag JAVA staticModule setInfo moduleClass.tpe staticModule setFlag JAVA - staticModule.moduleClass setFlag JAVA - // attributes now depend on having infos set already - parseAttributes(clazz, classInfo) - - def queueLoad() { - in.bp = curbp - 0 until u2 foreach (_ => parseField()) - sawPrivateConstructor = false - 0 until u2 foreach (_ => parseMethod()) - val needsConstructor = ( - !sawPrivateConstructor - && !(instanceScope containsName nme.CONSTRUCTOR) - && (sflags & INTERFACE) == 0 - ) - if (needsConstructor) - instanceScope enter clazz.newClassConstructor(NoPosition) - } - loaders.pendingLoadActions ::= (queueLoad _) - if (loaders.parentsLevel == 0) { - while (loaders.pendingLoadActions.nonEmpty) { - val item = loaders.pendingLoadActions.head - loaders.pendingLoadActions = loaders.pendingLoadActions.tail - item() - } - } - } else - parseAttributes(clazz, classInfo) + propagatePackageBoundary(jflags, clazz, staticModule, moduleClass) + + val fieldsStartBp = in.bp + skipMembers() // fields + skipMembers() // methods + + parseAttributes(clazz, completer) + + in.bp = fieldsStartBp + 0 until u2 foreach (_ => parseField()) + sawPrivateConstructor = false + 0 until u2 foreach (_ => parseMethod()) + val needsConstructor = ( + !sawPrivateConstructor + && !(instanceScope containsName nme.CONSTRUCTOR) + && ((sflags & INTERFACE) == 0) + ) + if (needsConstructor) + instanceScope enter clazz.newClassConstructor(NoPosition) + + // we could avoid this if we eagerly created class type param symbols here to expose through the + // ClassTypeCompleter to satisfy the calls to rawInfo.typeParams from Symbol.typeParams. That would + // require a refactor of `sigToType`. + // + // We would also need to make sure that clazzTParams is populated before member type completers called sig2type. + clazz.initialize + } } /** Add type parameters of enclosing classes */ @@ -551,17 +568,17 @@ abstract class ClassfileParser { in.skip(4); skipAttributes() } else { val name = readName() - val info = readType() + val lazyInfo = new MemberTypeCompleter(name, jflags, pool.getExternalName(u2).value) val sym = ownerForFlags(jflags).newValue(name.toTermName, NoPosition, sflags) // Note: the info may be overwritten later with a generic signature // parsed from SignatureATTR sym setInfo { if (jflags.isEnum) ConstantType(Constant(sym)) - else info + else lazyInfo } propagatePackageBoundary(jflags, sym) - parseAttributes(sym, info) + parseAttributes(sym, lazyInfo) addJavaFlagsAnnotations(sym, jflags) getScope(jflags) enter sym @@ -586,8 +603,8 @@ abstract class ClassfileParser { val jflags = readMethodFlags() val sflags = jflags.toScalaFlags if (jflags.isPrivate) { - val name = readName() - if (name == nme.CONSTRUCTOR) + val isConstructor = pool.getName(u2).value == "" // opt avoid interning a Name for private methods we're about to discard + if (isConstructor) sawPrivateConstructor = true in.skip(2); skipAttributes() } else { @@ -596,63 +613,30 @@ abstract class ClassfileParser { } else { val name = readName() val sym = ownerForFlags(jflags).newMethod(name.toTermName, NoPosition, sflags) - var info = pool.getType(sym, u2) - var removedOuterParameter = false - if (name == nme.CONSTRUCTOR) - info match { - case MethodType(params, restpe) => - // if this is a non-static inner class, remove the explicit outer parameter - val paramsNoOuter = innerClasses getEntry currentClass match { - case Some(entry) if !isScalaRaw && !entry.jflags.isStatic => - /* About `clazz.owner.hasPackageFlag` below: scala/bug#5957 - * For every nested java class A$B, there are two symbols in the scala compiler. - * 1. created by SymbolLoader, because of the existence of the A$B.class file, owner: package - * 2. created by ClassfileParser of A when reading the inner classes, owner: A - * If symbol 1 gets completed (e.g. because the compiled source mentions `A$B`, not `A#B`), the - * ClassfileParser for 1 executes, and clazz.owner is the package. - */ - assert(params.head.tpe.typeSymbol == clazz.owner || clazz.owner.hasPackageFlag, params.head.tpe.typeSymbol + ": " + clazz.owner) - removedOuterParameter = true - params.tail - case _ => - params - } - val newParams = paramsNoOuter match { - case (init :+ tail) if jflags.isSynthetic => - // scala/bug#7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which - // are added when an inner class needs to access a private constructor. - init - case _ => - paramsNoOuter - } - - info = MethodType(newParams, clazz.tpe) - } // Note: the info may be overwritten later with a generic signature // parsed from SignatureATTR - sym setInfo info + val lazyInfo = new MemberTypeCompleter(name, jflags, pool.getExternalName(u2).value) + sym.info = lazyInfo propagatePackageBoundary(jflags, sym) - parseAttributes(sym, info, removedOuterParameter) + parseAttributes(sym, lazyInfo) addJavaFlagsAnnotations(sym, jflags) - if (jflags.isVarargs) - sym modifyInfo arrayToRepeated - getScope(jflags) enter sym } } } - private def sigToType(sym: Symbol, sig: Name): Type = { + private def sigToType(sym: Symbol, sig: String): Type = { + val sigChars = sig.toCharArray var index = 0 val end = sig.length def accept(ch: Char) { assert(sig.charAt(index) == ch, (sig.charAt(index), ch)) index += 1 } - def subName(isDelimiter: Char => Boolean): Name = { + def subName(isDelimiter: Char => Boolean): String = { val start = index while (!isDelimiter(sig.charAt(index))) { index += 1 } - sig.subName(start, index) + new String(sigChars, start, index - start) } def sig2type(tparams: immutable.Map[Name,Symbol], skiptvs: Boolean): Type = { val tag = sig.charAt(index); index += 1 @@ -724,7 +708,7 @@ abstract class ClassfileParser { var tpe = processClassType(processInner(classSym.tpe_*)) while (sig.charAt(index) == '.') { accept('.') - val name = subName(c => c == ';' || c == '<' || c == '.').toTypeName + val name = newTypeName(subName(c => c == ';' || c == '<' || c == '.')) val clazz = tpe.member(name) val dummyArgs = Nil // the actual arguments are added in processClassType val inner = typeRef(pre = tpe, sym = clazz, args = dummyArgs) @@ -761,7 +745,7 @@ abstract class ClassfileParser { sig2type(tparams, skiptvs) JavaMethodType(sym.newSyntheticValueParams(paramtypes.toList), restype) case 'T' => - val n = subName(';'.==).toTypeName + val n = newTypeName(subName(';'.==)) index += 1 if (skiptvs) AnyTpe else tparams(n).typeConstructor @@ -785,7 +769,7 @@ abstract class ClassfileParser { index += 1 val start = index while (sig.charAt(index) != '>') { - val tpname = subName(':'.==).toTypeName + val tpname = newTypeName(subName(':'.==)) val s = sym.newTypeParameter(tpname) tparams = tparams + (tpname -> s) sig2typeBounds(tparams, skiptvs = true) @@ -793,7 +777,7 @@ abstract class ClassfileParser { } index = start while (sig.charAt(index) != '>') { - val tpname = subName(':'.==).toTypeName + val tpname = newTypeName(subName(':'.==)) val s = tparams(tpname) s.setInfo(sig2typeBounds(tparams, skiptvs = false)) } @@ -816,96 +800,58 @@ abstract class ClassfileParser { GenPolyType(ownTypeParams, tpe) } // sigToType - def parseAttributes(sym: Symbol, symtype: Type, removedOuterParameter: Boolean = false) { - var paramNames: ListBuffer[Name] = null // null means we didn't find any - def convertTo(c: Constant, pt: Type): Constant = { - if (pt.typeSymbol == BooleanClass && c.tag == IntTag) - Constant(c.value != 0) - else - c convertTo pt - } - def parseAttribute() { + /** + * Only invoked for java classfiles. + */ + private def parseAttributes(sym: symbolTable.Symbol, completer: JavaTypeCompleter): Unit = { + def parseAttribute(): Unit = { val attrName = readTypeName() val attrLen = u4 attrName match { case tpnme.SignatureATTR => - if (!isScala && !isScalaRaw) { - val sig = pool.getExternalName(u2) - val newType = sigToType(sym, sig) - sym.setInfo(newType) - } - else in.skip(attrLen) + val sigIndex = u2 + val sig = pool.getExternalName(sigIndex) + assert(sym.rawInfo == completer, sym) + completer.sig = sig.value case tpnme.SyntheticATTR => sym.setFlag(SYNTHETIC | ARTIFACT) in.skip(attrLen) + case tpnme.BridgeATTR => sym.setFlag(BRIDGE | ARTIFACT) in.skip(attrLen) + case tpnme.DeprecatedATTR => val arg = Literal(Constant("see corresponding Javadoc for more information.")) sym.addAnnotation(DeprecatedAttr, arg, Literal(Constant(""))) in.skip(attrLen) + case tpnme.ConstantValueATTR => - val c = pool.getConstant(u2) - val c1 = convertTo(c, symtype) - if (c1 ne null) sym.setInfo(ConstantType(c1)) - else devWarning(s"failure to convert $c to $symtype") + completer.constant = pool.getConstant(u2) + case tpnme.MethodParametersATTR => def readParamNames(): Unit = { - import scala.tools.asm.Opcodes.ACC_SYNTHETIC val paramCount = u1 + val paramNames = new Array[NameOrString](paramCount) + val paramNameAccess = new Array[Int](paramCount) var i = 0 - if (removedOuterParameter && i < paramCount) { - in.skip(4) - i += 1 - } - paramNames = new ListBuffer() while (i < paramCount) { - val rawname = pool.getName(u2) - val access = u2 - - val name = - if ((access & ACC_SYNTHETIC) == 0) rawname.encode - else nme.NO_NAME - - paramNames += name + paramNames(i) = pool.getExternalName(u2) + paramNameAccess(i) = u2 i += 1 } + completer.paramNames = new ParamNames(paramNames, paramNameAccess) } readParamNames() - case tpnme.ScalaSignatureATTR => - if (!isScalaAnnot) { - devWarning(s"symbol ${sym.fullName} has pickled signature in attribute") - unpickler.unpickle(in.buf, in.bp, clazz, staticModule, in.file.name) - } - in.skip(attrLen) - case tpnme.ScalaATTR => - isScalaRaw = true - // Attribute on methods of java annotation classes when that method has a default - case tpnme.AnnotationDefaultATTR => + + case tpnme.AnnotationDefaultATTR => // Methods of java annotation classes that have a default sym.addAnnotation(AnnotationDefaultAttr) in.skip(attrLen) - // Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME + case tpnme.RuntimeAnnotationATTR => - if (isScalaAnnot || !isScala) { - // For Scala classfiles we are only interested in the scala signature annotations. Other - // annotations should be skipped (the pickle contains the symbol's annotations). - // Skipping them also prevents some spurious warnings / errors related to scala/bug#7014, - // scala/bug#7551, pos/5165b - val scalaSigAnnot = parseAnnotations(onlyScalaSig = isScalaAnnot) - if (isScalaAnnot) scalaSigAnnot match { - case Some(san: AnnotationInfo) => - val bytes = - san.assocs.find({ _._1 == nme.bytes }).get._2.asInstanceOf[ScalaSigBytes].bytes - - unpickler.unpickle(bytes, 0, clazz, staticModule, in.file.name) - case None => - throw new RuntimeException("Scala class file does not contain Scala annotation") - } - debuglog("[class] << " + sym.fullName + sym.annotationsString) - } - else - in.skip(attrLen) + val numAnnots = u2 + for (n <- 0 until numAnnots; annot <- parseAnnotation(u2)) + sym.addAnnotation(annot) // TODO 1: parse runtime visible annotations on parameters // case tpnme.RuntimeParamAnnotationATTR @@ -913,8 +859,8 @@ abstract class ClassfileParser { // TODO 2: also parse RuntimeInvisibleAnnotation / RuntimeInvisibleParamAnnotation, // i.e. java annotations with RetentionPolicy.CLASS? - case tpnme.ExceptionsATTR if (!isScala) => - parseExceptions(attrLen) + case tpnme.ExceptionsATTR => + parseExceptions(attrLen, completer) case tpnme.SourceFileATTR => if (forInteractive) { @@ -935,196 +881,108 @@ abstract class ClassfileParser { case rootMirror.EmptyPackage => srcfileLeaf case pkg => pkg.fullName(File.separatorChar)+File.separator+srcfileLeaf } - srcfile0 = settings.outputDirs.srcFilesFor(in.file, srcpath).find(_.exists) + srcfile0 = settings.outputDirs.srcFilesFor(file, srcpath).find(_.exists) } else in.skip(attrLen) + case tpnme.CodeATTR => if (sym.owner.isInterface) { sym setFlag JAVA_DEFAULTMETHOD log(s"$sym in ${sym.owner} is a java8+ default method.") } in.skip(attrLen) + case _ => in.skip(attrLen) } } - def skipAnnotArg(): Unit = { - u1 match { - case STRING_TAG | BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | - INT_TAG | LONG_TAG | FLOAT_TAG | DOUBLE_TAG | CLASS_TAG => - in.skip(2) - - case ENUM_TAG => - in.skip(4) - - case ARRAY_TAG => - val num = u2 - for (i <- 0 until num) skipAnnotArg() - - case ANNOTATION_TAG => - parseAnnotation(u2, onlyScalaSig = true) - } - } - - def parseAnnotArg: Option[ClassfileAnnotArg] = { - val tag = u1 - val index = u2 - tag match { - case STRING_TAG => - Some(LiteralAnnotArg(Constant(pool.getName(index).toString))) - case BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | INT_TAG | - LONG_TAG | FLOAT_TAG | DOUBLE_TAG => - Some(LiteralAnnotArg(pool.getConstant(index))) - case CLASS_TAG => - Some(LiteralAnnotArg(Constant(pool.getType(index)))) - case ENUM_TAG => - val t = pool.getType(index) - val n = readName() - val module = t.typeSymbol.companionModule - val s = module.info.decls.lookup(n) - if (s != NoSymbol) Some(LiteralAnnotArg(Constant(s))) - else { - warning( - sm"""While parsing annotations in ${in.file}, could not find $n in enum ${module.nameString}. - |This is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (scala/bug#7014).""" - ) - None - } - - case ARRAY_TAG => - val arr = new ArrayBuffer[ClassfileAnnotArg]() - var hasError = false - for (i <- 0 until index) - parseAnnotArg match { - case Some(c) => arr += c - case None => hasError = true - } - if (hasError) None - else Some(ArrayAnnotArg(arr.toArray)) - case ANNOTATION_TAG => - parseAnnotation(index, onlyScalaSig = false) map (NestedAnnotArg(_)) - } - } - - def parseScalaSigBytes: Option[ScalaSigBytes] = { - val tag = u1 - assert(tag == STRING_TAG, tag) - Some(ScalaSigBytes(pool getBytes u2)) - } - - def parseScalaLongSigBytes: Option[ScalaSigBytes] = { - val tag = u1 - assert(tag == ARRAY_TAG, tag) - val stringCount = u2 - val entries = - for (i <- 0 until stringCount) yield { - val stag = u1 - assert(stag == STRING_TAG, stag) - u2 - } - Some(ScalaSigBytes(pool.getBytes(entries.toList))) - } - - // TODO scala/bug#9296 duplicated code, refactor - /* Parse and return a single annotation. If it is malformed, - * return None. - */ - def parseAnnotation(attrNameIndex: Int, onlyScalaSig: Boolean): Option[AnnotationInfo] = try { - val attrType = pool.getType(attrNameIndex) - val nargs = u2 - val nvpairs = new ListBuffer[(Name, ClassfileAnnotArg)] - var hasError = false - for (i <- 0 until nargs) { - val name = readName() - // The "bytes: String" argument of the ScalaSignature attribute is parsed specially so that it is - // available as an array of bytes (the pickled Scala signature) instead of as a string. The pickled signature - // is encoded as a string because of limitations in the Java class file format. - if ((attrType == ScalaSignatureAnnotation.tpe) && (name == nme.bytes)) - parseScalaSigBytes match { - case Some(c) => nvpairs += ((name, c)) - case None => hasError = true - } - else if ((attrType == ScalaLongSignatureAnnotation.tpe) && (name == nme.bytes)) - parseScalaLongSigBytes match { - case Some(c) => nvpairs += ((name, c)) - case None => hasError = true - } - else - if (onlyScalaSig) skipAnnotArg() - else parseAnnotArg match { - case Some(c) => nvpairs += ((name, c)) - case None => hasError = true - } - } - if (hasError) None - else Some(AnnotationInfo(attrType, List(), nvpairs.toList)) - } catch { - case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found - case NonFatal(ex) => - // We want to be robust when annotations are unavailable, so the very least - // we can do is warn the user about the exception - // There was a reference to ticket 1135, but that is outdated: a reference to a class not on - // the classpath would *not* end up here. A class not found is signaled - // with a `FatalError` exception, handled above. Here you'd end up after a NPE (for example), - // and that should never be swallowed silently. - warning(s"Caught: $ex while parsing annotations in ${in.file}") - if (settings.debug) ex.printStackTrace() - None // ignore malformed annotations - } - /* * Parse the "Exceptions" attribute which denotes the exceptions * thrown by a method. */ - def parseExceptions(len: Int) { + def parseExceptions(len: Int, completer: JavaTypeCompleter): Unit = { val nClasses = u2 for (n <- 0 until nClasses) { // FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (scala/bug#7065) - val cls = pool.getClassSymbol(u2) - // we call initialize due to the fact that we call Symbol.isMonomorphicType in addThrowsAnnotation - // and that method requires Symbol to be forced to give the right answers, see scala/bug#7107 for details - cls.initialize - sym.addThrowsAnnotation(cls) + val cls = pool.getClassName(u2) + completer.exceptions ::= cls } } + // begin parseAttributes + for (i <- 0 until u2) parseAttribute() + } - /* Parse a sequence of annotations and attaches them to the - * current symbol sym, except for the ScalaSignature annotation that it returns, if it is available. */ - def parseAnnotations(onlyScalaSig: Boolean): Option[AnnotationInfo] = { - val nAttr = u2 - var scalaSigAnnot: Option[AnnotationInfo] = None - for (n <- 0 until nAttr) parseAnnotation(u2, onlyScalaSig) match { - case Some(scalaSig) if scalaSig.atp == ScalaSignatureAnnotation.tpe => - scalaSigAnnot = Some(scalaSig) - case Some(scalaSig) if scalaSig.atp == ScalaLongSignatureAnnotation.tpe => - scalaSigAnnot = Some(scalaSig) - case Some(annot) => - sym.addAnnotation(annot) - case None => - } - scalaSigAnnot + def parseAnnotArg(): Option[ClassfileAnnotArg] = { + val tag = u1 + val index = u2 + tag match { + case STRING_TAG => + Some(LiteralAnnotArg(Constant(pool.getName(index).value))) + case BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | INT_TAG | + LONG_TAG | FLOAT_TAG | DOUBLE_TAG => + Some(LiteralAnnotArg(pool.getConstant(index))) + case CLASS_TAG => + Some(LiteralAnnotArg(Constant(pool.getType(index)))) + case ENUM_TAG => + val t = pool.getType(index) + val n = readName() + val module = t.typeSymbol.companionModule + val s = module.info.decls.lookup(n) + if (s != NoSymbol) Some(LiteralAnnotArg(Constant(s))) + else { + warning( + sm"""While parsing annotations in ${file}, could not find $n in enum ${module.nameString}. + |This is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (scala/bug#7014).""" + ) + None + } + + case ARRAY_TAG => + val arr = new ArrayBuffer[ClassfileAnnotArg]() + var hasError = false + for (i <- 0 until index) + parseAnnotArg() match { + case Some(c) => arr += c + case None => hasError = true + } + if (hasError) None + else Some(ArrayAnnotArg(arr.toArray)) + case ANNOTATION_TAG => + parseAnnotation(index) map (NestedAnnotArg(_)) } + } - def addParamNames(): Unit = - if ((paramNames ne null) && sym.hasRawInfo && sym.isMethod) { - val params = sym.rawInfo.params - foreach2(paramNames.toList, params) { - case (nme.NO_NAME, _) => // param was ACC_SYNTHETIC; ignore - case (name, param) => - param.resetFlag(SYNTHETIC) - param.name = name - } - devWarningIf(!sameLength(paramNames.toList, params)) { - // there's not anything we can do, but it's slightly worrisome - sm"""MethodParameters length mismatch while parsing $sym: - | rawInfo.params: ${sym.rawInfo.params} - | MethodParameters: ${paramNames.toList}""" - } - } - // begin parseAttributes - for (i <- 0 until u2) parseAttribute() - addParamNames() + // TODO scala/bug#9296 duplicated code, refactor + /** + * Parse and return a single annotation. If it is malformed, return None. + */ + def parseAnnotation(attrNameIndex: Int): Option[AnnotationInfo] = try { + val attrType = pool.getType(attrNameIndex) + val nargs = u2 + val nvpairs = new ListBuffer[(Name, ClassfileAnnotArg)] + var hasError = false + for (i <- 0 until nargs) { + val name = readName() + parseAnnotArg() match { + case Some(c) => nvpairs += ((name, c)) + case None => hasError = true + } + } + if (hasError) None + else Some(AnnotationInfo(attrType, List(), nvpairs.toList)) + } catch { + case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found + case NonFatal(ex) => + // We want to be robust when annotations are unavailable, so the very least + // we can do is warn the user about the exception + // There was a reference to ticket 1135, but that is outdated: a reference to a class not on + // the classpath would *not* end up here. A class not found is signaled + // with a `FatalError` exception, handled above. Here you'd end up after a NPE (for example), + // and that should never be swallowed silently. + warning(s"Caught: $ex while parsing annotations in ${file}") + if (settings.debug) ex.printStackTrace() + None // ignore malformed annotations } /** Apply `@native`/`@transient`/`@volatile` annotations to `sym`, @@ -1136,9 +994,9 @@ abstract class ClassfileParser { /** Enter own inner classes in the right scope. It needs the scopes to be set up, * and implicitly current class' superclasses. */ - private def enterOwnInnerClasses() { - def className(name: Name): Name = - name.subName(name.lastPos('.') + 1, name.length) + private def enterOwnInnerClasses(): Unit = { + def className(name: String): String = + name.substring(name.lastIndexOf('.') + 1, name.length) def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile) { def jflags = entry.jflags @@ -1186,8 +1044,8 @@ abstract class ClassfileParser { decls unlink e } - val cName = className(entry.externalName) - unlinkIfPresent(cName.toTermName) + val cName = newTermName(className(entry.externalName)) + unlinkIfPresent(cName) unlinkIfPresent(cName.toTypeName) } @@ -1200,54 +1058,145 @@ abstract class ClassfileParser { } } - /** Parse inner classes. Expects `in.bp` to point to the superclass entry. - * Restores the old `bp`. + /** + * Either + * - set `isScala` and invoke the unpickler, or + * - set `isScalaRaw`, or + * - parse inner classes (for Java classfiles) + * + * Expects `in.bp` to point to the `access_flags` entry, restores the old `bp`. */ - def parseInnerClasses() { + def unpickleOrParseInnerClasses() { val oldbp = in.bp + in.skip(4) // access_flags, this_class skipSuperclasses() skipMembers() // fields skipMembers() // methods - val attrs = u2 - for (i <- 0 until attrs) { + + var innersStart = -1 + var runtimeAnnotStart = -1 + + val numAttrs = u2 + var i = 0 + while (i < numAttrs) { val attrName = readTypeName() val attrLen = u4 attrName match { case tpnme.ScalaSignatureATTR => isScala = true - val pbuf = new PickleBuffer(in.buf, in.bp, in.bp + attrLen) - pbuf.readNat(); pbuf.readNat() - if (pbuf.readNat == 0) // a scala signature attribute with no entries means that the actual scala signature - isScalaAnnot = true // is in a ScalaSignature annotation. - in.skip(attrLen) + if (runtimeAnnotStart != -1) i = numAttrs case tpnme.ScalaATTR => isScalaRaw = true - case tpnme.InnerClassesATTR if !isScala => - val entries = u2 - for (i <- 0 until entries) { - val innerIndex, outerIndex, nameIndex = u2 - val jflags = readInnerClassFlags() - if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0) - innerClasses add InnerClassEntry(innerIndex, outerIndex, nameIndex, jflags) + i = numAttrs + case tpnme.InnerClassesATTR => + innersStart = in.bp + case tpnme.RuntimeAnnotationATTR => + runtimeAnnotStart = in.bp + if (isScala) i = numAttrs + case _ => + } + in.skip(attrLen) + i += 1 + } + + if (isScala) { + def parseScalaSigBytes(): Array[Byte] = { + val tag = u1 + assert(tag == STRING_TAG, tag) + pool.getBytes(u2) + } + + def parseScalaLongSigBytes(): Array[Byte] = { + val tag = u1 + assert(tag == ARRAY_TAG, tag) + val stringCount = u2 + val entries = + for (i <- 0 until stringCount) yield { + val stag = u1 + assert(stag == STRING_TAG, stag) + u2 } + pool.getBytes(entries.toList) + } + + def checkScalaSigAnnotArg() = { + val numArgs = u2 + assert(numArgs == 1, s"ScalaSignature has $numArgs arguments") + val name = readName() + assert(name == nme.bytes, s"ScalaSignature argument has name $name") + } + + def skipAnnotArg(): Unit = u1 match { + case STRING_TAG | BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | + INT_TAG | LONG_TAG | FLOAT_TAG | DOUBLE_TAG | CLASS_TAG => + in.skip(2) + + case ENUM_TAG => + in.skip(4) + + case ARRAY_TAG => + val num = u2 + for (i <- 0 until num) skipAnnotArg() + + case ANNOTATION_TAG => + in.skip(2) // type + skipAnnotArgs() + } + + def skipAnnotArgs() = { + val numArgs = u2 + for (i <- 0 until numArgs) { + in.skip(2) + skipAnnotArg() + } + } + + val SigTpe = ScalaSignatureAnnotation.tpe + val LongSigTpe = ScalaLongSignatureAnnotation.tpe + + assert(runtimeAnnotStart != -1, s"No RuntimeVisibleAnnotations in classfile with ScalaSignature attribute: $clazz") + in.bp = runtimeAnnotStart + val numAnnots = u2 + var i = 0 + var bytes: Array[Byte] = null + while (i < numAnnots && bytes == null) pool.getType(u2) match { + case SigTpe => + checkScalaSigAnnotArg() + bytes = parseScalaSigBytes() + case LongSigTpe => + checkScalaSigAnnotArg() + bytes = parseScalaLongSigBytes() case _ => - in.skip(attrLen) + skipAnnotArgs() + } + + AnyRefClass // Force scala.AnyRef, otherwise we get "error: Symbol AnyRef is missing from the classpath" + assert(bytes != null, s"No Scala(Long)Signature annotation in classfile with ScalaSignature attribute: $clazz") + unpickler.unpickle(bytes, 0, clazz, staticModule, file.name) + } else if (!isScalaRaw && innersStart != -1) { + in.bp = innersStart + val entries = u2 + for (i <- 0 until entries) { + val innerIndex, outerIndex, nameIndex = u2 + val jflags = readInnerClassFlags() + if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0) + innerClasses add InnerClassEntry(pool.getClassName(innerIndex), pool.getClassName(outerIndex), pool.getName(nameIndex), jflags) } } in.bp = oldbp } /** An entry in the InnerClasses attribute of this class file. */ - case class InnerClassEntry(external: Int, outer: Int, name: Int, jflags: JavaAccFlags) { - def externalName = pool getClassName external - def outerName = pool getClassName outer - def originalName = pool getName name + case class InnerClassEntry(external: NameOrString, outer: NameOrString, name: NameOrString, jflags: JavaAccFlags) { + def externalName = external.value + def outerName = outer.value + def originalName = name.name def isModule = originalName.isTermName def scope = if (jflags.isStatic) staticScope else instanceScope def enclosing = if (jflags.isStatic) enclModule else enclClass // The name of the outer class, without its trailing $ if it has one. - private def strippedOuter = outerName.dropModule + private def strippedOuter = outerName.stripSuffix(nme.MODULE_SUFFIX_STRING) private def isInner = innerClasses contains strippedOuter private def enclClass = if (isInner) innerClasses innerSymbol strippedOuter else classNameToSymbol(strippedOuter) private def enclModule = enclClass.companionModule @@ -1259,10 +1208,10 @@ abstract class ClassfileParser { * If the given name is not an inner class, it returns the symbol found in `definitions`. */ object innerClasses { - private val inners = mutable.HashMap[Name, InnerClassEntry]() + private val inners = mutable.HashMap[String, InnerClassEntry]() - def contains(name: Name) = inners contains name - def getEntry(name: Name) = inners get name + def contains(name: String) = inners contains name + def getEntry(name: String) = inners get name def entries = inners.values def add(entry: InnerClassEntry): Unit = { @@ -1272,7 +1221,7 @@ abstract class ClassfileParser { } inners(entry.externalName) = entry } - def innerSymbol(externalName: Name): Symbol = this getEntry externalName match { + def innerSymbol(externalName: String): Symbol = this getEntry externalName match { case Some(entry) => innerSymbol(entry) case _ => NoSymbol } @@ -1301,6 +1250,128 @@ abstract class ClassfileParser { sym setInfo createFromClonedSymbols(alias.initialize.typeParams, alias.tpe)(typeFun) } } + private class ParamNames(val names: Array[NameOrString], val access: Array[Int]) { + assert(names.length == access.length) + def length = names.length + } + private abstract class JavaTypeCompleter extends LazyType { + var constant: Constant = _ + var sig: String = _ + var paramNames: ParamNames = _ + var exceptions: List[NameOrString] = Nil + } + private final class ClassTypeCompleter(name: Name, jflags: JavaAccFlags, parent: NameOrString, ifaces: List[NameOrString]) extends JavaTypeCompleter { + override def complete(sym: symbolTable.Symbol): Unit = { + val info = if (sig != null) sigToType(sym, sig) else { + val superType = + if (parent == null) AnyClass.tpe_* + else if (jflags.isAnnotation) { u2; AnnotationClass.tpe } + else getClassSymbol(parent.value).tpe_* + var ifacesTypes = ifaces.filterNot(_ eq null).map(x => getClassSymbol(x.value).tpe_*) + if (jflags.isAnnotation) ifacesTypes ::= ClassfileAnnotationClass.tpe + ClassInfoType(superType :: ifacesTypes, instanceScope, clazz) + } + sym.setInfo(info) + } + } + + private final class MemberTypeCompleter(name: Name, jflags: JavaAccFlags, descriptor: String) extends JavaTypeCompleter { + override def isJavaVarargsMethod: Boolean = jflags.isVarargs + override def javaThrownExceptions: List[Symbol] = exceptions.map(e => classNameToSymbol(e.value)) + override def complete(sym: symbolTable.Symbol): Unit = { + def descriptorInfo = sigToType(sym, descriptor) + val hasOuterParam = (name == nme.CONSTRUCTOR) && (descriptorInfo match { + case MethodType(params, restpe) => + // if this is a non-static inner class, remove the explicit outer parameter + innerClasses getEntry currentClass match { + case Some(entry) if !entry.jflags.isStatic => + /* About `clazz.owner.hasPackageFlag` below: scala/bug#5957 + * For every nested java class A$B, there are two symbols in the scala compiler. + * 1. created by SymbolLoader, because of the existence of the A$B.class file, owner: package + * 2. created by ClassfileParser of A when reading the inner classes, owner: A + * If symbol 1 gets completed (e.g. because the compiled source mentions `A$B`, not `A#B`), the + * ClassfileParser for 1 executes, and clazz.owner is the package. + */ + assert(params.head.tpe.typeSymbol == clazz.owner || clazz.owner.hasPackageFlag, "" + params.head.tpe.typeSymbol + ": " + clazz.owner) + true + case _ => + false + } + case _ => false + }) + + val info = if (sig != null) { + sigToType(sym, sig) + } else if (name == nme.CONSTRUCTOR) { + descriptorInfo match { + case MethodType(params, restpe) => + val paramsNoOuter = if (hasOuterParam) params.tail else params + val newParams = paramsNoOuter match { + case (init :+ tail) if jflags.isSynthetic => + // scala/bug#7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which + // are added when an inner class needs to access a private constructor. + init + case _ => + paramsNoOuter + } + MethodType(newParams, clazz.tpe) + case info => info + } + } else { + descriptorInfo + } + if (constant != null) { + val c1 = convertTo(constant, info.resultType) + if (c1 ne null) sym.setInfo(ConstantType(c1)) + else { + devWarning(s"failure to convert $constant to ${info.resultType}") + sym.setInfo(info) + } + } else { + sym.setInfo(if (sym.isMethod && jflags.isVarargs) arrayToRepeated(info) else info) + } + + for (e <- exceptions) { + // we call initialize due to the fact that we call Symbol.isMonomorphicType in addThrowsAnnotation + // and that method requires Symbol to be forced to give the right answers, see scala/bug#7107 for details + val cls = getClassSymbol(e.value) + sym withAnnotation AnnotationInfo.lazily { + val throwableTpe = cls.tpe_* + AnnotationInfo(appliedType(ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil) + } + } + + // Note: the info may be overwritten later with a generic signature + // parsed from SignatureATTR + if (paramNames != null) { + import scala.tools.asm.Opcodes.ACC_SYNTHETIC + + if (sym.hasRawInfo && sym.isMethod) { + val paramNamesNoOuter = (if (hasOuterParam) 1 else 0) to paramNames.length + val params = sym.rawInfo.params + foreach2(paramNamesNoOuter.toList, params) { + case (i, param) => + val isSynthetic = (paramNames.access(i) & ACC_SYNTHETIC) != 0 + if (!isSynthetic) { + param.name = paramNames.names(i).name.toTermName.encode + param.resetFlag(SYNTHETIC) + } + } + // there's not anything we can do, but it's slightly worrisome + devWarningIf(!sameLength(paramNamesNoOuter.toList, params)) { + sm"""MethodParameters length mismatch while parsing $sym: + | rawInfo.params: ${sym.rawInfo.params}""" + } + } + } + } + private def convertTo(c: Constant, pt: Type): Constant = { + if (pt.typeSymbol == BooleanClass && c.tag == IntTag) + Constant(c.value != 0) + else + c convertTo pt + } + } def skipAttributes() { var attrCount: Int = u2 diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/DataReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/DataReader.scala new file mode 100644 index 000000000000..8c1287ac0df7 --- /dev/null +++ b/src/compiler/scala/tools/nsc/symtab/classfile/DataReader.scala @@ -0,0 +1,68 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala.tools.nsc.symtab.classfile + +trait DataReader { + + def bp: Int + def bp_=(i: Int): Unit + + /** read a byte + */ + @throws(classOf[IndexOutOfBoundsException]) + def nextByte: Byte + + /** read some bytes + */ + def nextBytes(len: Int): Array[Byte] + + /** read a character + */ + def nextChar: Char + + /** read an integer + */ + def nextInt: Int + + /** extract a character at position bp from buf + */ + def getChar(mybp: Int): Char + + /** extract an integer at position bp from buf + */ + def getByte(mybp: Int): Byte + + def getBytes(mybp: Int, bytes: Array[Byte]): Unit + + /** extract an integer at position bp from buf + */ + def getInt(mybp: Int): Int + + /** extract a long integer at position bp from buf + */ + def getLong(mybp: Int): Long + + /** extract a float at position bp from buf + */ + def getFloat(mybp: Int): Float + + /** extract a double at position bp from buf + */ + def getDouble(mybp: Int): Double + + def getUTF(mybp: Int, len: Int): String + + /** skip next 'n' bytes + */ + def skip(n: Int): Unit +} diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ReusableDataReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ReusableDataReader.scala new file mode 100644 index 000000000000..8bbbc4a3cce6 --- /dev/null +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ReusableDataReader.scala @@ -0,0 +1,156 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala.tools.nsc.symtab.classfile + +import java.io.{ByteArrayInputStream, DataInputStream, InputStream} +import java.nio.channels.Channels +import java.nio.{BufferUnderflowException, ByteBuffer} + +final class ReusableDataReader() extends DataReader { + private[this] var data = new Array[Byte](32768) + private[this] var bb: ByteBuffer = ByteBuffer.wrap(data) + private[this] var size = 0 + private[this] val reader: DataInputStream = { + val stream = new InputStream { + override def read(): Int = try { + bb.get & 0xff + } catch { + case _: BufferUnderflowException => -1 + } + + override def read(b: Array[Byte], off: Int, len: Int): Int = { + val pos = bb.position() + bb.get(b, off, len) + bb.position() - pos + } + + override def markSupported(): Boolean = false + } + new DataInputStream(stream) + } + + private def nextPositivePowerOfTwo(target: Int): Int = 1 << -Integer.numberOfLeadingZeros(target - 1) + + def reset(file: scala.reflect.io.AbstractFile): this.type = { + this.size = 0 + file.sizeOption match { + case Some(size) => + if (size > data.length) { + data = new Array[Byte](nextPositivePowerOfTwo(size)) + } else { + java.util.Arrays.fill(data, 0.toByte) + } + val input = file.input + try { + var endOfInput = false + while (!endOfInput) { + val remaining = data.length - this.size + if (remaining == 0) endOfInput = true + else { + val read = input.read(data, this.size, remaining) + if (read < 0) endOfInput = true + else this.size += read + } + } + bb = ByteBuffer.wrap(data, 0, size) + } finally { + input.close() + } + case None => + val input = file.input + try { + var endOfInput = false + while (!endOfInput) { + val remaining = data.length - size + if (remaining == 0) { + data = java.util.Arrays.copyOf(data, nextPositivePowerOfTwo(size)) + } + val read = input.read(data, this.size, data.length - this.size) + if (read < 0) endOfInput = true + else this.size += read + } + bb = ByteBuffer.wrap(data, 0, size) + } finally { + input.close() + } + } + this + } + + @throws(classOf[IndexOutOfBoundsException]) + def nextByte: Byte = bb.get + + def nextBytes(len: Int): Array[Byte] = { + val result = new Array[Byte](len) + reader.readFully(result) + result + } + + def nextChar: Char = bb.getChar() + + def nextInt: Int = bb.getInt() + + def getChar(mybp: Int): Char = { + bb.getChar(mybp) + } + + def getInt(mybp: Int): Int = { + bb.getInt(mybp) + } + + def getLong(mybp: Int): Long = { + bb.getLong(mybp) + } + + def getFloat(mybp: Int): Float = { + bb.getFloat(mybp) + } + + def getDouble(mybp: Int): Double = { + bb.getDouble(mybp) + } + + def skip(n: Int): Unit = { + bb.position(bb.position() + n) + } + def bp: Int = bb.position() + def bp_=(i: Int): Unit = { + try { + bb.position(i) + } catch { + case ex: IllegalArgumentException => + throw ex + } + } + + def getByte(mybp: Int): Byte = { + bb.get(mybp) + } + def getBytes(mybp: Int, bytes: Array[Byte]): Unit = { + val saved = bb.position() + bb.position(mybp) + try reader.readFully(bytes) + finally bb.position(saved) + } + def getUTF(mybp: Int, len: Int): String = { + val saved = bb.position() + val savedLimit = bb.limit() + bb.position(mybp) + bb.limit(mybp + len) + try reader.readUTF() + finally { + bb.limit(savedLimit) + bb.position(saved) + } + } +} diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala index 4714b351944b..d201a14570f2 100644 --- a/src/library/scala/concurrent/Awaitable.scala +++ b/src/library/scala/concurrent/Awaitable.scala @@ -60,7 +60,8 @@ trait Awaitable[+T] { * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ - @throws(classOf[Exception]) + @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) def result(atMost: Duration)(implicit permit: CanAwait): T } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 8f6983b27d1d..4f12a8379419 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -578,7 +578,8 @@ object Future { throw new TimeoutException(s"Future timed out after [$atMost]") } - @throws(classOf[Exception]) + @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) override def result(atMost: Duration)(implicit permit: CanAwait): Nothing = { ready(atMost) throw new TimeoutException(s"Future timed out after [$atMost]") diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index 042b1ab636d0..bc3853a0b98b 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -214,7 +214,8 @@ package concurrent { * @throws TimeoutException if after waiting for the specified time `awaitable` is still not ready * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ - @throws(classOf[Exception]) + @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) def result[T](awaitable: Awaitable[T], atMost: Duration): T = blocking(awaitable.result(atMost)(AwaitPermission)) } diff --git a/src/library/scala/deprecated.scala b/src/library/scala/deprecated.scala index b35288a22915..42dccf60cb69 100644 --- a/src/library/scala/deprecated.scala +++ b/src/library/scala/deprecated.scala @@ -64,5 +64,5 @@ import scala.annotation.meta._ * @see [[scala.deprecatedOverriding]] * @see [[scala.deprecatedName]] */ -@getter @setter @beanGetter @beanSetter +@getter @setter @beanGetter @beanSetter @field class deprecated(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 2828db3e01d4..eba017a6ae87 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -192,11 +192,11 @@ trait Definitions extends api.StandardDefinitions { // It becomes tricky to create dedicated objects for other symbols because // of initialization order issues. - lazy val JavaLangPackage = getPackage(TermName("java.lang")) + lazy val JavaLangPackage = getPackage("java.lang") lazy val JavaLangPackageClass = JavaLangPackage.moduleClass.asClass - lazy val ScalaPackage = getPackage(TermName("scala")) + lazy val ScalaPackage = getPackage("scala") lazy val ScalaPackageClass = ScalaPackage.moduleClass.asClass - lazy val RuntimePackage = getPackage(TermName("scala.runtime")) + lazy val RuntimePackage = getPackage("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass.asClass def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { @@ -292,7 +292,7 @@ trait Definitions extends api.StandardDefinitions { // top types lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) markAllCompleted lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe) markAllCompleted - lazy val ObjectClass = getRequiredClass(sn.Object.toString) + lazy val ObjectClass = getRequiredClass("java.lang.Object") // Cached types for core monomorphic classes lazy val AnyRefTpe = AnyRefClass.tpe @@ -343,12 +343,12 @@ trait Definitions extends api.StandardDefinitions { // exceptions and other throwables lazy val ClassCastExceptionClass = requiredClass[ClassCastException] - lazy val IndexOutOfBoundsExceptionClass = getClassByName(sn.IOOBException) - lazy val InvocationTargetExceptionClass = getClassByName(sn.InvTargetException) + lazy val IndexOutOfBoundsExceptionClass = getClassByName("java.lang.IndexOutOfBoundsException") + lazy val InvocationTargetExceptionClass = getClassByName("java.lang.reflect.InvocationTargetException") lazy val MatchErrorClass = requiredClass[MatchError] lazy val NonLocalReturnControlClass = requiredClass[scala.runtime.NonLocalReturnControl[_]] - lazy val NullPointerExceptionClass = getClassByName(sn.NPException) - lazy val ThrowableClass = getClassByName(sn.Throwable) + lazy val NullPointerExceptionClass = getClassByName("java.lang.NullPointerException") + lazy val ThrowableClass = getClassByName("java.lang.Throwable") lazy val UninitializedErrorClass = requiredClass[UninitializedFieldError] lazy val IllegalArgExceptionClass = requiredClass[IllegalArgumentException] @@ -422,7 +422,10 @@ trait Definitions extends api.StandardDefinitions { def isByName(param: Symbol) = isByNameParamType(param.tpe_*) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf - def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) + def isJavaVarArgsMethod(m: Symbol) = m.isMethod && (m.rawInfo match { + case completer: LazyType => completer.isJavaVarargsMethod + case _ => isJavaVarArgs(m.info.params) + }) def isJavaVarArgs(params: Seq[Symbol]) = !params.isEmpty && isJavaRepeatedParamType(params.last.tpe) def isScalaVarArgs(params: Seq[Symbol]) = !params.isEmpty && isScalaRepeatedParamType(params.last.tpe) def isVarArgsList(params: Seq[Symbol]) = !params.isEmpty && isRepeatedParamType(params.last.tpe) @@ -488,7 +491,7 @@ trait Definitions extends api.StandardDefinitions { // reflection / structural types lazy val SoftReferenceClass = requiredClass[java.lang.ref.SoftReference[_]] - lazy val MethodClass = getClassByName(sn.MethodAsObject) + lazy val MethodClass = getClassByName("java.lang.reflect.Method") lazy val EmptyMethodCacheClass = requiredClass[scala.runtime.EmptyMethodCache] lazy val MethodCacheClass = requiredClass[scala.runtime.MethodCache] def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_) @@ -1219,7 +1222,7 @@ trait Definitions extends api.StandardDefinitions { // Trying to allow for deprecated locations sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol) ) - lazy val metaAnnotations: Set[Symbol] = getPackage(TermName("scala.annotation.meta")).info.members filter (_ isSubClass StaticAnnotationClass) toSet + lazy val metaAnnotations: Set[Symbol] = getPackage("scala.annotation.meta").info.members filter (_ isSubClass StaticAnnotationClass) toSet // According to the scala.annotation.meta package object: // * By default, annotations on (`val`-, `var`- or plain) constructor parameters diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index befaa49175a1..0ca0794600a9 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -46,19 +46,23 @@ trait Mirrors extends api.Mirrors { } /** Todo: organize similar to mkStatic in scala.reflect.Base */ - private def getModuleOrClass(path: Name, len: Int): Symbol = { - val point = path lastPos('.', len - 1) + private def getModuleOrClass(path: Name, len: Int): Symbol = + getModuleOrClass(path.toString, len, path.newName(_)) + + private def getModuleOrClass(path: String, len: Int, toName: String => Name): Symbol = { + val point = path lastIndexOf ('.', len - 1) val owner = - if (point > 0) getModuleOrClass(path.toTermName, point) + if (point > 0) getModuleOrClass(path, point, newTermName(_)) else RootClass - val name = path subName (point + 1, len) + + val name = toName(path.substring(point + 1, len)) val sym = owner.info member name - val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym + val result = if (name.isTermName) sym.suchThat(_ hasFlag MODULE) else sym if (result != NoSymbol) result else { if (settings.debug) { log(sym.info); log(sym.info.members) }//debug thisMirror.missingHook(owner, name) orElse { - MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror) + MissingRequirementError.notFound((if (name.isTermName) "object " else "class ")+path+" in "+thisMirror) } } } @@ -69,8 +73,8 @@ trait Mirrors extends api.Mirrors { * Unlike `getModuleOrClass`, this function * loads unqualified names from the root package. */ - private def getModuleOrClass(path: Name): Symbol = - getModuleOrClass(path, path.length) + private def getModuleOrClass(path: String, toName: String => Name): Symbol = + getModuleOrClass(path, path.length, toName) /** If you're looking for a class, pass a type name. * If a module, a term name. @@ -78,10 +82,10 @@ trait Mirrors extends api.Mirrors { * Unlike `getModuleOrClass`, this function * loads unqualified names from the empty package. */ - private def staticModuleOrClass(path: Name): Symbol = { - val isPackageless = path.pos('.') == path.length - if (isPackageless) EmptyPackageClass.info decl path - else getModuleOrClass(path) + private def staticModuleOrClass(path: String, toName: String => Name): Symbol = { + val isPackageless = !path.contains('.') + if (isPackageless) EmptyPackageClass.info decl toName(path) + else getModuleOrClass(path, toName) } protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol @@ -104,28 +108,41 @@ trait Mirrors extends api.Mirrors { } } + @deprecated("Use overload that accepts a String.", "2.13.0") def getClassByName(fullname: Name): ClassSymbol = - ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName)) + ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toString, fullname.length, newTypeName(_))) + + def getClassByName(fullname: String): ClassSymbol = + getRequiredClass(fullname) + + // TODO_NAMES + def getRequiredClass(fullname: String, toName: String => Name): ClassSymbol = + ensureClassSymbol(fullname, getModuleOrClass(fullname, fullname.length, toName)) def getRequiredClass(fullname: String): ClassSymbol = - getClassByName(newTypeNameCached(fullname)) + ensureClassSymbol(fullname, getModuleOrClass(fullname, fullname.length, newTypeName(_))) def requiredClass[T: ClassTag] : ClassSymbol = - getRequiredClass(erasureName[T]) + getRequiredClass(erasureName[T], newTypeName(_)) def getClassIfDefined(fullname: String): Symbol = - getClassIfDefined(newTypeNameCached(fullname)) + getClassIfDefined(fullname, newTypeName(_)) + @deprecated("Use overload that accepts a String.", "2.13.0") def getClassIfDefined(fullname: Name): Symbol = wrapMissing(getClassByName(fullname.toTypeName)) + // TODO_NAMES + def getClassIfDefined(fullname: String, toName: String => Name): Symbol = + wrapMissing(getRequiredClass(fullname, toName)) + /** @inheritdoc * * Unlike getClassByName/getRequiredClass this function can also load packageless symbols. * Compiler might ignore them, but they should be loadable with macros. */ override def staticClass(fullname: String): ClassSymbol = - try ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname))) + try ensureClassSymbol(fullname, staticModuleOrClass(fullname, newTypeName(_))) catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) } /************************ loaders of module symbols ************************/ @@ -136,11 +153,15 @@ trait Mirrors extends api.Mirrors { case _ => MissingRequirementError.notFound("object " + fullname) } + @deprecated("Use overload that accepts a String.", "2.13.0") def getModuleByName(fullname: Name): ModuleSymbol = - ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true) + getModuleByName(fullname.toString) + + def getModuleByName(fullname: String): ModuleSymbol = + ensureModuleSymbol(fullname, getModuleOrClass(fullname, fullname.length, newTermName(_)), allowPackages = true) def getRequiredModule(fullname: String): ModuleSymbol = - getModuleByName(newTermNameCached(fullname)) + getModuleByName(fullname) // TODO: What syntax do we think should work here? Say you have an object // like scala.Predef. You can't say requiredModule[scala.Predef] since there's @@ -153,10 +174,11 @@ trait Mirrors extends api.Mirrors { getRequiredModule(erasureName[T] stripSuffix "$") def getModuleIfDefined(fullname: String): Symbol = - getModuleIfDefined(newTermNameCached(fullname)) + wrapMissing(getModuleByName(fullname)) + @deprecated("Use overload that accepts a String.", "2.13.0") def getModuleIfDefined(fullname: Name): Symbol = - wrapMissing(getModuleByName(fullname.toTermName)) + getModuleIfDefined(fullname.toString) /** @inheritdoc * @@ -164,7 +186,7 @@ trait Mirrors extends api.Mirrors { * Compiler might ignore them, but they should be loadable with macros. */ override def staticModule(fullname: String): ModuleSymbol = - try ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false) + try ensureModuleSymbol(fullname, staticModuleOrClass(fullname, newTermName(_)), allowPackages = false) catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) } /************************ loaders of package symbols ************************/ @@ -175,8 +197,11 @@ trait Mirrors extends api.Mirrors { case _ => MissingRequirementError.notFound("package " + fullname) } + @deprecated("Use overload that accepts a String.", "2.13.0") def getPackage(fullname: TermName): ModuleSymbol = - ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true) + getPackage(fullname.toString) + def getPackage(fullname: String): ModuleSymbol = + ensurePackageSymbol(fullname, getModuleOrClass(fullname, newTermName(_)), allowModules = true) def getPackageIfDefined(fullname: TermName): Symbol = wrapMissing(getPackage(fullname)) @@ -198,7 +223,7 @@ trait Mirrors extends api.Mirrors { wrapMissing(getPackageObject(fullname)) override def staticPackage(fullname: String): ModuleSymbol = - try ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false) + try ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname, fullname.length, newTermName(_)), allowModules = false) catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) } /************************ helpers ************************/ diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 7e19e72e9ea7..e74257dde1d2 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -52,6 +52,8 @@ trait Names extends api.Names { /** Hashtable for finding type names quickly. */ private val typeHashtable = new Array[TypeName](HASH_SIZE) + final def allNames(): Iterator[TermName] = termHashtable.iterator.filter(_ ne null).flatMap(n => Iterator.iterate(n)(_.next).takeWhile(_ ne null)) + private def hashValue(cs: Array[Char], offset: Int, len: Int): Int = { var h = 0 var i = 0 diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 6428d83cdf18..75935982a85e 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -1170,21 +1170,15 @@ trait StdNames { protected val stringToTypeName = null protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s) - final val BoxedBoolean: TypeName = "java.lang.Boolean" - final val BoxedByte: TypeName = "java.lang.Byte" - final val BoxedCharacter: TypeName = "java.lang.Character" - final val BoxedDouble: TypeName = "java.lang.Double" - final val BoxedFloat: TypeName = "java.lang.Float" - final val BoxedInteger: TypeName = "java.lang.Integer" - final val BoxedLong: TypeName = "java.lang.Long" - final val BoxedNumber: TypeName = "java.lang.Number" - final val BoxedShort: TypeName = "java.lang.Short" - final val IOOBException: TypeName = "java.lang.IndexOutOfBoundsException" - final val InvTargetException: TypeName = "java.lang.reflect.InvocationTargetException" - final val MethodAsObject: TypeName = "java.lang.reflect.Method" - final val NPException: TypeName = "java.lang.NullPointerException" - final val Object: TypeName = "java.lang.Object" - final val Throwable: TypeName = "java.lang.Throwable" + final val BoxedBoolean: String = "java.lang.Boolean" + final val BoxedByte: String = "java.lang.Byte" + final val BoxedCharacter: String = "java.lang.Character" + final val BoxedDouble: String = "java.lang.Double" + final val BoxedFloat: String = "java.lang.Float" + final val BoxedInteger: String = "java.lang.Integer" + final val BoxedLong: String = "java.lang.Long" + final val BoxedNumber: String = "java.lang.Number" + final val BoxedShort: String = "java.lang.Short" final val GetCause: TermName = newTermName("getCause") final val GetClass: TermName = newTermName("getClass") @@ -1197,7 +1191,7 @@ trait StdNames { final val AltMetafactory: TermName = newTermName("altMetafactory") final val Bootstrap: TermName = newTermName("bootstrap") - val Boxed = immutable.Map[TypeName, TypeName]( + val Boxed = immutable.Map[TypeName, String]( tpnme.Boolean -> BoxedBoolean, tpnme.Byte -> BoxedByte, tpnme.Char -> BoxedCharacter, diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 7982e71000c9..8d9d87c7c2ad 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -24,7 +24,7 @@ import scala.collection.mutable.ListBuffer import util.{ Statistics, shortClassOfInstance, StatisticsStatics } import Flags._ import scala.annotation.tailrec -import scala.reflect.io.{ AbstractFile, NoAbstractFile } +import scala.reflect.io.{AbstractFile, NoAbstractFile} import Variance._ trait Symbols extends api.Symbols { self: SymbolTable => @@ -3030,7 +3030,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => loop(info) } - override def exceptions = for (ThrownException(tp) <- annotations) yield tp.typeSymbol + override def exceptions = { + rawInfo match { + case lt: LazyType if isJava => + lt.javaThrownExceptions + case _ => + for (ThrownException(tp) <- annotations) yield tp.typeSymbol + } + } } implicit val MethodSymbolTag = ClassTag[MethodSymbol](classOf[MethodSymbol]) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 92ac84ff876d..6710f0abbe7f 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1540,53 +1540,9 @@ trait Types throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol) } - object baseClassesCycleMonitor { - private var open: List[Symbol] = Nil - @inline private def cycleLog(msg: => String) { - if (settings.debug) - Console.err.println(msg) - } - def size = open.size - def push(clazz: Symbol) { - cycleLog("+ " + (" " * size) + clazz.fullNameString) - open ::= clazz - } - def pop(clazz: Symbol) { - assert(open.head eq clazz, (clazz, open)) - open = open.tail - } - def isOpen(clazz: Symbol) = open contains clazz - } - protected def defineBaseClassesOfCompoundType(tpe: CompoundType) { - def define() = defineBaseClassesOfCompoundType(tpe, force = false) - if (!breakCycles || isPastTyper) define() - else tpe match { - // non-empty parents helpfully excludes all package classes - case tpe @ ClassInfoType(_ :: _, _, clazz) if !clazz.isAnonOrRefinementClass => - // Cycle: force update - if (baseClassesCycleMonitor isOpen clazz) - defineBaseClassesOfCompoundType(tpe, force = true) - else { - baseClassesCycleMonitor push clazz - try define() - finally baseClassesCycleMonitor pop clazz - } - case _ => - define() - } - } - private def defineBaseClassesOfCompoundType(tpe: CompoundType, force: Boolean) { val period = tpe.baseClassesPeriod - if (period == currentPeriod) { - if (force && breakCycles) { - def what = tpe.typeSymbol + " in " + tpe.typeSymbol.owner.fullNameString - val bcs = computeBaseClasses(tpe) - tpe.baseClassesCache = bcs - warning(s"Breaking cycle in base class computation of $what ($bcs)") - } - } - else { + if (period != currentPeriod) { tpe.baseClassesPeriod = currentPeriod if (!isValidForBaseClasses(period)) { val start = if (StatisticsStatics.areSomeColdStatsEnabled) statistics.pushTimer(typeOpsStack, baseClassesNanos) else null @@ -3555,6 +3511,8 @@ trait Types override def complete(sym: Symbol) override def safeToString = "" override def kind = "LazyType" + def isJavaVarargsMethod: Boolean = false + def javaThrownExceptions: List[Symbol] = Nil } /** A marker trait representing an as-yet unevaluated type diff --git a/src/reflect/scala/reflect/io/AbstractFile.scala b/src/reflect/scala/reflect/io/AbstractFile.scala index 714f4f4b5274..b8bd8826a3fc 100644 --- a/src/reflect/scala/reflect/io/AbstractFile.scala +++ b/src/reflect/scala/reflect/io/AbstractFile.scala @@ -17,6 +17,7 @@ package io import java.io.{ IOException, InputStream, OutputStream, BufferedOutputStream, ByteArrayOutputStream } import java.io.{ File => JFile } import java.net.URL +import java.nio.ByteBuffer /** * An abstraction over files for use in the reflection/compiler libraries. @@ -192,6 +193,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { out.toByteArray() } } + def toByteBuffer: ByteBuffer = ByteBuffer.wrap(toByteArray) /** Returns all abstract subfiles of this abstract directory. */ def iterator: Iterator[AbstractFile] diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala index 75ba6e852023..406e6db458a9 100644 --- a/src/reflect/scala/reflect/io/PlainFile.scala +++ b/src/reflect/scala/reflect/io/PlainFile.scala @@ -14,6 +14,10 @@ package scala package reflect package io +import java.nio.ByteBuffer +import java.nio.file.StandardOpenOption +import java.util + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { override def isDirectory = true @@ -49,6 +53,20 @@ class PlainFile(val givenPath: Path) extends AbstractFile { override def input = givenPath.toFile.inputStream() override def output = givenPath.toFile.outputStream() override def sizeOption = Some(givenPath.length.toInt) + override def toByteBuffer: ByteBuffer = { + val chan = java.nio.file.Files.newByteChannel(file.toPath, util.EnumSet.of(StandardOpenOption.READ)) + try { + import java.nio.ByteBuffer + val buffer: ByteBuffer = ByteBuffer.allocate(chan.size.toInt) + var endOfInput = false + while (!endOfInput ) { + endOfInput = chan.read(buffer) < 0 + buffer.compact() + } + buffer.flip() + buffer + } finally chan.close() + } override def hashCode(): Int = fpath.hashCode() override def equals(that: Any): Boolean = that match { diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 0b4d7131fbeb..264a3cd9afda 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -162,7 +162,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.SuperType this.TypeBounds this.CompoundType - this.baseClassesCycleMonitor this.RefinedType this.ClassInfoType this.ConstantType diff --git a/test/files/jvm/future-spec/main.scala b/test/files/jvm/future-spec/main.scala index 697d0fe91f3f..f5db78e30b11 100644 --- a/test/files/jvm/future-spec/main.scala +++ b/test/files/jvm/future-spec/main.scala @@ -107,7 +107,7 @@ class TestLatch(count: Int = 1) extends Awaitable[Unit] { this } - @throws(classOf[Exception]) + @throws(classOf[TimeoutException]) def result(atMost: Duration)(implicit permit: CanAwait): Unit = { ready(atMost) } diff --git a/test/files/jvm/throws-annot-from-java.check b/test/files/jvm/throws-annot-from-java.check index bf639260e77a..4a4bd6ad2110 100644 --- a/test/files/jvm/throws-annot-from-java.check +++ b/test/files/jvm/throws-annot-from-java.check @@ -8,10 +8,10 @@ scala> :paste // Entering paste mode (ctrl-D to finish) { - val clazz = rootMirror.getClassByName(newTermName("test.ThrowsDeclaration_2")); + val clazz = rootMirror.getClassByName("test.ThrowsDeclaration_2"); { val method = clazz.info.member(newTermName("foo")) - val throwsAnn = method.annotations.head + val throwsAnn = method.initialize.annotations.head val atp = throwsAnn.atp println("foo") println("atp.typeParams.isEmpty: " + atp.typeParams.isEmpty) @@ -21,7 +21,7 @@ scala> :paste { val method = clazz.info.member(newTermName("bar")) - val throwsAnn = method.annotations.head + val throwsAnn = method.initialize.annotations.head val Literal(const) = throwsAnn.args.head val tp = const.typeValue println("bar") @@ -37,7 +37,7 @@ atp.typeParams.isEmpty: true throws[IllegalStateException](classOf[java.lang.IllegalStateException]) bar -tp.typeParams.isEmpty: true -throws[test.PolymorphicException[_]](classOf[test.PolymorphicException]) +tp.typeParams.isEmpty: false +throws[test.PolymorphicException](classOf[test.PolymorphicException]) scala> :quit diff --git a/test/files/jvm/throws-annot-from-java/Test_3.scala b/test/files/jvm/throws-annot-from-java/Test_3.scala index de1d9845732a..df62e032262e 100644 --- a/test/files/jvm/throws-annot-from-java/Test_3.scala +++ b/test/files/jvm/throws-annot-from-java/Test_3.scala @@ -4,10 +4,10 @@ object Test extends ReplTest { def code = """:power :paste { - val clazz = rootMirror.getClassByName(newTermName("test.ThrowsDeclaration_2")); + val clazz = rootMirror.getClassByName("test.ThrowsDeclaration_2"); { val method = clazz.info.member(newTermName("foo")) - val throwsAnn = method.annotations.head + val throwsAnn = method.initialize.annotations.head val atp = throwsAnn.atp println("foo") println("atp.typeParams.isEmpty: " + atp.typeParams.isEmpty) @@ -17,7 +17,7 @@ object Test extends ReplTest { { val method = clazz.info.member(newTermName("bar")) - val throwsAnn = method.annotations.head + val throwsAnn = method.initialize.annotations.head val Literal(const) = throwsAnn.args.head val tp = const.typeValue println("bar") diff --git a/test/files/neg/moduleClassReference.check b/test/files/neg/moduleClassReference.check new file mode 100644 index 000000000000..1f16aeb2509f --- /dev/null +++ b/test/files/neg/moduleClassReference.check @@ -0,0 +1,4 @@ +moduleClassReference.scala:2: error: not found: value Predef$ + def foo = Predef$.MODULE$ == Predef + ^ +one error found diff --git a/test/files/neg/moduleClassReference.scala b/test/files/neg/moduleClassReference.scala new file mode 100644 index 000000000000..dbf688840e2f --- /dev/null +++ b/test/files/neg/moduleClassReference.scala @@ -0,0 +1,3 @@ +object Test { + def foo = Predef$.MODULE$ == Predef +} diff --git a/test/files/neg/t7251.check b/test/files/neg/t7251.check index 33fdafc2ee1e..a17e710d367e 100644 --- a/test/files/neg/t7251.check +++ b/test/files/neg/t7251.check @@ -1,4 +1,4 @@ -B_2.scala:5: error: class s.Outer$Triple$ is not a value +B_2.scala:5: error: object Outer$Triple$ is not a member of package s println( s.Outer$Triple$ ) ^ one error found diff --git a/test/files/pos/t11538.flags b/test/files/pos/t11538.flags new file mode 100644 index 000000000000..7882ee62698f --- /dev/null +++ b/test/files/pos/t11538.flags @@ -0,0 +1 @@ +-Xfatal-warnings -deprecation -stop:refchecks \ No newline at end of file diff --git a/test/files/pos/t11538.scala b/test/files/pos/t11538.scala new file mode 100644 index 000000000000..77c931e2c202 --- /dev/null +++ b/test/files/pos/t11538.scala @@ -0,0 +1,13 @@ +package t11538 + +@deprecated("not for you", since = "just now") +class Abhorrent + +object Bizzle { + @deprecated("use mipple instead", since = "recently") + val wibble: Abhorrent = mipple + @deprecated("use wobble instead", since = "recently") + def mipple: Abhorrent = wobble + @deprecated("use wibble instead", since = "recently") + var wobble: Abhorrent = wibble +} \ No newline at end of file diff --git a/test/files/run/compiler-asSeenFrom.scala b/test/files/run/compiler-asSeenFrom.scala index a60c2e892524..940907665820 100644 --- a/test/files/run/compiler-asSeenFrom.scala +++ b/test/files/run/compiler-asSeenFrom.scala @@ -42,7 +42,7 @@ abstract class CompilerTest extends DirectTest { } class SymsInPackage(pkgName: String) { - def pkg = rootMirror.getPackage(TermName(pkgName)) + def pkg = rootMirror.getPackage(pkgName) def classes = allMembers(pkg) filter (_.isClass) def modules = allMembers(pkg) filter (_.isModule) def symbols = classes ++ terms filterNot (_ eq NoSymbol) diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala index e35b7231c2d3..2984d81e6009 100644 --- a/test/files/run/existentials-in-compiler.scala +++ b/test/files/run/existentials-in-compiler.scala @@ -74,8 +74,8 @@ package extest { } """ - override def check(source: String, unit: global.CompilationUnit) { - getPackage(TermName("extest")).moduleClass.info.decls.toList.filter(_.isType).map(_.initialize).sortBy(_.name.toString) foreach { clazz => + override def check(source: String, unit: global.CompilationUnit): Unit = { + getPackage("extest").moduleClass.info.decls.toList.filter(_.isType).map(_.initialize).sortBy(_.name.toString) foreach { clazz => exitingTyper { clazz.info println(clazz.defString) diff --git a/test/files/run/t7008-scala-defined/Impls_Macros_2.scala b/test/files/run/t7008-scala-defined/Impls_Macros_2.scala index 330db8da753b..d49cfff1aa11 100644 --- a/test/files/run/t7008-scala-defined/Impls_Macros_2.scala +++ b/test/files/run/t7008-scala-defined/Impls_Macros_2.scala @@ -5,6 +5,8 @@ object Macros { def impl(c: Context) = { import c.universe._ val decls = c.typeOf[ScalaClassWithCheckedExceptions_1[_]].decls.toList + decls.foreach(_.info) + decls.foreach(_.annotations.foreach(_.tpe)) val s = decls.sortBy(_.name.toString).map(decl => (s"${decl.name}: ${decl.annotations}")).mkString(scala.compat.Platform.EOL) reify(println(c.Expr[String](Literal(Constant(s))).splice)) } diff --git a/test/files/run/t7008/Impls_Macros_2.scala b/test/files/run/t7008/Impls_Macros_2.scala index 3c6fe116ce2e..e55cbbfdbf8d 100644 --- a/test/files/run/t7008/Impls_Macros_2.scala +++ b/test/files/run/t7008/Impls_Macros_2.scala @@ -5,6 +5,8 @@ object Macros { def impl(c: Context) = { import c.universe._ val decls = c.typeOf[JavaClassWithCheckedExceptions_1[_]].decls.toList + decls.foreach(_.info) + decls.foreach(_.annotations.foreach(_.tpe)) val s = decls.sortBy(_.name.toString).map(decl => (s"${decl.name}: ${decl.annotations}")).mkString(scala.compat.Platform.EOL) reify(println(c.Expr[String](Literal(Constant(s))).splice)) } diff --git a/test/files/run/t7096.scala b/test/files/run/t7096.scala index f723d70abef8..44485e5da1e8 100644 --- a/test/files/run/t7096.scala +++ b/test/files/run/t7096.scala @@ -41,7 +41,7 @@ abstract class CompilerTest extends DirectTest { } class SymsInPackage(pkgName: String) { - def pkg = rootMirror.getPackage(TermName(pkgName)) + def pkg = rootMirror.getPackage(pkgName) def classes = allMembers(pkg) filter (_.isClass) def modules = allMembers(pkg) filter (_.isModule) def symbols = classes ++ terms filterNot (_ eq NoSymbol) diff --git a/test/files/run/t7455/Test.scala b/test/files/run/t7455/Test.scala index 2cda9225f4fa..afe3f09fb57e 100644 --- a/test/files/run/t7455/Test.scala +++ b/test/files/run/t7455/Test.scala @@ -23,8 +23,8 @@ object Test extends DirectTest { clazz = compiler.rootMirror.staticClass(name) constr <- clazz.info.member(termNames.CONSTRUCTOR).alternatives } { - println(constr.defString) fullyInitializeSymbol(constr) + println(constr.defString) } } } diff --git a/test/junit/scala/tools/nsc/PipelineMainTest.scala b/test/junit/scala/tools/nsc/PipelineMainTest.scala index 8d4218029c6d..e779cfc774e7 100644 --- a/test/junit/scala/tools/nsc/PipelineMainTest.scala +++ b/test/junit/scala/tools/nsc/PipelineMainTest.scala @@ -263,8 +263,8 @@ class PipelineMainTest { class CleanVisitor() extends SimpleFileVisitor[Path] { override def preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult = { if (dir.getFileName.toString == "target") { - deleteRecursive(dir) - Files.createDirectories(dir) + for (p <- Files.list(dir).iterator.asScala) + deleteRecursive(p) FileVisitResult.SKIP_SUBTREE } else super.preVisitDirectory(dir, attrs) }