diff options
Diffstat (limited to 'src')
18 files changed, 205 insertions, 73 deletions
diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index a3a95ffd37..1288eb0b7c 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -22,13 +22,74 @@ if "%~1"=="-toolcp" ( goto another_param ) -set _LINE_PARAMS=%1 +rem We keep in _JAVA_PARAMS all -J-prefixed and -D-prefixed arguments +set _JAVA_PARAMS= + +if [%1]==[] goto param_afterloop +set _TEST_PARAM=%~1 +if not "%_TEST_PARAM:~0,1%"=="-" goto param_afterloop + +rem ignore -e "scala code" +if "%_TEST_PARAM:~0,2%"=="-e" ( + shift + shift + if [%1]==[] goto param_afterloop +) + +set _TEST_PARAM=%~1 +if "%_TEST_PARAM:~0,2%"=="-J" ( + set _JAVA_PARAMS=%_TEST_PARAM:~2% +) + +if "%_TEST_PARAM:~0,2%"=="-D" ( + rem test if this was double-quoted property "-Dprop=42" + for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO ( + if not "%%G" == "%_TEST_PARAM%" ( + rem double quoted: "-Dprop=42" -> -Dprop="42" + set _JAVA_PARAMS=%%G="%%H" + ) else if [%2] neq [] ( + rem it was a normal property: -Dprop=42 or -Drop="42" + set _JAVA_PARAMS=%_TEST_PARAM%=%2 + shift + ) + ) +) + :param_loop shift + if [%1]==[] goto param_afterloop -set _LINE_PARAMS=%_LINE_PARAMS% %1 +set _TEST_PARAM=%~1 +if not "%_TEST_PARAM:~0,1%"=="-" goto param_afterloop + +rem ignore -e "scala code" +if "%_TEST_PARAM:~0,2%"=="-e" ( + shift + shift + if [%1]==[] goto param_afterloop +) + +set _TEST_PARAM=%~1 +if "%_TEST_PARAM:~0,2%"=="-J" ( + set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM:~2% +) + +if "%_TEST_PARAM:~0,2%"=="-D" ( + rem test if this was double-quoted property "-Dprop=42" + for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO ( + if not "%%G" == "%_TEST_PARAM%" ( + rem double quoted: "-Dprop=42" -> -Dprop="42" + set _JAVA_PARAMS=%_JAVA_PARAMS% %%G="%%H" + ) else if [%2] neq [] ( + rem it was a normal property: -Dprop=42 or -Drop="42" + set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM%=%2 + shift + ) + ) +) goto param_loop :param_afterloop + if "%OS%" NEQ "Windows_NT" ( echo "Warning, your version of Windows is not supported. Attempting to start scala anyway." ) @@ -51,6 +112,9 @@ rem We use the value of the JAVA_OPTS environment variable if defined set _JAVA_OPTS=%JAVA_OPTS% if not defined _JAVA_OPTS set _JAVA_OPTS=@javaflags@ +rem We append _JAVA_PARAMS java arguments to JAVA_OPTS if necessary +if defined _JAVA_PARAMS set _JAVA_OPTS=%_JAVA_OPTS% %_JAVA_PARAMS% + set _TOOL_CLASSPATH=@classpath@ if "%_TOOL_CLASSPATH%"=="" ( for %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f" diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 14e3f5b642..2b96961291 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -874,9 +874,14 @@ abstract class ClassfileParser { case ENUM_TAG => val t = pool.getType(index) val n = readName() - val s = t.typeSymbol.companionModule.info.decls.lookup(n) - assert(s != NoSymbol, t) - Some(LiteralAnnotArg(Constant(s))) + val module = t.typeSymbol.companionModule + val s = module.info.decls.lookup(n) + if (s != NoSymbol) Some(LiteralAnnotArg(Constant(s))) + else { + warning(s"""While parsing annotations in ${in.file}, could not find $n in enum $module.\nThis is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (SI-7014).""") + None + } + case ARRAY_TAG => val arr = new ArrayBuffer[ClassfileAnnotArg]() var hasError = false diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala index 3c7dc79636..114bcba5df 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala @@ -202,15 +202,16 @@ trait Solving extends Logic { withLit(findModelFor(dropUnit(f, unitLit)), unitLit) case _ => // partition symbols according to whether they appear in positive and/or negative literals - val pos = new mutable.HashSet[Sym]() - val neg = new mutable.HashSet[Sym]() + // SI-7020 Linked- for deterministic counter examples. + val pos = new mutable.LinkedHashSet[Sym]() + val neg = new mutable.LinkedHashSet[Sym]() f.foreach{_.foreach{ lit => if (lit.pos) pos += lit.sym else neg += lit.sym }} // appearing in both positive and negative - val impures = pos intersect neg + val impures: mutable.LinkedHashSet[Sym] = pos intersect neg // appearing only in either positive/negative positions - val pures = (pos ++ neg) -- impures + val pures: mutable.LinkedHashSet[Sym] = (pos ++ neg) -- impures if (pures nonEmpty) { val pureSym = pures.head diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 95d6ca52ec..454f913412 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1418,14 +1418,6 @@ trait Namers extends MethodSynthesis { annCtx.setReportErrors() // need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892. AnnotationInfo lazily { - if (typer.context ne ctx) - log(sm"""|The var `typer.context` in ${Namer.this} was mutated before the annotation ${ann} was forced. - | - |current value = ${typer.context} - |original value = $ctx - | - |This confirms the hypothesis for the cause of SI-7603. If you see this message, please comment on that ticket.""") - enteringTyper(newTyper(annCtx) typedAnnotation ann) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 8e9933f734..dea4c46e79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -162,7 +162,7 @@ trait NamesDefaults { self: Analyzer => // never used for constructor calls, they always have a stable qualifier def blockWithQualifier(qual: Tree, selected: Name) = { - val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos, newFlags = ARTIFACT) setInfo qual.tpe + val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos, newFlags = ARTIFACT) setInfo uncheckedBounds(qual.tpe) blockTyper.context.scope enter sym val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType) // it stays in Vegas: SI-5720, SI-5727 @@ -289,9 +289,10 @@ trait NamesDefaults { self: Analyzer => arg.tpe } ).widen // have to widen or types inferred from literal defaults will be singletons - val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos, newFlags = ARTIFACT) setInfo ( - if (byName) functionType(Nil, argTpe) else argTpe - ) + val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos, newFlags = ARTIFACT) setInfo { + val tp = if (byName) functionType(Nil, argTpe) else argTpe + uncheckedBounds(tp) + } Some((context.scope.enter(s), byName, repeated)) }) map2(symPs, args) { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 5929cab1d1..32e908e03b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1414,17 +1414,35 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans false } - private def checkTypeRef(tp: Type, tree: Tree) = tp match { + private def checkTypeRef(tp: Type, tree: Tree, skipBounds: Boolean) = tp match { case TypeRef(pre, sym, args) => checkDeprecated(sym, tree.pos) if(sym.isJavaDefined) sym.typeParams foreach (_.cookJavaRawInfo()) - if (!tp.isHigherKinded) + if (!tp.isHigherKinded && !skipBounds) checkBounds(tree, pre, sym.owner, sym.typeParams, args) case _ => } - private def checkAnnotations(tpes: List[Type], tree: Tree) = tpes foreach (tp => checkTypeRef(tp, tree)) + private def checkTypeRefBounds(tp: Type, tree: Tree) = { + var skipBounds = false + tp match { + case AnnotatedType(ann :: Nil, underlying, selfSym) if ann.symbol == UncheckedBoundsClass => + skipBounds = true + underlying + case TypeRef(pre, sym, args) => + if (!tp.isHigherKinded && !skipBounds) + checkBounds(tree, pre, sym.owner, sym.typeParams, args) + tp + case _ => + tp + } + } + + private def checkAnnotations(tpes: List[Type], tree: Tree) = tpes foreach { tp => + checkTypeRef(tp, tree, skipBounds = false) + checkTypeRefBounds(tp, tree) + } private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f private def applyRefchecksToAnnotations(tree: Tree): Unit = { @@ -1453,8 +1471,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } doTypeTraversal(tree) { - case AnnotatedType(annots, _, _) => applyChecks(annots) - case _ => + case tp @ AnnotatedType(annots, _, _) => + applyChecks(annots) + case tp => } case _ => } @@ -1639,13 +1658,27 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } val existentialParams = new ListBuffer[Symbol] - doTypeTraversal(tree) { // check all bounds, except those that are existential type parameters - case ExistentialType(tparams, tpe) => + var skipBounds = false + // check all bounds, except those that are existential type parameters + // or those within typed annotated with @uncheckedBounds + doTypeTraversal(tree) { + case tp @ ExistentialType(tparams, tpe) => existentialParams ++= tparams - case t: TypeRef => - checkTypeRef(deriveTypeWithWildcards(existentialParams.toList)(t), tree) + case ann: AnnotatedType if ann.hasAnnotation(UncheckedBoundsClass) => + // SI-7694 Allow code synthetizers to disable checking of bounds for TypeTrees based on inferred LUBs + // which might not conform to the constraints. + skipBounds = true + case tp: TypeRef => + val tpWithWildcards = deriveTypeWithWildcards(existentialParams.toList)(tp) + checkTypeRef(tpWithWildcards, tree, skipBounds) case _ => } + if (skipBounds) { + tree.tpe = tree.tpe.map { + _.filterAnnotations(_.symbol != UncheckedBoundsClass) + } + } + tree case TypeApply(fn, args) => @@ -1715,6 +1748,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans inPattern = false super.transform(result) } + case ValDef(_, _, _, _) if treeInfo.hasSynthCaseSymbol(result) => + deriveValDef(result)(transform) // SI-7716 Don't refcheck the tpt of the synthetic val that holds the selector. case _ => super.transform(result) } diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 0c5f798c23..1af176736b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -350,11 +350,14 @@ trait TypeDiagnostics { val strings = mutable.Map[String, Set[TypeDiag]]() withDefaultValue Set() val names = mutable.Map[Name, Set[TypeDiag]]() withDefaultValue Set() - def record(t: Type, sym: Symbol) = { - val diag = TypeDiag(t, sym) + val localsSet = locals.toSet - strings("" + t) += diag - names(sym.name) += diag + def record(t: Type, sym: Symbol) = { + if (!localsSet(sym)) { + val diag = TypeDiag(t, sym) + strings("" + t) += diag + names(sym.name) += diag + } } for (tpe <- types ; t <- tpe) { t match { diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 7f9b81e1ec..906a575d90 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -16,6 +16,7 @@ import File.pathSeparator import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator import java.net.MalformedURLException import java.util.regex.PatternSyntaxException +import scala.reflect.runtime.ReflectionUtils /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as @@ -80,7 +81,7 @@ object ClassPath { } /** A useful name filter. */ - def isTraitImplementation(name: String) = name endsWith "$class.class" + def isTraitImplementation(name: String) = ReflectionUtils.isTraitImplementation(name) def specToURL(spec: String): Option[URL] = try Some(new URL(spec)) @@ -139,7 +140,7 @@ object ClassPath { } object DefaultJavaContext extends JavaContext { - override def isValidName(name: String) = !isTraitImplementation(name) + override def isValidName(name: String) = !ReflectionUtils.scalacShouldntLoadClassfile(name) } private def endsClass(s: String) = s.length > 6 && s.substring(s.length - 6) == ".class" diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 8d2f200e99..57ebe1b30d 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -12,6 +12,7 @@ import java.lang.{Class => jClass} import scala.compat.Platform.EOL import scala.reflect.NameTransformer import scala.reflect.api.JavaUniverse +import scala.reflect.io.NoAbstractFile abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => @@ -136,7 +137,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _) def wrapper (tree: => Tree) = wrapper1(wrapper2(tree)) - phase = (new Run).typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled + val run = new Run + run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works + phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions reporter.reset() diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index a7ce044780..e0a6757d34 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -335,13 +335,8 @@ object ClassfileConstants { abstract class FlagTranslation { import Flags._ - private var isAnnotation = false - private var isClass = false - private def initFields(flags: Int) = { - isAnnotation = (flags & JAVA_ACC_ANNOTATION) != 0 - isClass = false - } - private def translateFlag(jflag: Int): Long = (jflag: @switch) match { + private def isAnnotation(flags: Int): Boolean = (flags & JAVA_ACC_ANNOTATION) != 0 + private def translateFlag(jflag: Int, isAnnotation: Boolean, isClass: Boolean): Long = (jflag: @switch) match { case JAVA_ACC_PRIVATE => PRIVATE case JAVA_ACC_PROTECTED => PROTECTED case JAVA_ACC_FINAL => FINAL @@ -351,31 +346,28 @@ object ClassfileConstants { case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT case _ => 0L } - private def translateFlags(jflags: Int, baseFlags: Long): Long = { + private def translateFlags(jflags: Int, baseFlags: Long, isAnnotation: Boolean, isClass: Boolean): Long = { + def translateFlag0(jflags: Int): Long = translateFlag(jflags, isAnnotation, isClass) var res: Long = JAVA | baseFlags /* fast, elegant, maintainable, pick any two... */ - res |= translateFlag(jflags & JAVA_ACC_PRIVATE) - res |= translateFlag(jflags & JAVA_ACC_PROTECTED) - res |= translateFlag(jflags & JAVA_ACC_FINAL) - res |= translateFlag(jflags & JAVA_ACC_SYNTHETIC) - res |= translateFlag(jflags & JAVA_ACC_STATIC) - res |= translateFlag(jflags & JAVA_ACC_ABSTRACT) - res |= translateFlag(jflags & JAVA_ACC_INTERFACE) + res |= translateFlag0(jflags & JAVA_ACC_PRIVATE) + res |= translateFlag0(jflags & JAVA_ACC_PROTECTED) + res |= translateFlag0(jflags & JAVA_ACC_FINAL) + res |= translateFlag0(jflags & JAVA_ACC_SYNTHETIC) + res |= translateFlag0(jflags & JAVA_ACC_STATIC) + res |= translateFlag0(jflags & JAVA_ACC_ABSTRACT) + res |= translateFlag0(jflags & JAVA_ACC_INTERFACE) res } def classFlags(jflags: Int): Long = { - initFields(jflags) - isClass = true - translateFlags(jflags, 0) + translateFlags(jflags, 0, isAnnotation(jflags), isClass = true) } def fieldFlags(jflags: Int): Long = { - initFields(jflags) - translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0) + translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0 , isAnnotation(jflags), isClass = false) } def methodFlags(jflags: Int): Long = { - initFields(jflags) - translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE | ARTIFACT else 0) + translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE | ARTIFACT else 0, isAnnotation(jflags), isClass = false) } } object FlagTranslation extends FlagTranslation { } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 92f2a64ce9..90a1ab39d5 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1004,6 +1004,7 @@ trait Definitions extends api.StandardDefinitions { lazy val ThrowsClass = requiredClass[scala.throws[_]] lazy val TransientAttr = requiredClass[scala.transient] lazy val UncheckedClass = requiredClass[scala.unchecked] + lazy val UncheckedBoundsClass = getClassIfDefined("scala.reflect.internal.annotations.uncheckedBounds") lazy val UnspecializedClass = requiredClass[scala.annotation.unspecialized] lazy val VolatileAttr = requiredClass[scala.volatile] diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index b0828e9c54..9ddf156128 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -411,6 +411,11 @@ trait Importers extends api.Importers { to: SymbolTable => if (my != null) { addFixup(recreatedTreeCompleter(their, my)) tryFixup() + // we have to be careful with position import as some shared trees + // like EmptyTree, emptyValDef don't support position assignment + if (their.pos != NoPosition) { + my.setPos(importPosition(their.pos)) + } } my } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 1603029340..206dff44e2 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -574,6 +574,8 @@ trait Printers extends api.Printers { self: SymbolTable => case refTree: RefTree => if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]") else print(tree.symbol) + case defTree: DefTree => + print(tree.symbol) case _ => print(tree.symbol.name) } diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 49b5dae0ea..876dadee1f 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4539,6 +4539,12 @@ trait Types else (ps :+ SerializableTpe).toList ) + /** Adds the @uncheckedBound annotation if the given `tp` has type arguments */ + final def uncheckedBounds(tp: Type): Type = { + if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp // second condition for backwards compatibilty with older scala-reflect.jar + else tp.withAnnotation(AnnotationInfo marker UncheckedBoundsClass.tpe) + } + /** Members of the given class, other than those inherited * from Any or AnyRef. */ diff --git a/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala new file mode 100644 index 0000000000..a44bb54734 --- /dev/null +++ b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala @@ -0,0 +1,13 @@ +package scala.reflect +package internal +package annotations + +/** + * An annotation that designates the annotated type should not be checked for violations of + * type parameter bounds in the `refchecks` phase of the compiler. This can be used by synthesized + * code the uses an inferred type of an expression as the type of an artifict val/def (for example, + * a temporary value introduced by an ANF transform). See [[https://issues.scala-lang.org/browse/SI-7694]]. + * + * @since 2.10.3 + */ +final class uncheckedBounds extends scala.annotation.StaticAnnotation diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 93861b0899..dd77b084c5 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -18,7 +18,7 @@ import internal.pickling.ByteCodecs import internal.pickling.UnPickler import scala.collection.mutable.{ HashMap, ListBuffer } import internal.Flags._ -import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance} +import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance, scalacShouldntLoadClass} import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} @@ -696,8 +696,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val parents = try { parentsLevel += 1 val jsuperclazz = jclazz.getGenericSuperclass - val superclazz = if (jsuperclazz == null) AnyTpe else typeToScala(jsuperclazz) - superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala) + val ifaces = jclazz.getGenericInterfaces.toList map typeToScala + val isAnnotation = JavaAccFlags(jclazz).isAnnotation + if (isAnnotation) AnnotationClass.tpe :: ClassfileAnnotationClass.tpe :: ifaces + else (if (jsuperclazz == null) AnyTpe else typeToScala(jsuperclazz)) :: ifaces } finally { parentsLevel -= 1 } @@ -709,14 +711,21 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def enter(sym: Symbol, mods: JavaAccFlags) = ( if (mods.isStatic) module.moduleClass else clazz ).info.decls enter sym - for (jinner <- jclazz.getDeclaredClasses) + def enterEmptyCtorIfNecessary(): Unit = { + if (jclazz.getConstructors.isEmpty) + clazz.info.decls.enter(clazz.newClassConstructor(NoPosition)) + } + + for (jinner <- jclazz.getDeclaredClasses) { jclassAsScala(jinner) // inner class is entered as a side-effect // no need to call enter explicitly + } pendingLoadActions ::= { () => jclazz.getDeclaredFields foreach (f => enter(jfieldAsScala(f), f.javaFlags)) jclazz.getDeclaredMethods foreach (m => enter(jmethodAsScala(m), m.javaFlags)) jclazz.getConstructors foreach (c => enter(jconstrAsScala(c), c.javaFlags)) + enterEmptyCtorIfNecessary() } if (parentsLevel == 0) { @@ -949,7 +958,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val cls = if (jclazz.isMemberClass && !nme.isImplClassName(jname)) lookupClass - else if (jclazz.isLocalClass0 || isInvalidClassName(jname)) + else if (jclazz.isLocalClass0 || scalacShouldntLoadClass(jname)) // local classes and implementation classes not preserved by unpickling - treat as Java // // upd. but only if they cannot be loaded as top-level classes diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index 2db9706007..710ec02acd 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -78,4 +78,10 @@ private[scala] object ReflectionUtils { accessor setAccessible true accessor invoke outer } + + def isTraitImplementation(fileName: String) = fileName endsWith "$class.class" + + def scalacShouldntLoadClassfile(fileName: String) = isTraitImplementation(fileName) + + def scalacShouldntLoadClass(name: scala.reflect.internal.SymbolTable#Name) = scalacShouldntLoadClassfile(name + ".class") } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 815cc0c885..3e01a6df02 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -5,6 +5,7 @@ package runtime import internal.Flags import java.lang.{Class => jClass, Package => jPackage} import scala.collection.mutable +import scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass private[reflect] trait SymbolLoaders { self: SymbolTable => @@ -90,14 +91,6 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => } } - /** Is the given name valid for a top-level class? We exclude names with embedded $-signs, because - * these are nested classes or anonymous classes, - */ - def isInvalidClassName(name: Name) = { - val dp = name pos '$' - 0 < dp && dp < (name.length - 1) - } - class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand with SynchronizedScope { assert(pkgClass.isType) @@ -107,7 +100,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => val e = super.lookupEntry(name) if (e != null) e - else if (isInvalidClassName(name) || (negatives contains name)) + else if (scalacShouldntLoadClass(name) || (negatives contains name)) null else { val path = |