diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-10-28 20:49:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-28 20:49:19 +0200 |
commit | 066637781d42d8c512abaf7496e679e0e9f250e6 (patch) | |
tree | 3bd645a6fffbd7f8edb92598c45b4aab6fd3a896 | |
parent | 4a487ca5d0da7925fcd23772e25cc10d8167a351 (diff) | |
parent | 795d59a8f600e45ee9b05b483a4d80d2d8ce6de5 (diff) | |
download | scala-066637781d42d8c512abaf7496e679e0e9f250e6.tar.gz scala-066637781d42d8c512abaf7496e679e0e9f250e6.tar.bz2 scala-066637781d42d8c512abaf7496e679e0e9f250e6.zip |
Merge pull request #5482 from lrytz/sd248-frontend
Frontend fixes for scala-dev#248
23 files changed, 233 insertions, 190 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index b36d5d4ef1..d948d151a6 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -52,20 +52,28 @@ abstract class SymbolLoaders { }) } + def newClass(owner: Symbol, name: String): ClassSymbol = owner.newClass(newTypeName(name)) + /** Enter class with given `name` into scope of `root` * and give them `completer` as type. */ - def enterClass(owner: Symbol, name: String, completer: SymbolLoader): Symbol = { - val clazz = owner.newClass(newTypeName(name)) + def enterClass(owner: Symbol, name: String, completer: SymbolLoader): Symbol = + enterClass(owner, newClass(owner, name), completer) + + def enterClass(owner: Symbol, clazz: ClassSymbol, completer: SymbolLoader): Symbol = { clazz setInfo completer enterIfNew(owner, clazz, completer) } + def newModule(owner: Symbol, name: String): ModuleSymbol = owner.newModule(newTermName(name)) + /** Enter module with given `name` into scope of `root` * and give them `completer` as type. */ - def enterModule(owner: Symbol, name: String, completer: SymbolLoader): Symbol = { - val module = owner.newModule(newTermName(name)) + def enterModule(owner: Symbol, name: String, completer: SymbolLoader): Symbol = + enterModule(owner, newModule(owner, name), completer) + + def enterModule(owner: Symbol, module: ModuleSymbol, completer: SymbolLoader): Symbol = { module setInfo completer module.moduleClass setInfo moduleClassLoader enterIfNew(owner, module, completer) @@ -113,9 +121,12 @@ abstract class SymbolLoaders { /** Enter class and module with given `name` into scope of `root` * and give them `completer` as type. */ - def enterClassAndModule(root: Symbol, name: String, completer: SymbolLoader) { - val clazz = enterClass(root, name, completer) - val module = enterModule(root, name, completer) + def enterClassAndModule(root: Symbol, name: String, getCompleter: (ClassSymbol, ModuleSymbol) => SymbolLoader) { + val clazz = newClass(root, name) + val module = newModule(root, name) + val completer = getCompleter(clazz, module) + enterClass(root, clazz, completer) + enterModule(root, module, completer) if (!clazz.isAnonymousClass) { // Diagnostic for SI-7147 def msg: String = { @@ -136,7 +147,7 @@ abstract class SymbolLoaders { * (overridden in interactive.Global). */ def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) { - enterClassAndModule(root, name, new SourcefileLoader(src)) + enterClassAndModule(root, name, (_, _) => new SourcefileLoader(src)) } /** The package objects of scala and scala.reflect should always @@ -162,17 +173,10 @@ abstract class SymbolLoaders { if (settings.verbose) inform("[symloader] no class, picked up source file for " + src.path) enterToplevelsFromSource(owner, classRep.name, src) case (Some(bin), _) => - enterClassAndModule(owner, classRep.name, newClassLoader(bin)) + enterClassAndModule(owner, classRep.name, new ClassfileLoader(bin, _, _)) } } - /** Create a new loader from a binary classfile. - * This is intended as a hook allowing to support loading symbols from - * files other than .class files. - */ - protected def newClassLoader(bin: AbstractFile): SymbolLoader = - new ClassfileLoader(bin) - /** * A lazy type that completes itself by calling parameter doComplete. * Any linked modules/classes or module classes are also initialized. @@ -277,7 +281,7 @@ abstract class SymbolLoaders { } } - class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader with FlagAssigningCompleter { + 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 { @@ -304,13 +308,7 @@ abstract class SymbolLoaders { protected def doComplete(root: Symbol) { val start = if (Statistics.canEnable) Statistics.startTimer(classReadNanos) else null - - // Running the classfile parser after refchecks can lead to "illegal class file dependency" - // errors. More concretely, the classfile parser calls "sym.companionModule", which calls - // "isModuleNotMethod" on the companion. After refchecks, this method forces the info, which - // may run the classfile parser. This produces the error. - enteringPhase(phaseBeforeRefchecks)(classfileParser.parse(classfile, root)) - + classfileParser.parse(classfile, clazz, module) if (root.associatedFile eq NoAbstractFile) { root match { // In fact, the ModuleSymbol forwards its setter to the module class diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index f8c1a0d082..7e81fad606 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -10,6 +10,7 @@ package classfile import java.io.{File, IOException} import java.lang.Integer.toHexString + import scala.collection.{immutable, mutable} import scala.collection.mutable.{ArrayBuffer, ListBuffer} import scala.annotation.switch @@ -18,6 +19,7 @@ import scala.reflect.internal.pickling.{ByteCodecs, PickleBuffer} import scala.reflect.io.NoAbstractFile import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io.AbstractFile +import scala.util.control.NonFatal /** This abstract class implements a class file parser. * @@ -53,18 +55,18 @@ abstract class ClassfileParser { 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 clazz: Symbol = _ // the class symbol containing dynamic members - protected var staticModule: Symbol = _ // 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 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 file: AbstractFile = _ // the class file + protected var in: AbstractFileReader = _ // 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 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 classTParams = Map[Name,Symbol]() protected var srcfile0 : Option[AbstractFile] = None protected def moduleClass: Symbol = staticModule.moduleClass @@ -132,17 +134,21 @@ abstract class ClassfileParser { finally loaders.parentsLevel -= 1 } - def parse(file: AbstractFile, root: Symbol): Unit = { - debuglog("[class] >> " + root.fullName) - + /** + * `clazz` and `module` are the class and module symbols corresponding to the classfile being + * parsed. Note that the ClassfileLoader unconditionally creates both of these symbols, they may + * may get invalidated later on (.exists). + * + * Note that using `companionModule` / `companionClass` does not always work to navigate between + * those two symbols, namely when they are shadowed by a type / value in the a package object + * (scala-dev#248). + */ + def parse(file: AbstractFile, clazz: ClassSymbol, module: ModuleSymbol): Unit = { this.file = file - pushBusy(root) { + pushBusy(clazz) { this.in = new AbstractFileReader(file) - this.clazz = if (root.isModule) root.companionClass else root - // WARNING! do no use clazz.companionModule to find staticModule. - // In a situation where root can be defined, but its companionClass not, - // this would give incorrect results (see SI-5031 in separate compilation scenario) - this.staticModule = if (root.isModule) root else root.companionModule + this.clazz = clazz + this.staticModule = module this.isScala = false parseHeader() @@ -271,7 +277,7 @@ abstract class ClassfileParser { * arrays are considered to be class types, they might * appear as entries in 'newarray' or 'cast' opcodes. */ - def getClassOrArrayType(index: Int): Type = ( + def getClassOrArrayType(index: Int): Type = { if (index <= 0 || len <= index) errorBadIndex(index) else values(index) match { case tp: Type => tp @@ -283,7 +289,7 @@ abstract class ClassfileParser { case _ => recordAtIndex(classNameToSymbol(name), index).tpe_* } } - ) + } def getType(index: Int): Type = getType(null, index) def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index)) @@ -356,63 +362,43 @@ abstract class ClassfileParser { abort(s"bad constant pool tag ${in.buf(start)} at byte $start") } - private def loadClassSymbol(name: Name): Symbol = { - val file = classPath findClassFile name.toString getOrElse { - // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented - // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects - // that are not in their correct place (see bug for details) - - // TODO More consistency with use of stub symbols in `Unpickler` - // - better owner than `NoSymbol` - // - remove eager warning - val msg = s"Class $name not found - continuing with a stub." - if ((!settings.isScaladoc) && (settings.verbose || settings.developer)) warning(msg) - return NoSymbol.newStubSymbol(name.toTypeName, msg) - } - val completer = new loaders.ClassfileLoader(file) - var owner: Symbol = rootMirror.RootClass - var sym: Symbol = NoSymbol - var ss: Name = null - var start = 0 - var end = name indexOf '.' - - while (end > 0) { - ss = name.subName(start, end) - sym = owner.info.decls lookup ss - if (sym == NoSymbol) { - sym = owner.newPackage(ss.toTermName) setInfo completer - sym.moduleClass setInfo completer - owner.info.decls enter sym - } - owner = sym.moduleClass - start = end + 1 - end = name.indexOf('.', start) - } - ss = name.subName(0, start) - owner.info.decls lookup ss orElse { - sym = owner.newClass(ss.toTypeName) setInfoAndEnter completer - debuglog("loaded "+sym+" from file "+file) - sym - } + def stubClassSymbol(name: Name): Symbol = { + // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented + // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects + // that are not in their correct place (see bug for details) + + // TODO More consistency with use of stub symbols in `Unpickler` + // - better owner than `NoSymbol` + // - remove eager warning + val msg = s"Class $name not found - continuing with a stub." + if ((!settings.isScaladoc) && (settings.verbose || settings.developer)) warning(msg) + NoSymbol.newStubSymbol(name.toTypeName, msg) } - /** FIXME - we shouldn't be doing ad hoc lookups in the empty package. - * The method called "getClassByName" should either return the class or not. - */ - private def lookupClass(name: Name) = ( + private def lookupClass(name: Name) = try { if (name containsChar '.') - rootMirror getClassByName name // see tickets #2464, #3756 + 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) - ) + } catch { + // The handler + // - prevents crashes with deficient InnerClassAttributes (SI-2464, 0ce0ad5) + // - was referenced in the bugfix commit for SI-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 => + // getClassByName can throw a MissingRequirementError (which extends FatalError) + // definitions.getMember can throw a FatalError, for example in pos/t5165b + stubClassSymbol(name) + } /** Return the class symbol of the given name. */ def classNameToSymbol(name: Name): Symbol = { if (innerClasses contains name) innerClasses innerSymbol name else - try lookupClass(name) - catch { case _: FatalError => loadClassSymbol(name) } + lookupClass(name) } def parseClass() { @@ -441,13 +427,10 @@ abstract class ClassfileParser { } val isTopLevel = !(currentClass containsChar '$') // Java class name; *don't* try to to use Scala name decoding (SI-7532) - - val c = if (isTopLevel) pool.getClassSymbol(nameIdx) else clazz if (isTopLevel) { - if (c != clazz) { - if ((clazz eq NoSymbol) && (c ne NoSymbol)) clazz = c - else mismatchError(c) - } + val c = pool.getClassSymbol(nameIdx) + // scala-dev#248: when a type alias (in a package object) shadows a class symbol, getClassSymbol returns a stub + if (!c.isInstanceOf[StubSymbol] && c != clazz) mismatchError(c) } addEnclosingTParams(clazz) @@ -848,16 +831,19 @@ abstract class ClassfileParser { // Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME case tpnme.RuntimeAnnotationATTR => if (isScalaAnnot || !isScala) { - val scalaSigAnnot = parseAnnotations(attrLen) - 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") - } + // 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 SI-7014, + // SI-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 @@ -891,6 +877,24 @@ abstract class ClassfileParser { } } + 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 @@ -924,7 +928,7 @@ abstract class ClassfileParser { if (hasError) None else Some(ArrayAnnotArg(arr.toArray)) case ANNOTATION_TAG => - parseAnnotation(index) map (NestedAnnotArg(_)) + parseAnnotation(index, onlyScalaSig = false) map (NestedAnnotArg(_)) } } @@ -951,7 +955,7 @@ abstract class ClassfileParser { /* Parse and return a single annotation. If it is malformed, * return None. */ - def parseAnnotation(attrNameIndex: Int): Option[AnnotationInfo] = try { + def parseAnnotation(attrNameIndex: Int, onlyScalaSig: Boolean): Option[AnnotationInfo] = try { val attrType = pool.getType(attrNameIndex) val nargs = u2 val nvpairs = new ListBuffer[(Name, ClassfileAnnotArg)] @@ -972,18 +976,17 @@ abstract class ClassfileParser { case None => hasError = true } else - parseAnnotArg match { + 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 ex: java.lang.Error => throw ex - case ex: Throwable => + } 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 @@ -992,7 +995,6 @@ abstract class ClassfileParser { // 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 } @@ -1014,19 +1016,18 @@ abstract class ClassfileParser { /* 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(len: Int): Option[AnnotationInfo] = { + def parseAnnotations(onlyScalaSig: Boolean): Option[AnnotationInfo] = { val nAttr = u2 var scalaSigAnnot: Option[AnnotationInfo] = None - for (n <- 0 until nAttr) - parseAnnotation(u2) 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 => - } + 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 } @@ -1043,7 +1044,6 @@ abstract class ClassfileParser { def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile) { def jflags = entry.jflags - val completer = new loaders.ClassfileLoader(file) val name = entry.originalName val sflags = jflags.toScalaFlags val owner = ownerForFlags(jflags) @@ -1054,8 +1054,11 @@ abstract class ClassfileParser { val (innerClass, innerModule) = if (file == NoAbstractFile) { (newStub(name.toTypeName), newStub(name.toTermName)) } else { - val cls = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer - val mod = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer + val cls = owner.newClass(name.toTypeName, NoPosition, sflags) + val mod = owner.newModule(name.toTermName, NoPosition, sflags) + val completer = new loaders.ClassfileLoader(file, cls, mod) + cls setInfo completer + mod setInfo completer mod.moduleClass setInfo loaders.moduleClassLoader List(cls, mod.moduleClass) foreach (_.associatedFile = file) (cls, mod) @@ -1098,8 +1101,6 @@ abstract class ClassfileParser { val attrName = readTypeName() val attrLen = u4 attrName match { - case tpnme.SignatureATTR => - in.skip(attrLen) case tpnme.ScalaSignatureATTR => isScala = true val pbuf = new PickleBuffer(in.buf, in.bp, in.bp + attrLen) @@ -1166,10 +1167,10 @@ abstract class ClassfileParser { private def innerSymbol(entry: InnerClassEntry): Symbol = { val name = entry.originalName.toTypeName val enclosing = entry.enclosing - val member = ( + val member = { if (enclosing == clazz) entry.scope lookup name else lookupMemberAtTyperPhaseIfPossible(enclosing, name) - ) + } def newStub = enclosing.newStubSymbol(name, s"Unable to locate class corresponding to inner class entry for $name in owner ${entry.outerName}") member.orElse(newStub) } diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 3d1c160d52..6b1063ccd9 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -91,7 +91,6 @@ trait Mirrors extends api.Mirrors { private def ensureClassSymbol(fullname: String, sym: Symbol): ClassSymbol = { var result = sym - while (result.isAliasType) result = result.info.typeSymbol result match { case x: ClassSymbol => x case _ => MissingRequirementError.notFound("class " + fullname) @@ -212,27 +211,6 @@ trait Mirrors extends api.Mirrors { try body catch { case _: MissingRequirementError => NoSymbol } - /** getModule2/getClass2 aren't needed at present but may be again, - * so for now they're mothballed. - */ - // def getModule2(name1: Name, name2: Name) = { - // try getModuleOrClass(name1.toTermName) - // catch { case ex1: FatalError => - // try getModuleOrClass(name2.toTermName) - // catch { case ex2: FatalError => throw ex1 } - // } - // } - // def getClass2(name1: Name, name2: Name) = { - // try { - // val result = getModuleOrClass(name1.toTypeName) - // if (result.isAliasType) getClass(name2) else result - // } - // catch { case ex1: FatalError => - // try getModuleOrClass(name2.toTypeName) - // catch { case ex2: FatalError => throw ex1 } - // } - // } - def init() { if (initialized) return // Still fiddling with whether it's cleaner to do some of this setup here diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f870ecfc15..8d77e334db 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -302,9 +302,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newClassConstructor(pos: Position): MethodSymbol = newConstructor(pos) setInfo MethodType(Nil, this.tpe) - def newLinkedModule(clazz: Symbol, newFlags: Long = 0L): ModuleSymbol = { - val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, MODULE | newFlags) - connectModuleToClass(m, clazz.asInstanceOf[ClassSymbol]) + def newLinkedModule(moduleClass: Symbol, newFlags: Long = 0L): ModuleSymbol = { + val m = newModuleSymbol(moduleClass.name.toTermName, moduleClass.pos, MODULE | newFlags) + connectModuleToClass(m, moduleClass.asInstanceOf[ClassSymbol]) } final def newModule(name: TermName, pos: Position = NoPosition, newFlags0: Long = 0L): ModuleSymbol = { val newFlags = newFlags0 | MODULE @@ -1063,7 +1063,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => // parent LowPriorityImplicits. See comment in c5441dc for more elaboration. // Since the fix for SI-7335 Predef parents must be defined in Predef.scala, and we should not // get here anymore. - devWarning(s"calling Symbol#exists with sourcefile based symbol loader may give incorrect results."); + devWarning(s"calling Symbol#exists with sourcefile based symbol loader may give incorrect results.") } rawInfo load this @@ -2223,7 +2223,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * to the class. As presently implemented this potentially returns class for * any symbol except NoSymbol. */ - def companionClass: Symbol = flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this) + def companionClass: Symbol = flatOwnerInfo.decl(name.toTypeName).suchThat(d => d.isClass && d.isCoDefinedWith(this)) /** For a class: the module or case class factory with the same name in the same package. * For all others: NoSymbol @@ -2860,8 +2860,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def associatedFile_=(f: AbstractFile) { moduleClass.associatedFile = f } override def moduleClass = referenced - override def companionClass = - flatOwnerInfo.decl(name.toTypeName).suchThat(sym => sym.isClass && (sym isCoDefinedWith this)) override def owner = { if (Statistics.hotEnabled) Statistics.incCounter(ownerCount) diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index c6cb0d0223..6dea184826 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -17,6 +17,7 @@ import PickleFormat._ import scala.collection.mutable import scala.collection.mutable.ListBuffer import scala.annotation.switch +import scala.util.control.NonFatal /** @author Martin Odersky * @version 1.0 @@ -29,25 +30,22 @@ abstract class UnPickler { * from an array of bytes. * @param bytes bytearray from which we unpickle * @param offset offset from which unpickling starts - * @param classRoot the top-level class which is unpickled, or NoSymbol if inapplicable - * @param moduleRoot the top-level module which is unpickled, or NoSymbol if inapplicable + * @param classRoot the top-level class which is unpickled + * @param moduleRoot the top-level module which is unpickled * @param filename filename associated with bytearray, only used for error messages */ - def unpickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) { + def unpickle(bytes: Array[Byte], offset: Int, classRoot: ClassSymbol, moduleRoot: ModuleSymbol, filename: String) { try { + assert(classRoot != NoSymbol && moduleRoot != NoSymbol, s"The Unpickler expects a class and module symbol: $classRoot - $moduleRoot") new Scan(bytes, offset, classRoot, moduleRoot, filename).run() } catch { - case ex: IOException => - throw ex - case ex: MissingRequirementError => - throw ex - case ex: Throwable => + case NonFatal(ex) => /*if (settings.debug.value)*/ ex.printStackTrace() throw new RuntimeException("error reading Scala signature of "+filename+": "+ex.getMessage()) } } - class Scan(_bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(_bytes, offset, -1) { + class Scan(_bytes: Array[Byte], offset: Int, classRoot: ClassSymbol, moduleRoot: ModuleSymbol, filename: String) extends PickleBuffer(_bytes, offset, -1) { //println("unpickle " + classRoot + " and " + moduleRoot)//debug protected def debug = settings.debug.value @@ -293,10 +291,11 @@ abstract class UnPickler { case Right(sym) => sym -> readNat() } - def isModuleFlag = (flags & MODULE) != 0L - def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) - def isModuleRoot = (name == moduleRoot.name) && (owner == moduleRoot.owner) - def pflags = flags & PickledFlags + def isModuleFlag = (flags & MODULE) != 0L + def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) + def isModuleRoot = (name == moduleRoot.name) && (owner == moduleRoot.owner) + def isModuleClassRoot = (name == moduleRoot.name.toTypeName) && (owner == moduleRoot.owner) + def pflags = flags & PickledFlags def finishSym(sym: Symbol): Symbol = { /** @@ -341,22 +340,22 @@ abstract class UnPickler { finishSym(tag match { case TYPEsym | ALIASsym => owner.newNonClassSymbol(name.toTypeName, NoPosition, pflags) + case CLASSsym => - val sym = ( - if (isClassRoot) { - if (isModuleFlag) moduleRoot.moduleClass setFlag pflags - else classRoot setFlag pflags - } + val sym = { + if (isModuleFlag && isModuleClassRoot) moduleRoot.moduleClass setFlag pflags + else if (!isModuleFlag && isClassRoot) classRoot setFlag pflags else owner.newClassSymbol(name.toTypeName, NoPosition, pflags) - ) + } if (!atEnd) sym.typeOfThis = newLazyTypeRef(readNat()) - sym + case MODULEsym => - val clazz = at(inforef, () => readType()).typeSymbol // after NMT_TRANSITION, we can leave off the () => ... () + val moduleClass = at(inforef, () => readType()).typeSymbol // after NMT_TRANSITION, we can leave off the () => ... () if (isModuleRoot) moduleRoot setFlag pflags - else owner.newLinkedModule(clazz, pflags) + else owner.newLinkedModule(moduleClass, pflags) + case VALsym => if (isModuleRoot) { abort(s"VALsym at module root: owner = $owner, name = $name") } else owner.newTermSymbol(name.toTermName, NoPosition, pflags) diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 9b0d66f41c..95440ebc00 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -578,7 +578,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive * @param jclazz The Java class which contains the unpickled information in a * ScalaSignature or ScalaLongSignature annotation. */ - def unpickleClass(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = { + def unpickleClass(clazz: ClassSymbol, module: ModuleSymbol, jclazz: jClass[_]): Unit = { def markAbsent(tpe: Type) = setAllInfos(clazz, module, tpe) def handleError(ex: Exception) = { markAbsent(ErrorType) diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 768a3d5ce5..3f2864ee7b 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -14,7 +14,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => * by unpickling information from the corresponding Java class. If no Java class * is found, a package is created instead. */ - class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter { + class TopClassCompleter(clazz: ClassSymbol, module: ModuleSymbol) extends SymLoader with FlagAssigningCompleter { markFlagsCompleted(clazz, module)(mask = ~TopLevelPickledFlags) override def complete(sym: Symbol) = { debugInfo("completing "+sym+"/"+clazz.fullName) @@ -36,7 +36,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => * @param name The simple name of the newly created class * @param completer The completer to be used to set the info of the class and the module */ - protected def initAndEnterClassAndModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = { + protected def initAndEnterClassAndModule(owner: Symbol, name: TypeName, completer: (ClassSymbol, ModuleSymbol) => LazyType) = { assert(!(name.toString endsWith "[]"), name) val clazz = owner.newClass(name) val module = owner.newModule(name.toTermName) diff --git a/test/files/neg/t7014.check b/test/files/neg/t7014.check new file mode 100644 index 0000000000..07ad51e9d3 --- /dev/null +++ b/test/files/neg/t7014.check @@ -0,0 +1,5 @@ +warning: While parsing annotations in t7014-neg.obj/t7014/ThreadSafetyLevel.class, could not find COMPLETELY_THREADSAFE in enum object ThreadSafetyLevel. +This is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (SI-7014). +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t7014.flags b/test/files/neg/t7014.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t7014.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/pos/t7014/ThreadSafety.java b/test/files/neg/t7014/ThreadSafety.java index ed508804e3..ed508804e3 100644 --- a/test/files/pos/t7014/ThreadSafety.java +++ b/test/files/neg/t7014/ThreadSafety.java diff --git a/test/files/pos/t7014/ThreadSafetyLevel.java b/test/files/neg/t7014/ThreadSafetyLevel.java index 4df1dc787a..4df1dc787a 100644 --- a/test/files/pos/t7014/ThreadSafetyLevel.java +++ b/test/files/neg/t7014/ThreadSafetyLevel.java diff --git a/test/files/pos/t7014/t7014.scala b/test/files/neg/t7014/t7014.scala index 7c73f700be..7c73f700be 100644 --- a/test/files/pos/t7014/t7014.scala +++ b/test/files/neg/t7014/t7014.scala diff --git a/test/files/pos/sd248/Prop_1.scala b/test/files/pos/sd248/Prop_1.scala new file mode 100644 index 0000000000..d5decda547 --- /dev/null +++ b/test/files/pos/sd248/Prop_1.scala @@ -0,0 +1,2 @@ +package p +object Prop { class Whitelist } diff --git a/test/files/pos/sd248/Test_2.scala b/test/files/pos/sd248/Test_2.scala new file mode 100644 index 0000000000..602e6d37b5 --- /dev/null +++ b/test/files/pos/sd248/Test_2.scala @@ -0,0 +1,5 @@ +package p + +object PropTest { + def t = new Prop.Whitelist +} diff --git a/test/files/pos/sd248/package_1.scala b/test/files/pos/sd248/package_1.scala new file mode 100644 index 0000000000..a90354e66f --- /dev/null +++ b/test/files/pos/sd248/package_1.scala @@ -0,0 +1,3 @@ +package object p { + type Prop = String +} diff --git a/test/files/pos/t5165b.flags b/test/files/pos/t5165b.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t5165b.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t7551.flags b/test/files/pos/t7551.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t7551.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t7551/A.java b/test/files/pos/t7551/A.java new file mode 100644 index 0000000000..72aeb40fa0 --- /dev/null +++ b/test/files/pos/t7551/A.java @@ -0,0 +1,9 @@ +package p; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface A { + Class<?> subInterface(); +} diff --git a/test/files/pos/t7551/T.scala b/test/files/pos/t7551/T.scala new file mode 100644 index 0000000000..017926e0e2 --- /dev/null +++ b/test/files/pos/t7551/T.scala @@ -0,0 +1,9 @@ +package p + +@A(subInterface = classOf[T.S]) +trait T { +} + +object T { + private[p] trait S extends T { } +} diff --git a/test/files/pos/t7551/Test.scala b/test/files/pos/t7551/Test.scala new file mode 100644 index 0000000000..c1f529c4b1 --- /dev/null +++ b/test/files/pos/t7551/Test.scala @@ -0,0 +1,5 @@ +package p + +object Foo { + def bar(t: T) { } +} diff --git a/test/files/run/t7139.check b/test/files/run/t7139.check new file mode 100644 index 0000000000..9a29a6cef9 --- /dev/null +++ b/test/files/run/t7139.check @@ -0,0 +1,11 @@ + +scala> import test._ +import test._ + +scala> A(0) +res0: test.A = 0 + +scala> A(0) +res1: test.A = 0 + +scala> :quit diff --git a/test/files/run/t7139/A_1.scala b/test/files/run/t7139/A_1.scala new file mode 100644 index 0000000000..eb0eb300da --- /dev/null +++ b/test/files/run/t7139/A_1.scala @@ -0,0 +1,8 @@ +package test { + object A { + def apply(n: A) = n + } +} +package object test { + type A = Int +} diff --git a/test/files/run/t7139/Test_2.scala b/test/files/run/t7139/Test_2.scala new file mode 100644 index 0000000000..32feaa0284 --- /dev/null +++ b/test/files/run/t7139/Test_2.scala @@ -0,0 +1,9 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = + """import test._ + |A(0) + |A(0) + """.stripMargin +} |